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);
27 This module provides a means for registering, executing, and
28 coordinating one or more configuration steps. Please see
29 F<docs/configuration.pod> for further details about the configuration
34 =head2 Import Parameters
36 This module accepts no arguments to its C<import> method and exports no
43 use Storable
qw(2.12 nstore retrieve nfreeze thaw);
44 use Parrot
::Configure
::Data
;
45 use base
qw(Parrot::Configure::Compiler);
50 'Parrot::Configure::Task' => {
52 object
=> 'Parrot::Configure::Step',
66 Accepts no arguments and returns a Parrot::Configure object.
75 data
=> Parrot
::Configure
::Data
->new,
76 options
=> Parrot
::Configure
::Data
->new,
78 bless $singleton, 'Parrot::Configure';
94 Provides access to a Parrot::Configure::Data object intended to contain
95 initial and discovered configuration data.
97 Accepts no arguments and returns a Parrot::Configure::Data object.
104 return $conf->{data
};
109 Provides access to a Parrot::Configure::Data object intended to contain CLI
112 Accepts no arguments and returns a Parrot::Configure::Data object.
119 return $conf->{options
};
124 Provides a list of registered steps, where each step is represented by an
125 Parrot::Configure::Task object. Steps are returned in the order in which
126 they were registered.
128 Accepts no arguments and returns a list in list context or an arrayref in
136 return wantarray ? @
{ $conf->{steps
} } : $conf->{steps
};
139 =item * C<get_list_of_steps()>
141 Provides a list of the B<names> of registered steps.
143 C<steps()>, in contrast, provides a list of registered step B<objects>, of
144 which the B<step name> is just a small part. Step names are returned in the
145 order in which their corresponding step objects were registered.
147 Accepts no arguments and returns a list in list context or an arrayref in
150 B<Note:> The list of step names returned by C<get_list_of_steps()> will be the
151 same as that in the second argument returned by
152 C<Parrot::Configure::Options::process_options()> B<provided> that you have not
153 used C<add_step()> or C<add_steps()> to add any configuration steps.
157 sub get_list_of_steps
{
159 die 'list_of_steps not available until steps have been added'
160 unless defined $conf->{list_of_steps
};
161 return wantarray ? @
{ $conf->{list_of_steps
} } : $conf->{list_of_steps
};
164 =item * C<add_step()>
166 Registers a new step and any parameters that should be passed to it. The
167 first parameter passed is the class name of the step being registered. All
168 other parameters are saved and passed to the registered class's C<runstep()>
171 Accepts a list and modifies the data structure within the
172 Parrot::Configure object.
177 my ( $conf, $step ) = @_;
179 push @
{ $conf->{steps
} },
180 Parrot
::Configure
::Task
->new(
187 =item * C<add_steps()>
189 Registers new steps to be run at the end of the execution queue.
191 Accepts a list of new steps and modifies the data structure within the
192 Parrot::Configure object.
197 my ( $conf, @new_steps ) = @_;
199 for ( my $i = 0 ; $i <= $#new_steps ; $i++ ) {
200 $conf->add_step( $new_steps[$i] );
201 push @
{ $conf->{list_of_steps
} }, $new_steps[$i];
202 $conf->{hash_of_steps
}->{ $new_steps[$i] } = $i + 1;
208 =item * C<runsteps()>
210 Sequentially executes steps in the order they were registered. The invoking
211 Parrot::Configure object is passed as the first argument to each step's
212 C<runstep()> method, followed by any parameters that were registered for that
215 Accepts no arguments and modifies the data structure within the
216 Parrot::Configure object.
223 my $n = 0; # step number
224 my ( $silent, $verbose, $verbose_step_str, $fatal, $fatal_step_str, $ask );
225 $silent = $conf->options->get(qw( silent ));
227 ( $verbose, $verbose_step_str, $fatal, $fatal_step_str, $ask ) =
228 $conf->options->get(qw( verbose verbose-step fatal fatal-step ask ));
232 my %steps_to_die_for = ();
233 # If the --fatal option is true, then all config steps are mapped into
234 # %steps_to_die_for and there is no consideration of --fatal-step.
236 %steps_to_die_for = map { ($_,1) } @
{ $conf->{list_of_steps
} };
238 # We make certain that argument to --fatal-step is a comma-delimited
239 # string of configuration steps, each of which is a string delimited by
240 # two colons, the first half of which is one of init|inter|auto|gen
241 elsif ( defined ( $fatal_step_str ) ) {
242 %steps_to_die_for = _handle_fatal_step_option
( $fatal_step_str );
245 # No action needed; this is the default case where no step is fatal
249 if (defined $verbose_step_str) {
250 %verbose_steps = _handle_verbose_step_option
( $verbose_step_str );
252 foreach my $task ( $conf->steps ) {
253 my ($red_flag, $this_step_is_verbose);
254 my $step_name = $task->step;
255 if ( scalar keys %steps_to_die_for ) {
256 if ( $steps_to_die_for{$step_name} ) {
260 if ( scalar keys %verbose_steps ) {
261 $this_step_is_verbose = $verbose_steps{$step_name}
267 my $rv = $conf->_run_this_step(
271 verbose_step
=> $this_step_is_verbose,
277 if ( ! defined $rv ) {
282 $conf->{log}->[$n] = {
291 sub _handle_fatal_step_option
{
292 my $fatal_step_str = shift;
293 my %steps_to_die_for = ();
294 my $named_step_pattern = qr/(?:init|inter|auto|gen)::\w+/;
295 if ( $fatal_step_str =~ m
{^
297 (, $named_step_pattern)*
300 my @fatal_steps = split /,/, $fatal_step_str;
301 for my $s (@fatal_steps) {
302 $steps_to_die_for{$s}++;
306 die q{Argument to fatal-step option must be comma-delimited string of valid configuration steps};
308 return %steps_to_die_for;
311 sub _handle_verbose_step_option
{
312 my $verbose_step_str = shift;
313 my %verbose_steps = ();
314 my $named_step_pattern = qr/(?:init|inter|auto|gen)::\w+/;
315 if ( $verbose_step_str =~ m
{^
317 (, $named_step_pattern)*
320 my @verbose_steps = split /,/, $verbose_step_str;
321 for my $s (@verbose_steps) {
322 $verbose_steps{$s}++;
326 die q{Argument to verbose-step option must be comma-delimited string of valid configuration steps};
328 return %verbose_steps;
331 =item * C<run_single_step()>
333 The invoking Parrot::Configure object is passed as the first argument to
334 each step's C<runstep()> method, followed by any parameters that were
335 registered for that step.
337 Accepts no arguments and modifies the data structure within the
338 Parrot::Configure object.
340 B<Note:> Currently used only in F<tools/dev/reconfigure.pl>; not used in
345 sub run_single_step
{
347 my $taskname = shift;
349 my ( $verbose, $verbose_step, $ask ) =
350 $conf->options->get(qw( verbose verbose-step ask ));
352 my $task = ( $conf->steps() )[0];
353 if ( $task->{'Parrot::Configure::Task::step'} eq $taskname ) {
354 $conf->_run_this_step(
358 verbose_step
=> $verbose_step,
365 die 'Mangled task in run_single_step';
375 my $step_name = $args->{task
}->step;
377 eval "use $step_name;"; ## no critic (BuiltinFunctions::ProhibitStringyEval)
381 my $sto = q{.configure_trace.sto};
383 local $Storable::Eval
= 1;
384 if ( $conf->options->get(q{configure_trace}) and ( -e
$sto ) ) {
385 $conftrace = retrieve
($sto);
388 my $step = $step_name->new();
390 # set per step verbosity
391 if ( $args->{verbose_step
} ) {
392 $conf->options->set( verbose
=> 2 );
395 my $stub = qq{$step_name - };
396 my $message = $stub .
397 (q{ } x
(22 - length($stub))) .
400 my $length_message = length($message);
401 unless ($args->{silent
}) {
402 # The first newline terminates the report on the *previous* step.
403 # (Probably needed to make interactive output work properly.
404 # Otherwise, we'd put it in _finish_printing_result().
407 print "\n" if $args->{verbose_step
};
411 # When successful, a Parrot configuration step now returns 1
412 eval { $ret = $step->runstep($conf); };
414 carp
"\nstep $step_name died during execution: $@\n";
418 # A Parrot configuration step can run successfully, but if it fails to
419 # achieve its objective it is supposed to return an undefined status.
421 # reset verbose value for the next step
422 $conf->options->set( verbose
=> $args->{verbose
} );
423 unless ($args->{silent
}) {
424 _finish_printing_result
(
427 step_name
=> $step_name,
429 description
=> $step->description,
430 length_message
=> $length_message,
434 if ($conf->options->get(q{configure_trace}) ) {
437 conftrace
=> $conftrace,
438 step_name
=> $step_name,
447 _failure_message
( $step, $step_name );
453 sub _failure_message
{
454 my ( $step, $step_name ) = @_;
455 my $result = $step->result || 'no result returned';
456 carp
"\nstep $step_name failed: " . $result;
462 sub _finish_printing_result
{
464 my $result = $argsref->{step
}->result || 'done';
466 if ($argsref->{args
}->{verbose
} or $argsref->{args
}->{verbose_step
}) {
467 # For more readable verbose output, we'll repeat the step description
470 print q{ } x
$spaces;
471 print $argsref->{description
};
473 ( $linelength - $spaces ) -
474 ( length($argsref->{description
}) + length($result) + 1 )
480 ( $argsref->{length_message
} + length($result) + 1 )
483 unless ( $argsref->{step_name
} =~ m{^inter} && $argsref->{args
}->{ask
} ) {
489 sub _update_conftrace
{
491 if (! defined $argsref->{conftrace
}->[0]) {
492 $argsref->{conftrace
}->[0] = [];
494 push @
{ $argsref->{conftrace
}->[0] }, $argsref->{step_name
};
496 options
=> $argsref->{conf
}->{options
},
497 data
=> $argsref->{conf
}->{data
},
499 push @
{ $argsref->{conftrace
} }, $evolved_data;
501 local $Storable::Deparse
= 1;
502 nstore
( $argsref->{conftrace
}, $argsref->{sto
} );
507 =item * C<option_or_data($arg)>
509 Are you tired of this construction all over the place?
511 my $opt = $conf->options->get( $arg );
512 $opt = $conf->data->get( $arg ) unless defined $opt;
514 It gives you the user-specified option for I<$arg>, and if there
515 isn't one, it gets it from the created data. You do it all the
516 time, but oh! the wear and tear on your fingers!
518 Toil no more! Use this simple construction:
520 my $opt = $conf->option_or_data($arg);
522 and save your fingers for some real work!
530 my $opt = $conf->options->get($arg);
531 return defined $opt ?
$opt : $conf->data->get($arg);
536 local $Storable::Deparse
= 1;
537 local $Storable::Eval
= 1;
538 return nfreeze
($conf);
543 my $serialized = shift;
544 foreach my $k (keys %{$conf}) {
547 local $Storable::Deparse
= 1;
548 local $Storable::Eval
= 1;
549 my %gut = %{ thaw
($serialized) };
550 while ( my ($k, $v) = each %gut ) {
561 The L</runsteps()> method is largely based on code written by Brent
562 Royal-Gordon C<brent@brentdax.com>.
566 Joshua Hoblitt C<jhoblitt@cpan.org>
570 F<docs/configuration.pod>, L<Parrot::Configure::Data>,
571 L<Parrot::Configure::Utils>, L<Parrot::Configure::Step>
579 # cperl-indent-level: 4
582 # vim: expandtab shiftwidth=4: