release-5
[kakapo:kakapo.git] / setup.nqp
1 #! /usr/bin/env parrot-nqp
2 # Copyright 2009-2010, Austin Hastings. See accompanying LICENSE file, or 
3 # http://www.opensource.org/licenses/artistic-license-2.0.php for license.
4
5 # =head1 NAME
6 #
7 # setup.nqp - Configure and build the Kakapo library.
8 #
9 # =head1 USAGE
10 #
11 #     $ parrot-nqp setup.nqp build
12 #     $ parrot-nqp setup.nqp test
13 #     $ sudo parrot-nqp setup.nqp install
14
15 INIT {
16         pir::load_language('parrot');
17         pir::load_bytecode('distutils.pbc');
18         
19         pir::load_bytecode('dumper.pir');
20 }
21
22 MAIN(get_args());
23
24 sub new_hash(*%hash) {
25         %hash;
26 }
27
28 sub MAIN(@argv) {
29         
30         my %kakapo := new_hash(
31                 :name(  'Kakapo' ),
32                 :abstract(      'Run-time library for NQP programs on the Parrot VM' ),
33                 :authority(     'http://gitorious.org/austin' ),
34                 :copyright_holder( 'Austin Hastings' ),
35                 :doc_files(     <README CREDITS> ),
36                 :keywords(      < library  nqp  parrot  runtime  stand alone  xunit 
37                                 unit  testing  matcher  pmc  methods  >),
38                 :license_type(  'Artistic License 2.0' ),
39                 :license_uri(   'http://www.perlfoundation.org/artistic_license_2_0' ),
40                 :checkout_uri(  'git://gitorious.org/kakapo/kakapo.git' ),
41                 :browser_uri(   'http://code.google.com/p/kakapo-parrot/' ),
42                 :project_uri(   'git://gitorious.org/kakapo/kakapo.git' ),
43
44                 :harness_files( 't/bootstrap t/Syntax.nqp t/DependencyQueue.nqp t/Global.nqp t/Parrot/Parrot.nqp t/Program.nqp' ),
45                 
46                 :release_id(            'release-5' ),
47                 :release_dir_format(    'released/%s'),
48                 :vdd_file(              'vdd.txt' ),
49         );
50
51         %kakapo<copy_templates><library/krt0.pir>                               := <src/Internals/krt0.pir_tmpl>;
52         %kakapo<copy_templates><src/Internals/kakapo_bottom.pir>        := <src/Internals/kakapo_bottom.pir_tmpl>;
53         %kakapo<copy_templates><src/Internals/kakapo_top.pir>           := <src/Internals/kakapo_top.pir_tmpl>;
54         
55
56         %kakapo<pir_nqp-rx><src/Internals/Base.pir>                             := <src/Internals/Base.nqp>;
57         %kakapo<pir_nqp-rx><src/Internals/Full.pir>                             := <src/Internals/Full.nqp>;
58
59         my @base_pir_files := <
60                 src/Global.pir
61                 src/Syntax.pir
62                 
63                 src/Parrot/Opcode.pir
64                 src/Parrot/Parrot.pir
65                 src/Parrot/Pir.pir
66                 
67                 src/Pmc/Array.pir
68                 src/Pmc/common_methods.pir
69                 src/Pmc/Exception.pir
70                         src/Exceptions.pir
71                 src/Pmc/Key.pir
72                 src/Pmc/Hash.pir
73                 src/Pmc/Namespace.pir
74                 src/Pmc/String.pir
75                 src/Pmc/Sub.pir
76                 src/Pmc/Undef.pir
77         >;
78         
79         for @base_pir_files {
80                 %kakapo<pir_nqp-rx>{~ $_} := change_ext(~$_, :from('.pir'), :to('.nqp'));
81         }
82         
83         %kakapo<build_libs><library/kakapo_base.pir> := <
84                 src/Internals/kakapo_top.pir
85                 src/Internals/Base.pir
86         >;
87         %kakapo<build_libs><library/kakapo_base.pir>.append( @base_pir_files );
88         %kakapo<build_libs><library/kakapo_base.pir>.push( <src/Internals/kakapo_bottom.pir>);
89         
90         my @full_pir_files := <
91                 src/Classes/P6object.pir
92                 src/Classes/P6metaclass.pir
93
94                 src/DependencyQueue.pir
95                 src/Program.pir
96
97                 src/UnitTest/Listeners.pir
98                 src/UnitTest/Loader.pir
99                 src/UnitTest/Result.pir
100                 src/UnitTest/Suite.pir
101                 src/UnitTest/Testcase.pir
102         >;
103         
104         for @full_pir_files {
105                 %kakapo<pir_nqp-rx>{~ $_} := change_ext(~$_, :from('.pir'), :to('.nqp'));
106         }
107
108         %kakapo<build_libs><library/kakapo_full.pir> := <
109                 src/Internals/kakapo_top.pir
110                 src/Internals/Full.pir
111         >;
112         %kakapo<build_libs><library/kakapo_full.pir>.append( @base_pir_files );
113         %kakapo<build_libs><library/kakapo_full.pir>.append( @full_pir_files );
114         %kakapo<build_libs><library/kakapo_full.pir>.push( <src/Internals/kakapo_bottom.pir>);
115
116         %kakapo<strip_annotations> := %kakapo<build_libs>;
117         
118         %kakapo<pbc_pir><library/kakapo_base.pbc>       := <library/kakapo_base.pir>;
119         %kakapo<pbc_pir><library/kakapo_full.pbc>       := <library/kakapo_full.pir>;
120         %kakapo<pbc_pir><library/krt0.pbc>              := <library/krt0.pir>;
121
122         %kakapo<release_files><kakapo_base.pir> := <library/kakapo_base.pir>;
123         %kakapo<release_files><kakapo_base.pbc> := <library/kakapo_base.pbc>;
124         %kakapo<release_files><kakapo_full.pir> := <library/kakapo_full.pir>;
125         %kakapo<release_files><kakapo_full.pbc> := <library/kakapo_full.pbc>;
126         %kakapo<release_files><krt0.pir>                := <library/krt0.pir>;
127         %kakapo<release_files><krt0.pbc>                := <library/krt0.pbc>;
128         
129         register_step_before('build', Setup::Step::copy_templates);
130         register_step_before('clean', Setup::Step::clean_templates);
131         
132         #install_build_libs();
133         install_substep('build', Setup::Step::build_libs, :before('_build_pbc_pir'));
134         install_substep('build', Setup::Step::strip_annotations, :before('_build_pbc_pir'));
135         register_step_before('clean', Setup::Step::clean_libs);
136         
137         register_step('release', Setup::Step::make_release);
138         
139         pir::shift(@argv);
140         setup_(@argv, %kakapo);
141 }
142
143 sub change_ext($file, :$from!, :$to!) {
144         my $len := pir::length__IS($file) - pir::length__IS($from);
145         
146         unless pir::substr__SSI($file, $len) eq $from {
147                 pir::die("No matching extension '$from' on file: $file");
148         }
149         
150         my $base := pir::substr__SSI($file, 0, $len);
151         $base ~ $to;    
152 }
153
154 sub get_args() {
155         my $interp := pir::getinterp__P();
156         $interp[2];
157 }
158
159 sub install_substep($step, &func, :$before, :$after) {
160         my $target := $before // $after;
161         my @insert;
162         @insert.push(&func);
163         
164         our %step;
165         my $index := ?$after;
166         for %step{$step} {
167                 if ~ $_ eq $target {
168                         pir::splice__vppii(%step{$step}, @insert, $index, 0);
169                         return 0;
170                 }
171                 
172                 $index++;
173         }
174         
175         pir::die("Unable to insert substep &func into $step - could not find $target");
176 }
177
178
179 # distutils functions are not in a namespace, so Step:: methods can't address them 
180 # directly.
181
182 sub needs_update($src, $dst, :$verbose) {
183         
184         ! file_exists($dst) ||newer(~$src, $dst, :verbose($verbose));
185 }
186
187 sub setup_(@steps, %config) {
188         Q:PIR {
189                 $P0 = find_lex '@steps'
190                 $P1 = find_lex '%config'
191                 'setup'($P0 :flat, $P1 :flat :named)
192         };
193 }
194
195 module Setup::Step;
196
197 sub build_libs(*%config) {
198         my $output_file;
199         my @inputs;
200         my $needs_update;
201         my $command;
202         
203         for %config<build_libs> {
204                 $output_file := ~ $_;
205                 @inputs := %config<build_libs>{$output_file};
206                 $needs_update := 0;
207                 
208                 unless newer(~$output_file, @inputs) {
209                         $command := 'cat ' 
210                                 ~ pir::join(' ', @inputs)
211                                 ~ ' > '
212                                 ~ $output_file;
213                         system($command, :verbose(1));
214                 }
215         }
216 }
217
218 sub clean_libs(*%config) {
219         clean_key(%config<build_libs>);
220 }
221
222 sub clean_templates(*%config) {
223         clean_key(%config<copy_templates>);
224 }
225         
226 sub copy_templates(*%config) {
227         my %cfg := %config<copy_templates>;
228         for %cfg {
229                 my $src := %cfg{$_};
230                 my $dst := ~ $_;
231                 
232                 unless newer(~$dst, ~$src) {
233                         cp($src, $dst, :verbose(1));
234                 }
235         }
236 }
237
238 sub make_release(*%config) {
239         my $release_id := %config<release_id>;
240         unless $release_id {
241                 pir::die("Cannot release: <release_id> config not set");
242         }
243         
244         my @args;
245         @args.push( $release_id );
246         
247         my $release_dir := pir::sprintf__SSP(%config<release_dir_format>, @args);
248
249         if file_exists($release_dir) {
250                 pir::die("Cannot release: '$release_dir' already exists.");
251         }
252         
253         my $vdd := %config<vdd_file>;
254         
255         unless $vdd && file_exists($vdd) {
256                 pir::die("Cannot release: no Version Description Document provided. Set <vdd_file> config.");
257         }
258         
259         my $fh := pir::open__PSS($vdd, 'r');
260         my $leader := $fh.readline;
261         $fh.close;
262         
263         if pir::index__ISS($leader, $release_id) < 0 {
264                 pir::die("Cannot release: VDD file '$vdd' does not contain '$release_id' in line 1");
265         }
266         
267         my %cfg := %config<release_files>; 
268         my $installed_vdd := 0;
269         
270         for %cfg {
271                 install(%cfg{~$_}, $release_dir ~ '/' ~$_, :verbose(1));
272                 
273                 if %cfg{~$_} eq $vdd {
274                         $installed_vdd++;
275                 }
276         }
277
278         unless $installed_vdd {
279                 install($vdd, $release_dir ~ '/VERSION', :verbose(1));
280         }
281         
282         unlink($vdd, :verbose(1));
283 }
284
285 sub strip_annotations(*%config) {
286         for %config<strip_annotations> {
287                 if file_exists(~$_) {
288                         my $fh := pir::open__PSS(~$_, 'r');
289                         my $body := $fh.readall();
290                         $fh.close;
291
292                         if pir::index__ISS($body, "\n.annotate ") >= 0 {
293                                 say("Removing  annotations from $_");
294                                 $body.replace("\n.annotate ", "\n# .annotate ");
295                                 $fh := pir::open__PSS(~$_, 'w');
296                                 $fh.puts($body);
297                                 $fh.close;
298                         }                               
299                 }
300         }
301 }