1 # Copyright (C) 2001-2009, Parrot Foundation.
4 package Parrot
::Configure
;
11 Parrot::Configure - Conducts the execution of Configuration Steps
15 use Parrot::Configure;
17 my $conf = Parrot::Configure->new;
18 my $data = $conf->data;
19 my $options = $conf->options;
20 my @steps = $conf->steps;
22 $conf->add_steps(@steps);
24 $conf->debug(@messages);
28 This module provides a means for registering, executing, and
29 coordinating one or more configuration steps. Please see
30 F<docs/configuration.pod> for further details about the configuration
35 =head2 Import Parameters
37 This module accepts no arguments to its C<import> method and exports no
44 use Storable
qw(2.12 nstore retrieve nfreeze thaw);
45 use Parrot
::Configure
::Data
;
46 use base
qw(Parrot::Configure::Compiler);
51 'Parrot::Configure::Task' => {
53 object
=> 'Parrot::Configure::Step',
67 Accepts no arguments and returns a Parrot::Configure object.
76 data
=> Parrot
::Configure
::Data
->new,
77 options
=> Parrot
::Configure
::Data
->new,
79 bless $singleton, 'Parrot::Configure';
95 Provides access to a Parrot::Configure::Data object intended to contain
96 initial and discovered configuration data.
98 Accepts no arguments and returns a Parrot::Configure::Data object.
105 return $conf->{data
};
110 Provides access to a Parrot::Configure::Data object intended to contain CLI
113 Accepts no arguments and returns a Parrot::Configure::Data object.
120 return $conf->{options
};
125 Provides a list of registered steps, where each step is represented by an
126 Parrot::Configure::Task object. Steps are returned in the order in which
127 they were registered.
129 Accepts no arguments and returns a list in list context or an arrayref in
137 return wantarray ? @
{ $conf->{steps
} } : $conf->{steps
};
140 =item * C<get_list_of_steps()>
142 Provides a list of the B<names> of registered steps.
144 C<steps()>, in contrast, provides a list of registered step B<objects>, of
145 which the B<step name> is just a small part. Step names are returned in the
146 order in which their corresponding step objects were registered.
148 Accepts no arguments and returns a list in list context or an arrayref in
151 B<Note:> The list of step names returned by C<get_list_of_steps()> will be the
152 same as that in the second argument returned by
153 C<Parrot::Configure::Options::process_options()> B<provided> that you have not
154 used C<add_step()> or C<add_steps()> to add any configuration steps.
158 sub get_list_of_steps
{
160 die 'list_of_steps not available until steps have been added'
161 unless defined $conf->{list_of_steps
};
162 return wantarray ? @
{ $conf->{list_of_steps
} } : $conf->{list_of_steps
};
165 =item * C<add_step()>
167 Registers a new step and any parameters that should be passed to it. The
168 first parameter passed is the class name of the step being registered. All
169 other parameters are saved and passed to the registered class's C<runstep()>
172 Accepts a list and modifies the data structure within the
173 Parrot::Configure object.
178 my ( $conf, $step ) = @_;
180 push @
{ $conf->{steps
} },
181 Parrot
::Configure
::Task
->new(
188 =item * C<add_steps()>
190 Registers new steps to be run at the end of the execution queue.
192 Accepts a list of new steps and modifies the data structure within the
193 Parrot::Configure object.
198 my ( $conf, @new_steps ) = @_;
200 for ( my $i = 0 ; $i <= $#new_steps ; $i++ ) {
201 $conf->add_step( $new_steps[$i] );
202 push @
{ $conf->{list_of_steps
} }, $new_steps[$i];
203 $conf->{hash_of_steps
}->{ $new_steps[$i] } = $i + 1;
209 =item * C<runsteps()>
211 Sequentially executes steps in the order they were registered. The invoking
212 Parrot::Configure object is passed as the first argument to each step's
213 C<runstep()> method, followed by any parameters that were registered for that
216 Accepts no arguments and modifies the data structure within the
217 Parrot::Configure object.
224 my $n = 0; # step number
225 my ( $silent, $verbose, $verbose_step_str, $fatal, $fatal_step_str, $ask );
226 $silent = $conf->options->get(qw( silent ));
228 ( $verbose, $verbose_step_str, $fatal, $fatal_step_str, $ask ) =
229 $conf->options->get(qw( verbose verbose-step fatal fatal-step ask ));
233 my %steps_to_die_for = ();
234 # If the --fatal option is true, then all config steps are mapped into
235 # %steps_to_die_for and there is no consideration of --fatal-step.
237 %steps_to_die_for = map { ($_,1) } @
{ $conf->{list_of_steps
} };
239 # We make certain that argument to --fatal-step is a comma-delimited
240 # string of configuration steps, each of which is a string delimited by
241 # two colons, the first half of which is one of init|inter|auto|gen
242 elsif ( defined ( $fatal_step_str ) ) {
243 %steps_to_die_for = _handle_fatal_step_option
( $fatal_step_str );
246 # No action needed; this is the default case where no step is fatal
250 if (defined $verbose_step_str) {
251 %verbose_steps = _handle_verbose_step_option
( $verbose_step_str );
253 foreach my $task ( $conf->steps ) {
254 my ($red_flag, $this_step_is_verbose);
255 my $step_name = $task->step;
256 if ( scalar keys %steps_to_die_for ) {
257 if ( $steps_to_die_for{$step_name} ) {
261 if ( scalar keys %verbose_steps ) {
262 $this_step_is_verbose = $verbose_steps{$step_name}
268 my $rv = $conf->_run_this_step(
272 verbose_step
=> $this_step_is_verbose,
278 if ( ! defined $rv ) {
283 $conf->{log}->[$n] = {
292 sub _handle_fatal_step_option
{
293 my $fatal_step_str = shift;
294 my %steps_to_die_for = ();
295 my $named_step_pattern = qr/(?:init|inter|auto|gen)::\w+/;
296 if ( $fatal_step_str =~ m
{^
298 (, $named_step_pattern)*
301 my @fatal_steps = split /,/, $fatal_step_str;
302 for my $s (@fatal_steps) {
303 $steps_to_die_for{$s}++;
307 die q{Argument to fatal-step option must be comma-delimited string of valid configuration steps};
309 return %steps_to_die_for;
312 sub _handle_verbose_step_option
{
313 my $verbose_step_str = shift;
314 my %verbose_steps = ();
315 my $named_step_pattern = qr/(?:init|inter|auto|gen)::\w+/;
316 if ( $verbose_step_str =~ m
{^
318 (, $named_step_pattern)*
321 my @verbose_steps = split /,/, $verbose_step_str;
322 for my $s (@verbose_steps) {
323 $verbose_steps{$s}++;
327 die q{Argument to verbose-step option must be comma-delimited string of valid configuration steps};
329 return %verbose_steps;
332 =item * C<run_single_step()>
334 The invoking Parrot::Configure object is passed as the first argument to
335 each step's C<runstep()> method, followed by any parameters that were
336 registered for that step.
338 Accepts no arguments and modifies the data structure within the
339 Parrot::Configure object.
341 B<Note:> Currently used only in F<tools/dev/reconfigure.pl>; not used in
346 sub run_single_step
{
348 my $taskname = shift;
350 my ( $verbose, $verbose_step, $ask ) =
351 $conf->options->get(qw( verbose verbose-step ask ));
353 my $task = ( $conf->steps() )[0];
354 if ( $task->{'Parrot::Configure::Task::step'} eq $taskname ) {
355 $conf->_run_this_step(
359 verbose_step
=> $verbose_step,
366 die 'Mangled task in run_single_step';
376 my $step_name = $args->{task
}->step;
378 eval "use $step_name;"; ## no critic (BuiltinFunctions::ProhibitStringyEval)
382 my $sto = q{.configure_trace.sto};
384 local $Storable::Eval
= 1;
385 if ( $conf->options->get(q{configure_trace}) and ( -e
$sto ) ) {
386 $conftrace = retrieve
($sto);
389 my $step = $step_name->new();
391 # set per step verbosity
392 if ( $args->{verbose_step
} ) {
393 $conf->options->set( verbose
=> 2 );
396 my $stub = qq{$step_name - };
397 my $message = $stub .
398 (q{ } x
(22 - length($stub))) .
401 my $length_message = length($message);
402 unless ($args->{silent
}) {
403 # The first newline terminates the report on the *previous* step.
404 # (Probably needed to make interactive output work properly.
405 # Otherwise, we'd put it in _finish_printing_result().
408 print "\n" if $args->{verbose_step
};
412 # When successful, a Parrot configuration step now returns 1
413 eval { $ret = $step->runstep($conf); };
415 carp
"\nstep $step_name died during execution: $@\n";
419 # A Parrot configuration step can run successfully, but if it fails to
420 # achieve its objective it is supposed to return an undefined status.
422 # reset verbose value for the next step
423 $conf->options->set( verbose
=> $args->{verbose
} );
424 unless ($args->{silent
}) {
425 _finish_printing_result
(
428 step_name
=> $step_name,
430 description
=> $step->description,
431 length_message
=> $length_message,
435 if ($conf->options->get(q{configure_trace}) ) {
438 conftrace
=> $conftrace,
439 step_name
=> $step_name,
448 _failure_message
( $step, $step_name );
454 sub _failure_message
{
455 my ( $step, $step_name ) = @_;
456 my $result = $step->result || 'no result returned';
457 carp
"\nstep $step_name failed: " . $result;
463 sub _finish_printing_result
{
465 my $result = $argsref->{step
}->result || 'done';
467 if ($argsref->{args
}->{verbose
} or $argsref->{args
}->{verbose_step
}) {
468 # For more readable verbose output, we'll repeat the step description
471 print q{ } x
$spaces;
472 print $argsref->{description
};
474 ( $linelength - $spaces ) -
475 ( length($argsref->{description
}) + length($result) + 1 )
481 ( $argsref->{length_message
} + length($result) + 1 )
484 unless ( $argsref->{step_name
} =~ m{^inter} && $argsref->{args
}->{ask
} ) {
490 sub _update_conftrace
{
492 if (! defined $argsref->{conftrace
}->[0]) {
493 $argsref->{conftrace
}->[0] = [];
495 push @
{ $argsref->{conftrace
}->[0] }, $argsref->{step_name
};
497 options
=> $argsref->{conf
}->{options
},
498 data
=> $argsref->{conf
}->{data
},
500 push @
{ $argsref->{conftrace
} }, $evolved_data;
502 local $Storable::Deparse
= 1;
503 nstore
( $argsref->{conftrace
}, $argsref->{sto
} );
508 =item * C<option_or_data($arg)>
510 Are you tired of this construction all over the place?
512 my $opt = $conf->options->get( $arg );
513 $opt = $conf->data->get( $arg ) unless defined $opt;
515 It gives you the user-specified option for I<$arg>, and if there
516 isn't one, it gets it from the created data. You do it all the
517 time, but oh! the wear and tear on your fingers!
519 Toil no more! Use this simple construction:
521 my $opt = $conf->option_or_data($arg);
523 and save your fingers for some real work!
531 my $opt = $conf->options->get($arg);
532 return defined $opt ?
$opt : $conf->data->get($arg);
537 local $Storable::Deparse
= 1;
538 local $Storable::Eval
= 1;
539 return nfreeze
($conf);
544 my $serialized = shift;
545 foreach my $k (keys %{$conf}) {
548 local $Storable::Deparse
= 1;
549 local $Storable::Eval
= 1;
550 my %gut = %{ thaw
($serialized) };
551 while ( my ($k, $v) = each %gut ) {
560 When C<--verbose> is requested, or when a particular configuration step is
561 specified in C<--verbose-step>, this method prints its arguments as a string
567 my ($conf, @messages) = @_;
568 if ($conf->options->get('verbose')) {
569 print join('' => @messages);
578 The L</runsteps()> method is largely based on code written by Brent
579 Royal-Gordon C<brent@brentdax.com>.
583 Joshua Hoblitt C<jhoblitt@cpan.org>
587 F<docs/configuration.pod>, L<Parrot::Configure::Data>,
588 L<Parrot::Configure::Utils>, L<Parrot::Configure::Step>
596 # cperl-indent-level: 4
599 # vim: expandtab shiftwidth=4: