[svn:mod_parrot] r337 - in mod_parrot/branches/configure: config/directives lib/ModParrot lib/ModParrot/Configure
[email protected] Sat, 17 May 2008 17:53:19 -0700 (PDT)
| Newsgroups | perl.cvs.mod_parrot |
|---|---|
| Message-ID | <[email protected]> |
Author: particle
Date: Sat May 17 17:53:18 2008
New Revision: 337
Added:
mod_parrot/branches/configure/lib/ModParrot/Configure.pm
mod_parrot/branches/configure/lib/ModParrot/Configure/Data.pm
Modified:
mod_parrot/branches/configure/config/directives/configure.op
mod_parrot/branches/configure/lib/ModParrot/Configure/Messages.pm
Log:
[config] create/init configure objects, ready to write and perform configure tasks
Modified: mod_parrot/branches/configure/config/directives/configure.op
==============================================================================
--- mod_parrot/branches/configure/config/directives/configure.op (original)
+++ mod_parrot/branches/configure/config/directives/configure.op Sat May 17 17:53:18 2008
@@ -11,11 +11,11 @@
## print the intro
introduction
-### TODO do we really want this here, or should it exist by default?
-#configure_new
-#configure_set_args
-#
-### run the configuration steps
+## TODO do we really want this here, or should it exist by default?
+configure_new
+configure_set_args
+
+## run the configuration steps
#run init::manifest
#run init::defaults
#run init::install
Added: mod_parrot/branches/configure/lib/ModParrot/Configure.pm
==============================================================================
--- (empty file)
+++ mod_parrot/branches/configure/lib/ModParrot/Configure.pm Sat May 17 17:53:18 2008
@@ -0,0 +1,308 @@
+# Copyright (C) 2008, Jeff Horwitz.
+# $Id$
+
+=head1 NAME
+
+ModParrot::Configure - Conducts the execution of Configuration Steps
+
+=head1 SYNOPSIS
+
+ use ModParrot::Configure;
+
+ my $conf = ModParrot::Configure->new;
+ my $data = $conf->data;
+ my $options = $conf->options;
+ my @steps = $conf->steps;
+ $conf->add_steps(@steps);
+ $conf->runsteps;
+
+=head1 DESCRIPTION
+
+This module provides provides a means for registering, executing, and
+coordinating one or more Configuration steps. Please see
+F<docs/configuration.pod> for further details about the configuration
+framework.
+
+=cut
+
+package ModParrot::Configure;
+
+use strict;
+use warnings;
+
+use lib qw(config);
+use Carp qw(carp);
+use ModParrot::Configure::Data;
+
+use Class::Struct;
+
+struct(
+ 'ModParrot::Configure::Task' => {
+ step => '$',
+ params => '@',
+ object => 'ModParrot::Configure::Step',
+ },
+);
+
+
+=head2 Methods
+
+=over 4
+
+=item * C<new()>
+
+Basic constructor. Returns a L<ModParrot::Configure> object.
+
+=cut
+
+my $singleton;
+BEGIN {
+ $singleton = {
+ steps => [],
+ data => ModParrot::Configure::Data->new,
+ options => ModParrot::Configure::Data->new,
+ };
+ bless $singleton, "ModParrot::Configure";
+}
+
+sub new {
+ my $class = shift;
+ return $singleton;
+}
+
+
+=item * C<data()>
+
+Provides access to a L<ModParrot::Configure::Data> object intended to contain
+initial and discovered configuration data.
+
+Accepts no arguments and returns a L<ModParrot::Configure::Data> object.
+
+=cut
+
+sub data {
+ my $self = shift;
+
+ return $self->{data};
+}
+
+
+=item * C<options()>
+
+Provides access to a L<ModParrot::Configure::Data> object intended to contain CLI
+option data.
+
+Accepts no arguments and returns a L<ModParrot::Configure::Data> object.
+
+=cut
+
+sub options {
+ my $self = shift;
+
+ return $self->{options};
+}
+
+
+=item * C<steps()>
+
+Provides a list of registered steps, where each step is represented by an
+L<ModParrot::Configure::Task> object. Steps are returned in the order in which
+they were registered in.
+
+Accepts no arguments and returns a list in list context or an arrayref in
+scalar context.
+
+=cut
+
+sub steps {
+ my $self = shift;
+
+ return wantarray ? @{ $self->{steps} } : $self->{steps};
+}
+
+=item * C<add_step()>
+
+Registers a new step and any parameters that should be passed to it. The
+first parameter passed is the class name of the step being registered. All
+other parameters are saved and passed to the registered class's C<runstep()>
+method.
+
+Accepts a list and modifies the data structure within the L<ModParrot::Configure> object.
+
+=cut
+
+
+sub add_step {
+ my ( $self, $step, @params ) = @_;
+
+ push @{ $self->{steps} }, ModParrot::Configure::Task->new( step => $step, params => \@params );
+
+ return 1;
+}
+
+
+=item * C<add_steps()>
+
+Registers new steps to be run at the end of the execution queue.
+
+Accepts a list of new steps and modifies the data structure within the L<ModParrot::Configure> object.
+
+=cut
+
+sub add_steps {
+ my ( $self, @new_steps ) = @_;
+
+ foreach my $step (@new_steps) {
+ $self->add_step($step);
+ }
+
+ return 1;
+}
+
+
+=item * C<runsteps()>
+
+Sequentially executes steps in the order they were registered. The invoking
+L<ModParrot::Configure> object is passed as the first argument to each step's
+C<runstep()> method, followed by any parameters that were registered for that
+step.
+
+Accepts no arguments and modifies the data structure within the L<ModParrot::Configure> object.
+
+=cut
+
+sub runsteps {
+ my $self = shift;
+
+ my ( $verbose, $verbose_step, $ask ) = $self->options->get(qw(verbose verbose-step ask));
+
+ my $n = 0; # step number
+ foreach my $task ( $self->steps ) {
+ $n++;
+ $self->_runstep( $task, $verbose, $verbose_step, $ask, $n );
+ }
+ return 1;
+}
+
+
+=item * C<runstep()>
+
+The invoking L<ModParrot::Configure> object is passed as the first argument to
+each step's C<runstep()> method, followed by any parameters that were
+registered for that step.
+
+Accepts no arguments and modifies the data structure within the L<ModParrot::Configure> object.
+
+=cut
+
+sub runstep {
+ my $self = shift;
+ my $taskname = shift;
+
+ my ( $verbose, $verbose_step, $ask ) = $self->options->get(qw(verbose verbose-step ask));
+
+ for my $task ( $self->steps() ) {
+# print STDERR $task->{"ModParrot::Configure::Task::step"}, "\n";
+ if ( $task->{"ModParrot::Configure::Task::step"} eq $taskname ) {
+ $self->_runstep( $task, $verbose, $verbose_step, $ask, 1 );
+ }
+ }
+}
+
+
+sub _runstep {
+ my $self = shift;
+ my $task = shift;
+
+ my ( $verbose, $verbose_step, $ask, $n ) = @_;
+
+ my $step_name = $task->step;
+ my @step_params = @{ $task->params };
+
+ eval "use $step_name;";
+ die $@ if $@;
+
+ my $step = $step_name->new;
+
+ # XXX This works. but is probably not a good design.
+ # Using $step->description() would be nicer
+ my $description = $step->description();
+ $description = "" unless defined $description;
+
+ # set per step verbosity
+ if ( defined $verbose_step ) {
+
+ # by step number
+ if ( $verbose_step =~ /^\d+$/ && $n == $verbose_step ) {
+ $self->options->set( verbose => 2 );
+ }
+
+ # by description
+ elsif ( $description =~ /$verbose_step/ ) {
+ $self->options->set( verbose => 2 );
+ }
+ }
+
+ # XXX cc_build uses this verbose setting, why?
+ $self->data->set( verbose => $verbose ) if $n > 2;
+
+ print "\n", $description, '...';
+ print "\n" if $verbose && $verbose == 2;
+
+ my $ret; # step return value
+ eval {
+ if (@step_params)
+ {
+ $ret = $step->runstep( $self, @step_params );
+ }
+ else {
+ $ret = $step->runstep($self);
+ }
+ };
+ if ($@) {
+ carp "\nstep $step_name died during execution: $@\n";
+ return;
+ }
+
+ # did the step return itself?
+ eval { $ret->can('result'); };
+
+ # if not, report the result and return
+ if ($@) {
+ my $result = $step->result || 'no result returned';
+ carp "\nstep $step_name failed: " . $result;
+ return;
+ }
+
+ my $result = $step->result || 'done';
+
+ print "..." if $verbose && $verbose == 2;
+ print "." x ( 71 - length($description) - length($result) );
+ print "$result." unless $step =~ m{^inter/} && $ask;
+
+ # reset verbose value for the next step
+ $self->options->set( verbose => $verbose );
+}
+
+
+=back
+
+=head1 CREDITS
+
+The L</runsteps()> method is largely based on code written by Brent
+Royal-Gordon C<[email protected]>.
+
+=head1 AUTHOR
+
+Joshua Hoblitt C<[email protected]>
+
+=head1 SEE ALSO
+
+F<docs/configuration.pod>, L<ModParrot::Configure::Data>,
+L<ModParrot::Configure::Step>, L<ModParrot::Configure::Step::Base>
+
+=cut
+
+1;
+
+# vim: expandtab shiftwidth=4:
Added: mod_parrot/branches/configure/lib/ModParrot/Configure/Data.pm
==============================================================================
--- (empty file)
+++ mod_parrot/branches/configure/lib/ModParrot/Configure/Data.pm Sat May 17 17:53:18 2008
@@ -0,0 +1,361 @@
+# Copyright (C) 2008, Jeff Horwitz.
+# $Id$
+
+=pod
+
+=head1 NAME
+
+ModParrot::Configure::Data - Configuration data container
+
+=head1 SYNOPSIS
+
+ use ModParrot::Configure::Data;
+
+ my $data = ModParrot::Configure::Data->new;
+ my @values = $data->get(@keys);
+ $data->set($key1 => $value1, $key2 => $value2);
+ $data->add($delimiter, $key1 => $value1, $key2 => $value2);
+ my @keys = $data->keys;
+ my $serialized = $data->dump;
+ $data->clean;
+ $data->settrigger($key, $trigger, $cb);
+ $data->gettriggers($key);
+ $data->gettrigger($key, $trigger);
+ $data->deltrigger($key, $trigger);
+
+=head1 DESCRIPTION
+
+This module contains configuration data for use by the other
+L<ModParrot::Configure::*> modules.
+
+=head1 USAGE
+
+=head2 Import Parameters
+
+This module accepts no arguments to its C<import> method and exports no
+I<symbols>.
+
+=cut
+
+package ModParrot::Configure::Data;
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+
+=head2 Methods
+
+=over 4
+
+=item C<new()>
+
+Basic object constructor.
+
+Accepts no arguments and returns a L<ModParrot::Configure::Data> object.
+
+=cut
+
+sub new {
+ my $class = shift;
+
+ my $self = {
+ c => {},
+ triggers => {},
+ };
+
+ bless $self, ref $class || $class;
+ return $self;
+}
+
+
+=item C<get($key, ...)>
+
+Provides access to key values.
+
+Accepts a list and returns a list.
+
+=cut
+
+sub get {
+ my $self = shift;
+
+ my $c = $self->{c};
+
+ return @$c{@_};
+}
+
+
+=item C<set($key => $val, ...)>
+
+Modifies or creates a new value.
+
+Accepts a list of C<< key => value >> pairs and returns a
+L<ModParrot::Configure::Data> object.
+
+=cut
+
+sub set {
+ my $self = shift;
+
+ my $verbose = defined $self->get('verbose') && $self->get('verbose') == 2;
+
+ print "Setting Configuration Data:\n(\n" if $verbose;
+
+ while ( my ( $key, $val ) = splice @_, 0, 2 ) {
+ print "\t$key => ", defined($val) ? "'$val'" : 'undef', ",\n"
+ if $verbose;
+ $self->{c}{$key} = $val;
+
+ foreach my $trigger ( $self->gettriggers($key) ) {
+ print "\tcalling trigger $trigger for $key\n" if $verbose;
+ my $cb = $self->gettrigger( $key, $trigger );
+
+ &$cb( $key, $val );
+ }
+ }
+
+ print ");\n" if $verbose;
+
+ return $self;
+}
+
+
+=item C<add($delim, $key => $val, ...)>
+
+Either creates a new key or appends to an existing key, with the previous/new
+values joined together by C<$delim>.
+
+Accepts a delimiter value followed by a list of C<< key => value >> pairs and
+returns a L<ModParrot::Configure::Data> object.
+
+=cut
+
+sub add {
+ my $self = shift;
+ my $delim = shift;
+
+ while ( my ( $key, $val ) = splice @_, 0, 2 ) {
+ my ($old) = $self->{c}{$key};
+ if ( defined $old ) {
+ $self->set( $key, "$old$delim$val" );
+ }
+ else {
+ $self->set( $key, $val );
+ }
+ }
+
+ return $self;
+}
+
+
+=item C<keys()>
+
+Provides a list of keys.
+
+Accepts no arguments and returns a list.
+
+=cut
+
+sub keys {
+ my $self = shift;
+
+ return keys %{ $self->{c} };
+}
+
+
+=item C<slurp()>
+
+Slurps in L<ModParrot::Config> data from previous configure.
+
+Accepts no arguments.
+
+=cut
+
+sub slurp() {
+ my $self = shift;
+ my $res = eval "no strict; use ModParrot::Config::Generated; \\%PConfig";
+
+ if ( not defined $res ) {
+ die "You cannot use --step until you have completed the full configure process\n";
+ }
+ $self->{c} = $res;
+}
+
+
+=item C<dump()>
+
+Provides a L<Data::Dumper> serialized string of the objects key/value pairs
+suitable for being C<eval>ed. The variable name of the structure is
+C<PConfig>.
+
+Accepts no arguments and returns a string.
+
+=cut
+
+# Data::Dumper supports Sortkeys since 2.12
+# older versions will work but obviously not sorted
+{
+ my $dd_version;
+ if ( $Data::Dumper::VERSION =~ /([\d.]+)/ ) {
+ $dd_version = $1;
+ }
+ else {
+ $dd_version = $Data::Dumper::VERSION;
+ }
+
+ if ( $dd_version >= 2.12 ) {
+ *dump = sub {
+ my $self = shift;
+ Data::Dumper->new( [ $self->{c} ], ['*PConfig'] )->Sortkeys(1)->Dump();
+ };
+ }
+ else {
+ *dump = sub {
+ my $self = shift;
+ Data::Dumper->new( [ $self->{c} ], ['*PConfig'] )->Dump();
+ };
+ }
+}
+
+
+=item C<clean()>
+
+Deletes keys matching C</^TEMP_/>. Keys using this naming convention are
+intended to be used only temporally, e.g. as file lists for Makefile
+generation.
+
+Accepts no arguments and returns a L<ModParrot::Configure::Data> object.
+
+=cut
+
+sub clean {
+ my $self = shift;
+
+ delete $self->{c}{$_} for grep { /^TEMP_/ } CORE::keys %{ $self->{c} };
+
+ return $self;
+}
+
+
+=item C<settrigger($key, $trigger, $cb)>
+
+Set a callback on C<$key> named C<$trigger>. Multiple triggers can be set on a
+given key. When the key is set via C<set> or C<add> then all callbacks that
+are defined will be called. Triggers are passed the key and value that was set
+after it has been changed.
+
+Accepts a key name, a trigger name, & a C<CODE> ref and returns a
+L<ModParrot::Configure::Data> object.
+
+=cut
+
+sub settrigger {
+ my ( $self, $key, $trigger, $cb ) = @_;
+
+ return unless defined $key and defined $trigger and defined $cb;
+
+ my $verbose = defined $self->get('verbose') && $self->get('verbose') == 2;
+
+ print "Setting trigger $trigger on configuration key $key\n",
+ if $verbose;
+
+ $self->{triggers}{$key}{$trigger} = $cb;
+
+ return $self;
+}
+
+
+=item C<gettriggers($key)>
+
+Get the names of all triggers set for C<$key>.
+
+Accepts a key name and returns a list.
+
+=cut
+
+sub gettriggers {
+ my ( $self, $key ) = @_;
+
+ return unless defined $self->{triggers}{$key};
+
+ my $verbose = defined $self->get('verbose') && $self->get('verbose') == 2;
+
+ print "Looking up all triggers on configuration key $key\n"
+ if $verbose;
+
+ return CORE::keys %{ $self->{triggers}{$key} };
+}
+
+
+=item C<gettrigger($key, $trigger)>
+
+Get the callback set for C<$key> under the name C<$trigger>
+
+Accepts a key name & a trigger name and returns a C<CODE> ref.
+
+=cut
+
+sub gettrigger {
+ my ( $self, $key, $trigger ) = @_;
+
+ return
+ unless defined $self->{triggers}{$key}
+ and defined $self->{triggers}{$key}{$trigger};
+
+ my $verbose = defined $self->get('verbose') && $self->get('verbose') == 2;
+
+ print "Looking up trigger $trigger on configuration key $key\n"
+ if $verbose;
+
+ return $self->{triggers}{$key}{$trigger};
+}
+
+
+=item C<deltrigger($key, $trigger)>
+
+Removes the trigger on C<$key> named by C<$trigger>
+
+Accepts a key name & a trigger name and returns a L<ModParrot::Configure::Data>
+object.
+
+=cut
+
+sub deltrigger {
+ my ( $self, $key, $trigger ) = @_;
+
+ return
+ unless defined $self->{triggers}{$key}
+ and defined $self->{triggers}{$key}{$trigger};
+
+ my $verbose = defined $self->get('verbose') && $self->get('verbose') == 2;
+
+ print "Removing trigger $trigger on configuration key $key\n"
+ if $verbose;
+
+ delete $self->{triggers}{$key}{$trigger};
+
+ return $self;
+}
+
+
+=back
+
+=head1 CREDITS
+
+Based largely on code written by Brent Royal-Gordon C<[email protected]>.
+
+=head1 AUTHOR
+
+Joshua Hoblitt C<[email protected]>
+
+=head1 SEE ALSO
+
+F<docs/configuration.pod>, L<ModParrot::Configure>, L<ModParrot::Configure::Step>,
+L<ModParrot::Configure::Step::Base>
+
+=cut
+
+1;
+
+# vim: expandtab shiftwidth=4:
Modified: mod_parrot/branches/configure/lib/ModParrot/Configure/Messages.pm
==============================================================================
--- mod_parrot/branches/configure/lib/ModParrot/Configure/Messages.pm (original)
+++ mod_parrot/branches/configure/lib/ModParrot/Configure/Messages.pm Sat May 17 17:53:18 2008
@@ -42,9 +42,9 @@
Copyright (C) 2008, Jeff Horwitz.
Hello, I'm Configure. My job is to poke and prod your system to figure out
-how to build mod_parrot. The process is completely automated, unless you passed in
-the `--ask' flag on the command line, in which case it'll prompt you for a few
-pieces of info.
+how to build mod_parrot. The process is completely automated, unless you
+passed in the "--ask" flag on the command line, in which case you will be
+prompted for a few pieces of info.
INTRODUCTION
}