File Coverage

blib/lib/Perl/Dist/APPerl.pm
Criterion Covered Total %
statement 54 459 11.7
branch 1 240 0.4
condition 2 72 2.7
subroutine 18 44 40.9
pod 0 8 0.0
total 75 823 9.1


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   1245 use version 0.77; our $VERSION = qv(v0.2.0);
  1         2054  
  1         8  
4 1     1   99 use strict;
  1         2  
  1         20  
5 1     1   4 use warnings;
  1         2  
  1         30  
6 1     1   759 use JSON::PP 2.0104 qw(decode_json);
  1         17546  
  1         83  
7 1     1   9 use File::Path 2.07 qw(make_path remove_tree);
  1         21  
  1         92  
8 1     1   7 use Cwd qw(abs_path getcwd);
  1         2  
  1         57  
9 1     1   627 use Data::Dumper qw(Dumper);
  1         6512  
  1         74  
10 1     1   9 use File::Basename qw(basename dirname);
  1         2  
  1         121  
11 1     1   563 use File::Copy qw(copy move cp);
  1         2421  
  1         67  
12 1     1   1074 use Env qw(@PATH);
  1         4456  
  1         7  
13 1     1   719 use FindBin qw();
  1         1060  
  1         28  
14 1     1   718 use Getopt::Long qw(GetOptionsFromArray);
  1         12479  
  1         3  
15             Getopt::Long::Configure qw(gnu_getopt);
16              
17             use constant {
18 1         85 START_WD => getcwd(),
19             PROJECT_FILE => 'apperl-project.json',
20 1     1   209 };
  1         2  
21             use constant {
22 1         165 PROJECT_TMP_DIR => (START_WD.'/.apperl'),
23 1     1   10 };
  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       93 : 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   7 };
  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   6 };
  1         2  
35             use constant {
36 1         2500 SITE_CONFIG_FILE => (SITE_CONFIG_DIR."/site.json"),
37 1     1   5 };
  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' },
698             'full-vista' => { desc => 'moving target: full for vista', base => 'v5.36.0-full-v0.1.0-vista' },
699             'small' => { desc => 'moving target: small', base => 'v5.36.0-small-v0.1.0' },
700             'small-vista' => { desc => 'moving target: small for vista', base => 'v5.36.0-small-v0.1.0-vista' },
701             # development configs
702             dontuse_threads => {
703             desc => "not recommended, threaded build is buggy",
704             base => 'v5.36.0-full-v0.1.0',
705             perl_extra_flags => ['-Doptimize=-Os', '-Dusethreads', '-de'],
706             perl_id => 'cosmo-apperl'
707             },
708             perl_cosmo_dev => {
709             desc => "For developing cosmo platform perl without apperl additions",
710             base => 'v5.36.0-full-v0.1.0',
711             perl_id => 'cosmo'
712             },
713             perl_cosmo_dev_on_vista => {
714             desc => "For developing cosmo platform perl without apperl additions on vista",
715             base => "perl_cosmo_dev",
716             cosmo_id => '9c5a7795add7add5a214afce27d896084e0861c5',
717             },
718             perl_apperl_dev => {
719             desc => "For developing apperl",
720             base => 'v5.36.0-full-v0.1.0',
721             perl_id => 'cosmo-apperl'
722             }
723             }
724             );
725 0           $defconfig{defaultconfig} = $defconfig{apperl_configs}{full}{base};
726              
727 0           my $projectconfig = _load_json(PROJECT_FILE);
728 0 0         if($projectconfig) {
729 0           foreach my $projkey (keys %$projectconfig) {
730 0 0         if($projkey ne 'apperl_configs') {
731 0           $defconfig{$projkey} = $projectconfig->{$projkey};
732             }
733             else {
734 0           $defconfig{$projkey} = {%{$defconfig{$projkey}}, %{$projectconfig->{$projkey}}};
  0            
  0            
735             }
736             }
737             }
738 0           return \%defconfig;
739             }
740              
741             sub _build_def_config {
742             return {
743 0   0 0     base => ($_[0] // 'nobuild-v0.1.0'),
744             desc => 'description of this config',
745             dest => 'perl.com'
746             };
747             }
748              
749             sub Init {
750 0     0 0   my ($defaultconfig, $base) = @_;
751             # validate
752 0 0         die "Cannot create project config, it already exists ".PROJECT_FILE if(-e PROJECT_FILE);
753 0           my $Configs = _load_apperl_configs();
754 0 0         if(defined $base) {
755 0 0         $defaultconfig or die "Cannot set base without name for new config";
756 0 0         if(exists $Configs->{apperl_configs}{$defaultconfig}) {
757 0           die "Cannot set base for $defaultconfig, $defaultconfig already exists ";
758             }
759 0 0         exists $Configs->{apperl_configs}{$base} or die "base config $base does not exist";
760             }
761              
762             # create project config
763 0   0       my %jsondata = ( 'defaultconfig' => ($defaultconfig // 'nobuild-v0.1.0'));
764 0 0 0       if($defaultconfig && ! exists $Configs->{apperl_configs}{$defaultconfig}) {
765             $jsondata{apperl_configs} = {
766 0           $defaultconfig => _build_def_config($base),
767             };
768             }
769 0           print "writing new project\n";
770 0           _write_json(PROJECT_FILE, \%jsondata);
771              
772             # checkout default config
773 0           Set($jsondata{defaultconfig});
774             }
775              
776             sub NewConfig {
777 0     0 0   my ($name, $base) = @_;
778 0 0         $name or die "Name required to add new config";
779 0           my $Configs = _load_apperl_configs();
780 0 0         ! exists $Configs->{apperl_configs}{$name} or die "Cannot create already existing config";
781 0 0         if(defined $base) {
782 0 0         exists $Configs->{apperl_configs}{$base} or die "base config $base does not exist";
783             }
784 0 0         my $projectconfig = _load_json(PROJECT_FILE) or die "project file must already exist";
785 0           $projectconfig->{apperl_configs}{$name} = _build_def_config($base);
786 0           print "rewriting project\n";
787 0           _write_json(PROJECT_FILE, $projectconfig);
788             }
789              
790             sub InstallBuildDeps {
791 0     0 0   my ($perlrepo, $cosmorepo) = @_;
792 0           my $SiteConfig = _load_json(SITE_CONFIG_FILE);
793             # if a repo is not set, set one up by default
794 0 0 0       if((!$SiteConfig || !exists $SiteConfig->{perl_repo}) && (!$perlrepo)) {
      0        
795 0           $perlrepo = SITE_REPO_DIR."/perl5";
796 0           _setup_repo($perlrepo, _load_apperl_configs()->{perl_remotes});
797 0           print "apperlm install-build-deps: setup perl repo\n";
798             }
799 0 0 0       if((!$SiteConfig || !exists $SiteConfig->{cosmo_repo}) && (!$cosmorepo)) {
      0        
800 0           $cosmorepo = SITE_REPO_DIR."/cosmopolitan";
801 0           _setup_repo( $cosmorepo, _load_apperl_configs()->{cosmo_remotes});
802 0           print "apperlm install-build-deps: setup cosmo repo\n";
803             }
804              
805             # (re)write site config
806 0   0       $perlrepo //= $SiteConfig->{perl_repo};
807 0   0       $cosmorepo //= $SiteConfig->{cosmo_repo};
808 0           my %siteconfig = (
809             perl_repo => abs_path($perlrepo),
810             cosmo_repo => abs_path($cosmorepo)
811             );
812 0           $SiteConfig = \%siteconfig;
813 0           make_path(SITE_CONFIG_DIR);
814 0           _write_json(SITE_CONFIG_FILE, \%siteconfig);
815 0           print "apperlm install-build-deps: wrote site config to ".SITE_CONFIG_FILE."\n";
816             }
817              
818             sub _remove_arr_items_from_arr {
819 0     0     my ($src, $toremove) = @_;
820 0           foreach my $item (@{$toremove}) {
  0            
821 0           my $index = 0;
822 0           $index++ until $src->[$index] eq $item;
823 0           splice(@$src, $index, 1);
824             }
825             }
826              
827             sub Status {
828 0     0 0   my $Configs = _load_apperl_configs();
829 0           my @configlist = sort(keys %{$Configs->{apperl_configs}});
  0            
830 0           my $UserProjectConfig = _load_user_project_config();
831 0           my $CurAPPerlName;
832 0 0         if($UserProjectConfig) {
833 0 0         if(exists $UserProjectConfig->{current_apperl}) {
834 0           $CurAPPerlName = $UserProjectConfig->{current_apperl};
835 0 0         exists $Configs->{apperl_configs}{$CurAPPerlName} or die("non-existent apperl config $CurAPPerlName in user project config");
836             }
837             }
838 0 0 0       if(!defined $CurAPPerlName && exists $Configs->{'defaultconfig'}) {
839 0           $CurAPPerlName = $Configs->{'defaultconfig'};
840 0 0         exists $Configs->{apperl_configs}{$CurAPPerlName} or die("non-existent default apperl config $CurAPPerlName");
841             }
842              
843 0           my @projectitems;
844 0           my $projectconfig = _load_json(PROJECT_FILE);
845 0 0 0       if($projectconfig && exists $projectconfig->{apperl_configs}) {
846 0           @projectitems = sort (keys %{$projectconfig->{apperl_configs}});
  0            
847             }
848 0           my @stable = grep( /v\d+\.\d+\.\d+(\-vista)?$/, @configlist);
849 0           my @rolling = ('full', 'full-vista', 'small', 'small-vista');
850 0           my @internal = ('dontuse_threads', 'perl_cosmo_dev', 'perl_cosmo_dev_on_vista', 'perl_apperl_dev');
851 0           my @categories = (
852             ['PROJECT', \@projectitems],
853             ['STABLE', \@stable],
854             ['ROLLING', \@rolling],
855             ['UNSTABLE/INTERNAL', \@internal],
856             ['UNKNOWN', \@configlist]
857             );
858 0           foreach my $cat (@categories) {
859 0           foreach my $item (@{$cat->[1]}) {
  0            
860 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        
861             }
862 0           _remove_arr_items_from_arr(\@configlist, \@{$cat->[1]});
  0            
863             }
864             }
865              
866             # unfortunately this needs to be called in several places to try to keep them in sync
867             # as perl's make trips up when trying to build an symlinked extension
868             sub _install_perl_repo_files {
869 0     0     my ($itemconfig, $SiteConfig) = @_;
870 0           foreach my $dest (keys %{$itemconfig->{perl_repo_files}}) {
  0            
871 0           foreach my $file (@{$itemconfig->{perl_repo_files}{$dest}}) {
  0            
872             #_command_or_die('ln', '-sf', START_WD."/$file", "$SiteConfig->{perl_repo}/$dest");
873 0           _copy_recursive(START_WD."/$file", "$SiteConfig->{perl_repo}/$dest");
874             }
875             }
876             }
877              
878             sub Set {
879 0     0 0   my ($cfgname) = @_;
880 0           my $UserProjectConfig = _load_user_project_config();
881 0 0         if($UserProjectConfig) {
882 0           delete $UserProjectConfig->{nobuild_perl_bin};
883             }
884             else {
885 0           $UserProjectConfig = {};
886             }
887 0           my $itemconfig = _load_apperl_config(_load_apperl_configs()->{apperl_configs}, $cfgname);
888 0           print Dumper($itemconfig);
889 0 0         if(! exists $itemconfig->{nobuild_perl_bin}) {
890 0 0         my $SiteConfig = _load_json(SITE_CONFIG_FILE) or die "cannot set without build deps (run apperlm install-build-deps)";
891 0 0         -d $SiteConfig->{cosmo_repo} or die $SiteConfig->{cosmo_repo} .' is not directory';
892 0 0         -d $SiteConfig->{perl_repo} or die $SiteConfig->{perl_repo} .' is not directory';
893 0           print "cd ".$SiteConfig->{cosmo_repo}."\n";
894 0 0         chdir($SiteConfig->{cosmo_repo}) or die "Failed to enter cosmo repo";
895 0           _command_or_die('git', 'checkout', $itemconfig->{cosmo_id});
896              
897 0           print "cd ".$SiteConfig->{perl_repo}."\n";
898 0 0         chdir($SiteConfig->{perl_repo}) or die "Failed to enter perl repo";
899 0           print "make veryclean\n";
900 0           system("make", "veryclean");
901 0           foreach my $todelete ('miniperl.com', 'perl.com', 'miniperl.elf', 'perl.elf') {
902 0           print "rm $todelete\n";
903 1 0 0 1   540 unlink($todelete) || $!{ENOENT} or die "failed to delete $todelete";
  1         1441  
  1         9  
  0            
904             }
905 0           _command_or_die('git', 'checkout', $itemconfig->{perl_id});
906              
907 0           print "cd ".START_WD."\n";
908 0 0         chdir(START_WD) or die "Failed to restore cwd";
909 0           _install_perl_repo_files($itemconfig, $SiteConfig);
910             }
911             else {
912 0           my $validperl;
913 0           foreach my $perlbin (@{$itemconfig->{nobuild_perl_bin}}) {
  0            
914 0           print "perlbin $perlbin\n";
915 0 0         if(-f $perlbin) {
916 0 0 0       if(( $perlbin eq $^X) && (! -d '/zip')) {
917 0           print "skipping $perlbin, it appears to not be APPerl\n";
918 0           next;
919             }
920 0           $validperl = $perlbin;
921 0           last;
922             }
923             }
924 0 0         $validperl or die "no valid perl found to use for nobuild config";
925 0           $validperl = abs_path($validperl);
926 0 0         $validperl or die "no valid perl found to use for nobuild config";
927 0           $UserProjectConfig->{nobuild_perl_bin} = $validperl;
928 0           print "Set UserProjectConfig to nobuild_perl-bin to $validperl\n";
929             }
930 0   0       $UserProjectConfig->{apperl_output} //= PROJECT_TMP_DIR."/o";
931 0           $UserProjectConfig->{current_apperl} = $cfgname;
932 0           _write_user_project_config($UserProjectConfig);
933 0           print "$0: Successfully switched to $cfgname\n";
934             }
935              
936             sub Configure {
937 0     0 0   my $Configs = _load_apperl_configs();
938 0 0         my $UserProjectConfig = _load_valid_user_project_config_with_default($Configs) or die "cannot Configure without valid UserProjectConfig";
939 0           my $CurAPPerlName = $UserProjectConfig->{current_apperl};
940 0 0         ! exists $UserProjectConfig->{nobuild_perl_bin} or die "nobuild perl cannot be configured";
941 0 0         my $SiteConfig = _load_json(SITE_CONFIG_FILE) or die "cannot Configure without build deps (run apperlm install-build-deps)";
942 0 0         -d $SiteConfig->{cosmo_repo} or die $SiteConfig->{cosmo_repo} .' is not directory';
943 0 0         -d $SiteConfig->{perl_repo} or die $SiteConfig->{perl_repo} .' is not directory';
944 0           my $itemconfig = _load_apperl_config($Configs->{apperl_configs}, $CurAPPerlName);
945 0           _install_perl_repo_files($itemconfig, $SiteConfig);
946             # build cosmo
947 0           print "$0: Building cosmo, COSMO_MODE=$itemconfig->{cosmo_mode} COSMO_APE_LOADER=$itemconfig->{cosmo_ape_loader}\n";
948 0           _command_or_die('make', '-C', $SiteConfig->{cosmo_repo}, '-j4', "MODE=$itemconfig->{cosmo_mode}",
949             "o/$itemconfig->{cosmo_mode}/cosmopolitan.a",
950             "o/$itemconfig->{cosmo_mode}/libc/crt/crt.o",
951             "o/$itemconfig->{cosmo_mode}/ape/public/ape.lds",
952             "o/$itemconfig->{cosmo_mode}/ape/$itemconfig->{cosmo_ape_loader}",
953             );
954              
955             # Finally Configure perl
956 0           print "cd ".$SiteConfig->{perl_repo}."\n";
957 0 0         chdir($SiteConfig->{perl_repo}) or die "Failed to enter perl repo";
958 0           $ENV{COSMO_REPO} = $SiteConfig->{cosmo_repo};
959 0           $ENV{COSMO_MODE} = $itemconfig->{cosmo_mode};
960 0           $ENV{COSMO_APE_LOADER} = $itemconfig->{cosmo_ape_loader};
961 0           my @onlyextensions = ();
962 0 0         push @onlyextensions, ("-Donlyextensions= ".join(' ', sort @{$itemconfig->{perl_onlyextensions}}).' ') if(exists $itemconfig->{perl_onlyextensions});
  0            
963 0           _command_or_die('sh', 'Configure', @{$itemconfig->{perl_flags}}, @onlyextensions, @{$itemconfig->{perl_extra_flags}}, @_);
  0            
  0            
964 0           print "$0: Configure successful, time for apperlm build\n";
965             }
966              
967             sub _fix_bases {
968 0     0     my ($in, $PERL_VERSION, $PERL_ARCHNAME) = @_;
969 0           $in =~ s/^__perllib__/lib\/perl5\/$PERL_VERSION/;
970 0           $in =~ s/^__perlarchlib__/lib\/perl5\/$PERL_VERSION\/$PERL_ARCHNAME/;
971 0           return $in;
972             }
973              
974             # system is pretty broken on APPerl when running on Windows
975             # let's search PATH ourselves ...
976             sub _find_zip {
977 0 0 0 0     if(($^O ne 'cosmo') || (! -f '/C/Windows/System32/cmd.exe')) {
978 0           return 'zip';
979             }
980             else {
981 0           foreach my $dir (@PATH) {
982 0           my $zippath = "$dir/zip.exe";
983 0 0         return $zippath if(-f $zippath);
984             }
985             }
986 0           die("Failed to find zip.exe, did you download Info-Zip and add the folder containing zip.exe to \%PATH\%?");
987             }
988              
989             sub Build {
990 0     0 0   my ($zippath) = @_;
991 0           my $Configs = _load_apperl_configs();
992 0 0         my $UserProjectConfig = _load_valid_user_project_config_with_default($Configs) or die "cannot Build without valid UserProjectConfig";
993 0           my $CurAPPerlName = $UserProjectConfig->{current_apperl};
994 0           my $itemconfig = _load_apperl_config($Configs->{apperl_configs}, $CurAPPerlName);
995              
996 0           my $PERL_APE;
997             my @perl_config_cmd;
998             # build cosmo perl if this isn't a nobuild config
999 0 0         if(! exists $UserProjectConfig->{nobuild_perl_bin}){
1000 0 0         my $SiteConfig = _load_json(SITE_CONFIG_FILE) or die "cannot build without build deps (run apperlm install-build-deps)";
1001 0 0         -d $SiteConfig->{cosmo_repo} or die $SiteConfig->{cosmo_repo} .' is not directory';
1002 0 0         -d $SiteConfig->{perl_repo} or die $SiteConfig->{perl_repo} .' is not directory';
1003 0           _install_perl_repo_files($itemconfig, $SiteConfig);
1004 0           print "cd ".$SiteConfig->{perl_repo}."\n";
1005 0 0         chdir($SiteConfig->{perl_repo}) or die "Failed to enter perl repo";
1006 0           _command_or_die('make');
1007 0           $PERL_APE = "$SiteConfig->{perl_repo}/perl.com";
1008 0           @perl_config_cmd = ('./perl', '-Ilib');
1009             }
1010             else {
1011 0           $PERL_APE = $UserProjectConfig->{nobuild_perl_bin};
1012 0           @perl_config_cmd = ($PERL_APE);
1013             }
1014              
1015             # prepare for install and pack
1016 0 0         -f $PERL_APE or die "apperlm build: perl ape not found";
1017 0           my $OUTPUTDIR = "$UserProjectConfig->{apperl_output}/$CurAPPerlName";
1018 0 0         if(-d $OUTPUTDIR) {
1019 0           print "rm -rf $OUTPUTDIR\n";
1020 0           remove_tree($OUTPUTDIR);
1021             }
1022 0           my $TEMPDIR = "$OUTPUTDIR/tmp";
1023 0           print "mkdir -p $TEMPDIR\n";
1024 0           make_path($TEMPDIR);
1025 0           my $PERL_PREFIX = _cmdoutput_or_die(@perl_config_cmd, '-e', 'use Config; print $Config{prefix}');
1026 0           my $PREFIX_NOZIP = $PERL_PREFIX;
1027 0           $PREFIX_NOZIP =~ s/^\/zip\/*//;
1028 0           my $PERL_VERSION = _cmdoutput_or_die(@perl_config_cmd, '-e', 'use Config; print $Config{version}');
1029 0           my $PERL_ARCHNAME = _cmdoutput_or_die(@perl_config_cmd, '-e', 'use Config; print $Config{archname}');
1030 0           my @zipfiles = map { "$PREFIX_NOZIP"._fix_bases($_, $PERL_VERSION, $PERL_ARCHNAME) } @{$itemconfig->{MANIFEST}};
  0            
  0            
1031 0           my $ZIP_ROOT = "$TEMPDIR/zip";
1032              
1033             # install cosmo perl if this isn't a nobuild config
1034 0 0         if(! exists $UserProjectConfig->{nobuild_perl_bin}){
1035 0           _command_or_die('make', "DESTDIR=$TEMPDIR", 'install');
1036 0           my @toremove = ("$TEMPDIR$PERL_PREFIX/bin/perl", "$TEMPDIR$PERL_PREFIX/bin/perl$PERL_VERSION");
1037 0           print 'rm '.join(' ', @toremove)."\n";
1038 0 0         unlink(@toremove) == scalar(@toremove) or die "Failed to unlink some files";
1039             }
1040             else {
1041 0           make_path($ZIP_ROOT);
1042             }
1043              
1044             # pack
1045 0           my $APPNAME = basename($PERL_APE);
1046 0           my $APPPATH = "$TEMPDIR/$APPNAME";
1047 0           print "cp $PERL_APE $APPPATH\n";
1048 0 0         copy($PERL_APE, $APPPATH) or die "copy failed: $!";
1049 0           print "chmod 755 $APPPATH\n";
1050 0 0         chmod(0755, $APPPATH) or die $!;
1051 0 0 0       if((! exists $UserProjectConfig->{nobuild_perl_bin}) || scalar(keys %{$itemconfig->{zip_extra_files}})) {
  0            
1052 0           print "cd $ZIP_ROOT\n";
1053 0 0         chdir($ZIP_ROOT) or die "failed to enter ziproot";
1054 0           foreach my $destkey (keys %{$itemconfig->{zip_extra_files}}) {
  0            
1055 0           my $dest = _fix_bases($destkey, $PERL_VERSION, $PERL_ARCHNAME);
1056 0           foreach my $file (@{$itemconfig->{zip_extra_files}{$destkey}}) {
  0            
1057 0           _copy_recursive($file, $dest);
1058             }
1059             }
1060 0   0       _command_or_die($zippath // _find_zip(), '-r', $APPPATH, @zipfiles);
1061             }
1062 0           print "mv $APPPATH $OUTPUTDIR/perl.com\n";
1063 0 0         move($APPPATH, "$OUTPUTDIR/perl.com") or die "move failed: $!";
1064              
1065             # copy to user specified location
1066 0 0         if(exists $itemconfig->{dest}) {
1067 0           print "cd ".START_WD."\n";
1068 0 0         chdir(START_WD) or die "Failed to restore cwd";
1069 0           my @args = ("$UserProjectConfig->{apperl_output}/$CurAPPerlName/perl.com", $itemconfig->{dest});
1070 0           print 'cp '.join(' ', @args)."\n";
1071 0 0         cp(@args) or die "copy failed: $!";
1072             }
1073             }
1074              
1075             sub apperlm {
1076 0     0 0   my $generic_usage = <<'END_USAGE';
1077             apperlm [...]
1078             List of commands, try apperlm --help for info about a command
1079             list | List available APPerl configurations
1080             init | Create an APPerl project in the current dir
1081             new-config | Add a new APPerl configuration to the project
1082             checkout | Switch to another APPerl configurations
1083             install-build-deps | Install build dependencies for APPerl
1084             configure | `Configure` Perl (only valid with build config)
1085             build | Build APPerl
1086             help | Prints this message
1087              
1088             Actually Portable Perl Manager (apperlm) handles configuring and
1089             building Actually Portable Perl (APPerl). See
1090             `perldoc Perl::Dist::APPerl` for more info.
1091             END_USAGE
1092 0 0         my $command = shift(@_) if(@_);
1093 0 0         $command or die($generic_usage);
1094 0 0         if($command eq 'list') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1095 0           my $usage = <<'END_USAGE';
1096             apperlm list
1097             List available APPerl configs; checks apperl-project.json and built-in
1098             to Perl::Dist::APPerl configs. If a current config is set it is denoted
1099             with a '*'.
1100             END_USAGE
1101 0 0         die($usage) if(@_);
1102 0           Perl::Dist::APPerl::Status();
1103             }
1104             elsif($command eq 'build') {
1105 0           my $usage = <<'END_USAGE';
1106             apperlm build [-z|--zippath ]
1107             -z|--zippath Path to InfoZip zip executable
1108             Build APPerl. If the current config is a from-scratch build, you must
1109             run `apperlm configure` first.
1110             END_USAGE
1111 0           my $zippath;
1112             my $help;
1113 0 0         GetOptionsFromArray(\@_, "zippath|z=s" => \$zippath,
1114             "help|h" => \$help,
1115             ) or die($usage);
1116 0 0         if($help) {
1117 0           print $usage;
1118 0           exit 0;
1119             }
1120 0           Perl::Dist::APPerl::Build($zippath);
1121             }
1122             elsif($command eq 'configure') {
1123 0           Perl::Dist::APPerl::Configure(@_);
1124             }
1125             elsif($command =~ /^(\-)*(halp|help|h)$/i) {
1126 0           print $generic_usage;
1127             }
1128             elsif($command =~ /^(\-)*(version|v)$/i) {
1129 0           my $message = <<"END_USAGE";
1130             apperlm $VERSION
1131             Copyright (C) 2022 Gavin Arthur Hayes
1132             This is free software; you can redistribute it and/or modify it under
1133             the same terms as the Perl 5 programming language system itself.
1134             END_USAGE
1135 0           print $message;
1136             }
1137             elsif($command eq 'checkout') {
1138 0 0         scalar(@_) == 1 or die('bad args');
1139 0           my $cfgname = $_[0];
1140 0           Perl::Dist::APPerl::Set($cfgname);
1141             }
1142             elsif($command eq 'init') {
1143 0           my $usage = <<'END_USAGE';
1144             apperlm init [-h|--help] [-n|--name ] [-b|--base ]
1145             -n|--name name of the default config
1146             -b|--base base class of the config
1147             -h|--help Show this message
1148             Create an APPerl project, create a config if -n specified and it
1149             doesn't already exist, checkout the config.
1150             END_USAGE
1151 0           my $name;
1152             my $base;
1153 0           my $help;
1154 0 0         GetOptionsFromArray(\@_, "name|n=s" => \$name,
1155             "base|b=s" => \$base,
1156             "help|h" => \$help,
1157             ) or die($usage);
1158 0 0         if($help) {
1159 0           print $usage;
1160 0           exit 0;
1161             }
1162 0           Perl::Dist::APPerl::Init($name, $base);
1163             }
1164             elsif($command eq 'install-build-deps') {
1165 0           my $usage = <<'END_USAGE';
1166             apperlm install-build-deps [-h|--help] [-c|--cosmo ] [-p|--perl ]
1167             -c|--cosmo set path to cosmopolitan repo (skips git initialization)
1168             -p|--perl set path to perl repo (skips git initialization)
1169             -h|--help Show this message
1170             Install build dependencies for APPerl, use -c or -p to skip initializing
1171             those repos by providing a path to it.
1172             END_USAGE
1173 0           my $cosmo;
1174             my $perl;
1175 0           my $help;
1176 0 0         GetOptionsFromArray(\@_, "cosmo|c=s" => \$cosmo,
1177             "perl|p=s" => \$perl,
1178             "help|h" => \$help,
1179             ) or die($usage);
1180 0 0         if($help) {
1181 0           print $usage;
1182 0           exit 0;
1183             }
1184 0           Perl::Dist::APPerl::InstallBuildDeps($perl, $cosmo);
1185             }
1186             elsif($command eq 'new-config') {
1187 0           my $usage = <<'END_USAGE';
1188             apperlm new-config [-h|--help] [-n|--name ] [-b|--base ]
1189             -n|--name name of the default config
1190             -b|--base base class of the config
1191             -h|--help Show this message
1192             Create a new APPerl config and add it to the project
1193             END_USAGE
1194 0           my $name;
1195             my $base;
1196 0           my $help;
1197 0 0         GetOptionsFromArray(\@_, "name|n=s" => \$name,
1198             "base|b=s" => \$base,
1199             "help|h" => \$help,
1200             ) or die($usage);
1201 0 0         if($help) {
1202 0           print $usage;
1203 0           exit 0;
1204             }
1205 0           Perl::Dist::APPerl::NewConfig($name, $base);
1206             }
1207             elsif($command eq 'get-config-key') {
1208 0 0         scalar(@_) == 2 or die('bad args');
1209 0           my $itemconfig = _load_apperl_config(_load_apperl_configs()->{apperl_configs}, $_[0]);
1210 0           print $itemconfig->{$_[1]};
1211             }
1212             else {
1213 0           die($generic_usage);
1214             }
1215             }
1216              
1217             sub _command_or_die {
1218 0     0     print join(' ', @_), "\n";
1219 0 0         system(@_) == 0 or die;
1220             }
1221              
1222             sub _cmdoutput_or_die {
1223 0     0     print join(' ', @_), "\n";
1224 0 0         my $kid = open(my $from_kid, '-|', @_) or die "can't fork $!";
1225 0           my $output = do { local $/; <$from_kid> };
  0            
  0            
1226 0           waitpid($kid, 0);
1227 0 0         (($? >> 8) == 0) or die("child failed");
1228 0           return $output;
1229             }
1230              
1231             sub _setup_repo {
1232 0     0     my ($repopath, $remotes) = @_;
1233 0           print "mkdir -p $repopath\n";
1234 0           make_path($repopath);
1235 0           print "cd $repopath\n";
1236 0 0         chdir($repopath) or die "Failed to chdir $repopath";
1237 0           _command_or_die('git', 'init');
1238 0           _command_or_die('git', 'checkout', '-b', 'placeholder_dont_use');
1239 0           foreach my $remote (keys %{$remotes}) {
  0            
1240 0           _command_or_die('git', 'remote', 'add', $remote, $remotes->{$remote});
1241 0           _command_or_die('git', 'fetch', $remote);
1242             }
1243             }
1244              
1245             sub _write_json {
1246 0     0     my ($destpath, $obj) = @_;
1247 0 0         open(my $fh, '>', $destpath) or die("Failed to open $destpath for writing");
1248 0           print $fh JSON::PP->new->pretty->encode($obj);
1249 0           close($fh);
1250             }
1251              
1252             sub _load_json {
1253 0     0     my ($jsonpath) = @_;
1254 0 0         open(my $fh, '<', $jsonpath) or return undef;
1255 0           my $file_content = do { local $/; <$fh> };
  0            
  0            
1256 0           close($fh);
1257 0           return decode_json($file_content);
1258             }
1259              
1260             sub _load_apperl_config {
1261 0     0     my ($apperlconfigs, $cfgname) = @_;
1262 0 0         exists $apperlconfigs->{$cfgname} or die "Unknown config: $cfgname";
1263              
1264             # find the base classes
1265 0           my $item = $apperlconfigs->{$cfgname};
1266 0           my @configlist = ($item);
1267 0           while(exists $item->{base}) {
1268 0           $item = $apperlconfigs->{$item->{base}};
1269 0           push @configlist, $item;
1270             }
1271 0           @configlist = reverse @configlist;
1272              
1273             # build the config from oldest to newest
1274             # keys that start with '+' are appended to the non-plus variant instead of replacing
1275             # keys that start with '-' are removed from the non-plus variant instead of replacing
1276             # Removing a key added the same stage or vice versa is undefined
1277 0           my %itemconfig;
1278 0           foreach my $config (@configlist) {
1279 0           foreach my $key (keys %$config) {
1280 0 0         if($key =~ /^(\+|\-)(.+)/) {
1281 0           my $append = $1 eq '+';
1282 0           my $realkey = $2;
1283 0 0         exists $itemconfig{$realkey} or die("cannot append without existing key");
1284 0           my $rtype = ref($itemconfig{$realkey});
1285 0 0         $rtype or die("not ref");
1286 0 0         if($append) {
1287 0 0         if($rtype eq 'ARRAY') {
    0          
1288 0           $itemconfig{$realkey} = [@{$itemconfig{$realkey}}, @{$config->{$key}}];
  0            
  0            
1289             }
1290             elsif($rtype eq 'HASH') {
1291 0           foreach my $dest (keys %{$config->{$key}}) {
  0            
1292 0           push @{$itemconfig{$realkey}{$dest}}, @{$config->{$key}{$dest}};
  0            
  0            
1293             }
1294             }
1295             else {
1296 0           die($rtype);
1297             }
1298             }
1299             else {
1300 0 0         if($rtype eq 'ARRAY') {
1301 0           _remove_arr_items_from_arr($itemconfig{$realkey}, $config->{$key});
1302             }
1303             else {
1304 0           die($rtype);
1305             }
1306             }
1307             }
1308             else {
1309 0           $itemconfig{$key} = $config->{$key};
1310             }
1311             }
1312             }
1313              
1314             # switch these from relative paths to abs paths
1315 0           foreach my $destdir (keys %{$itemconfig{zip_extra_files}}) {
  0            
1316 0           foreach my $path (@{$itemconfig{zip_extra_files}{$destdir}}) {
  0            
1317 0           $path = abs_path($path);
1318 0 0         $path or die;
1319 0 0         -e $path or die("missing file $path");
1320             }
1321             }
1322              
1323             # add in ourselves for bootstrapping, this even works when running internal Perl::Dist::APPerl from a bootstrapped build
1324 0 0 0       if(exists $itemconfig{'include_Perl-Dist-APPerl'} && $itemconfig{'include_Perl-Dist-APPerl'}) {
1325 0           my $thispath = abs_path(__FILE__);
1326 0 0         defined($thispath) or die(__FILE__.'issues?');
1327 0           push @{$itemconfig{zip_extra_files}{"__perllib__/Perl/Dist"}}, $thispath;
  0            
1328 0           my @additionalfiles = map { "$FindBin::Bin/$_" } ('apperlm');
  0            
1329 0   0       -e $_ or die("$_ $!") foreach @additionalfiles;
1330 0           push @{$itemconfig{zip_extra_files}{bin}}, @additionalfiles;
  0            
1331             }
1332              
1333             # verify apperl config sanity
1334 0 0         if(! exists $itemconfig{nobuild_perl_bin}) {
1335 0   0       $itemconfig{cosmo_ape_loader} //= 'ape-no-modify-self.o';
1336 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};
1337             }
1338              
1339 0           return \%itemconfig;
1340             }
1341              
1342             sub _load_user_project_config {
1343 0     0     return _load_json(PROJECT_TMP_CONFIG_FILE);
1344             }
1345              
1346             sub _load_valid_user_project_config {
1347 0     0     my ($Configs) = @_;
1348 0           my $UserProjectConfig = _load_user_project_config();
1349 0 0         if($UserProjectConfig) {
1350 0 0         if(exists $UserProjectConfig->{current_apperl}) {
1351 0           my $CurAPPerlName = $UserProjectConfig->{current_apperl};
1352 0 0         exists $Configs->{apperl_configs}{$CurAPPerlName} or die("non-existent apperl config $CurAPPerlName in user project config");
1353 0           return $UserProjectConfig;
1354             }
1355             }
1356 0           return undef;
1357             }
1358              
1359             sub _load_valid_user_project_config_with_default {
1360 0     0     my ($Configs) = @_;
1361 0           my $UserProjectConfig = _load_valid_user_project_config($Configs);
1362 0 0 0       return $UserProjectConfig if($UserProjectConfig || !exists $Configs->{defaultconfig});
1363 0           Set($Configs->{defaultconfig});
1364 0           return _load_valid_user_project_config($Configs);
1365             }
1366              
1367             sub _write_user_project_config {
1368 0     0     my ($config) = @_;
1369 0 0         if(! -d PROJECT_TMP_DIR) {
1370 0           make_path(PROJECT_TMP_DIR);
1371             };
1372 0           _write_json(PROJECT_TMP_CONFIG_FILE, $config);
1373             }
1374              
1375             sub _copy_recursive {
1376 0     0     my ($src, $dest) = @_;
1377 0 0         if(! -d $dest) {
1378 0           make_path($dest);
1379             }
1380 0           goto &_copy_recursive_inner;
1381             }
1382              
1383             sub _copy_recursive_inner {
1384 0     0     my ($src, $dest) = @_;
1385 0           print "_copy_recursive $src $dest\n";
1386 0 0         if(-f $src) {
    0          
1387 0 0         copy($src, $dest) or die("Failed to copy $!");
1388             }
1389             elsif(-d $src) {
1390 0           my $dest = "$dest/".basename($src);
1391 0 0         if(! -d $dest) {
1392 0 0         mkdir($dest) or die("Failed to mkdir $!");
1393             }
1394 0 0         opendir(my $dh, $src) or die("Failed to opendir");
1395 0           while(my $file = readdir($dh)) {
1396 0 0 0       next if(($file eq '.') || ($file eq '..'));
1397 0           _copy_recursive("$src/$file", $dest);
1398             }
1399 0           closedir($dh);
1400             }
1401             else {
1402 0           die "Unhandled file type for $src";
1403             }
1404             }
1405              
1406             1;
1407              
1408             __END__