File Coverage

blib/lib/Perl/Dist/APPerl.pm
Criterion Covered Total %
statement 70 660 10.6
branch 5 330 1.5
condition 3 91 3.3
subroutine 20 52 38.4
pod 0 8 0.0
total 98 1141 8.5


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