From 2cc6e72ebbe619872cdbb30e121376947107686c Mon Sep 17 00:00:00 2001 From: Vadim Belman Date: Fri, 15 Jul 2016 19:05:51 -0400 Subject: [PATCH] Item13897: Converted toold/configure Tested with -save only so far. - configure doesn't use setlib.cfg. - Foswiki::Configure::Item::ATTRSPEC converted from constant to a object attribute. Method _establishATTRSPEC must be overriden by a subclass to provide defaults. --- core/lib/Foswiki/Configure/Item.pm | 47 ++++++--- core/lib/Foswiki/Configure/LoadSpec.pm | 17 ++-- core/lib/Foswiki/Configure/Package.pm | 20 ++-- core/lib/Foswiki/Configure/Section.pm | 14 +-- core/lib/Foswiki/Configure/Value.pm | 44 ++++----- core/tools/configure | 130 ++++++++++++++----------- 6 files changed, 152 insertions(+), 120 deletions(-) diff --git a/core/lib/Foswiki/Configure/Item.pm b/core/lib/Foswiki/Configure/Item.pm index 290b234bce..7b0ff890dc 100644 --- a/core/lib/Foswiki/Configure/Item.pm +++ b/core/lib/Foswiki/Configure/Item.pm @@ -32,23 +32,20 @@ use Moo; use namespace::clean; extends qw(Foswiki::Object); -# Schema for dynamic attributes -use constant ATTRSPEC => {}; - has attrs => ( - is => 'rw', + is => 'rw', + lazy => 1, + trigger => sub { $_[0]->_checkOpts; }, + isa => Foswiki::Object::isaHASH( 'attrs', noUndef => 1, ), + required => 1, +); + +# Schema for dynamic attributes +has ATTRSPEC => ( + is => 'ro', lazy => 1, - clearer => 1, - default => sub { {} }, - trigger => sub { - my $this = shift; - my ($newAttrs) = @_; - if ( $newAttrs->{opts} ) { - $this->_parseOptions( $newAttrs->{opts} ); - delete $this->attrs->{opts}; - } - }, - isa => Foswiki::Object::isaHASH( 'attrs', noUndef => 1, ), + builder => '_establishATTRSPEC', + isa => Foswiki::Object::isaHASH( 'ATTRSPEC', noUndef => 1, ), ); =begin TML @@ -66,8 +63,8 @@ around BUILDARGS => sub { $params{desc} //= ''; foreach my $attr ( keys %params ) { + $params{attrs}{$attr} = $params{$attr}; unless ( $class->can($attr) ) { - $params{attrs}{$attr} = $params{$attr}; delete $params{$attr}; } } @@ -75,6 +72,24 @@ around BUILDARGS => sub { return $orig->( $class, %params ); }; +sub BUILD { + my $this = shift; + + $this->_checkOpts; +} + +sub _checkOpts { + my $this = shift; + if ( $this->attrs->{opts} ) { + $this->_parseOptions( $this->attrs->{opts} ); + delete $this->attrs->{opts}; + } +} + +sub _establishATTRSPEC { + return {}; +} + sub stringify { my $this = shift; my $s = Data::Dumper->Dump( [ $this->TO_JSON() ] ); diff --git a/core/lib/Foswiki/Configure/LoadSpec.pm b/core/lib/Foswiki/Configure/LoadSpec.pm index b08ba29386..dde4ac8baf 100644 --- a/core/lib/Foswiki/Configure/LoadSpec.pm +++ b/core/lib/Foswiki/Configure/LoadSpec.pm @@ -3,6 +3,7 @@ # Inner class that represents section headings temporarily during the # parse. They are expanded to section blocks at the end. package SectionMarker; +use v5.14; use Moo; extends qw(Foswiki::Configure::Item); @@ -14,6 +15,7 @@ sub BUILD { my $this = shift; $this->Depth( $this->Depth + 1 ); } sub getValueObject { return; } package Foswiki::Configure::LoadSpec; +use v5.14; =begin TML @@ -73,13 +75,12 @@ use warnings; use Assert; use Try::Tiny; -use Foswiki::Configure::Section (); -use Foswiki::Configure::Value (); -use Foswiki::Configure::Item (); -use Foswiki::Configure::Load (); -use Foswiki::Configure::FileUtil (); -use Foswiki::Configure::Pluggable (); -use Foswiki::Configure::Reporter (); +use Foswiki::Configure::Section; +use Foswiki::Configure::Value; +use Foswiki::Configure::Load; +use Foswiki::Configure::FileUtil; +use Foswiki::Configure::Pluggable; +use Foswiki::Configure::Reporter; our $TRUE = 1; # Required for checking default value syntax our $FALSE = 0; @@ -308,7 +309,7 @@ sub parse { $open = Foswiki::Configure::Value->new( typename => $type, opts => $opts, - defined_at => [ $file, $. ] + defined_at => [ $file, $. ], ); $reporter->NOTE( "\tOpened " . $open->attrs->{typename} ) if TRACE; diff --git a/core/lib/Foswiki/Configure/Package.pm b/core/lib/Foswiki/Configure/Package.pm index ef68f7fc26..97788f75c4 100644 --- a/core/lib/Foswiki/Configure/Package.pm +++ b/core/lib/Foswiki/Configure/Package.pm @@ -510,11 +510,11 @@ HERE # Add it to the $spec $spec->addChild( Foswiki::Configure::Value->new( - 'BOOLEAN', - LABEL => $plu, - keys => "{Plugins}{$plu}{Enabled}", - CHECKER => 'PLUGIN_MODULE', - default => '1' + typename => 'BOOLEAN', + LABEL => $plu, + keys => "{Plugins}{$plu}{Enabled}", + CHECKER => 'PLUGIN_MODULE', + default => '1' ) ); } @@ -529,11 +529,11 @@ HERE # Add it to the $spec $spec->addChild( Foswiki::Configure::Value->new( - 'STRING', - LABEL => "$plu Module", - keys => "{Plugins}{$plu}{Module}", - CHECKER => 'PLUGIN_MODULE', - default => 'Foswiki::Plugins::$plu' + typename => 'STRING', + LABEL => "$plu Module", + keys => "{Plugins}{$plu}{Module}", + CHECKER => 'PLUGIN_MODULE', + default => 'Foswiki::Plugins::$plu' ) ); } diff --git a/core/lib/Foswiki/Configure/Section.pm b/core/lib/Foswiki/Configure/Section.pm index 1a336c3049..fc51672324 100644 --- a/core/lib/Foswiki/Configure/Section.pm +++ b/core/lib/Foswiki/Configure/Section.pm @@ -18,12 +18,6 @@ use Moo; use namespace::clean; extends qw(Foswiki::Configure::Item); -# Attributes legal on a section header -use constant ATTRSPEC => { - EXPERT => {}, - SORTED => {} -}; - =begin TML ---++ ClassMethod new(@opts) @@ -45,6 +39,14 @@ around BUILDARGS => sub { return $orig->( $class, %params ); }; +# Attributes legal on a section header +around _establishATTRSPEC => sub { + return { + EXPERT => {}, + SORTED => {} + }; +}; + =begin TML ---++ ObjectMethod addChild($child) diff --git a/core/lib/Foswiki/Configure/Value.pm b/core/lib/Foswiki/Configure/Value.pm index 2aeb79fb11..08e3aa68d3 100755 --- a/core/lib/Foswiki/Configure/Value.pm +++ b/core/lib/Foswiki/Configure/Value.pm @@ -50,8 +50,6 @@ Processes are used to parse 'FEEDBACK' and 'CHECK' values. =cut package Foswiki::Configure::Value; - -use strict; use v5.14; use Data::Dumper (); @@ -65,26 +63,6 @@ use Moo; use namespace::clean; extends qw(Foswiki::Configure::Item); -# Options valid in a .spec for a leaf value -use constant ATTRSPEC => { - CHECK => { handler => '_CHECK' }, - CHECKER => {}, - CHECK_ON_CHANGE => {}, - DISPLAY_IF => { openclose => 1 }, - ENABLE_IF => { openclose => 1 }, - EXPERT => {}, - FEEDBACK => { handler => '_FEEDBACK' }, - HIDDEN => {}, - MULTIPLE => {}, # Allow multiple select - SPELLCHECK => {}, - LABEL => {}, - ONSAVE => {}, # Call Checker->onSave() when set. - - # Rename single character options (legacy) - H => 'HIDDEN', - M => { handler => '_MANDATORY' } -}; - # Legal options for a CHECK. The number indicates the number of expected # parameters; -1 means '0 or more' our %CHECK_options = ( @@ -136,6 +114,28 @@ sub BUILD { $this->attrs->{CHECK}->{emptyok} //= 1; # required for legacy } +# Options valid in a .spec for a leaf value +around _establishATTRSPEC => sub { + return { + CHECK => { handler => '_CHECK' }, + CHECKER => {}, + CHECK_ON_CHANGE => {}, + DISPLAY_IF => { openclose => 1 }, + ENABLE_IF => { openclose => 1 }, + EXPERT => {}, + FEEDBACK => { handler => '_FEEDBACK' }, + HIDDEN => {}, + MULTIPLE => {}, # Allow multiple select + SPELLCHECK => {}, + LABEL => {}, + ONSAVE => {}, # Call Checker->onSave() when set. + + # Rename single character options (legacy) + H => 'HIDDEN', + M => { handler => '_MANDATORY' }, + }; +}; + # Return true if this value is one of the preformatted types. Values for # these types transfer verbatim from the UI to the LocalSite.cfg sub isFormattedType { diff --git a/core/tools/configure b/core/tools/configure index ebe233e916..5e1b5ab9ff 100755 --- a/core/tools/configure +++ b/core/tools/configure @@ -22,21 +22,19 @@ # # As per the GPL, removal of this notice is prohibited. +use v5.14; use warnings; use strict; use Encode; use Getopt::Long; +use Storable qw(dclone); use Pod::Usage (); use Data::Dumper (); # Assume we are in the tools dir, and we can find bin and lib from there -use FindBin (); -$FindBin::Bin =~ /^(.*)$/; -my $bin = $1; - -use lib "$FindBin::Bin/../bin"; -require 'setlib.cfg'; +use FindBin; +use lib "$FindBin::Bin/../lib"; # SMELL: setlib does "require CGI" which sets STDIN to binmode. binmode( STDIN, ':crlf' ); @@ -44,28 +42,32 @@ binmode( STDIN, ':crlf' ); # require, not use. The libpath is resolved by setlib.cfg, # so "use SomeModule;" will fail. -require Assert; +use Assert; + +use Foswiki::App; -require Foswiki::Configure::Root; -require Foswiki::Configure::LoadSpec; -require Foswiki::Configure::Load; -require Foswiki::Configure::Query; +#require Foswiki::Configure::Root; +#require Foswiki::Configure::LoadSpec; +#require Foswiki::Configure::Load; +#require Foswiki::Configure::Query; { package Foswiki::Configure::ShellReporter; - require Foswiki::Configure::Reporter; - our @ISA = ('Foswiki::Configure::Reporter'); + use Moo; + use namespace::clean; + extends qw(Foswiki::Configure::Reporter); - sub new { - return bless( {}, $_[0] ); - } + has notes => ( is => 'rw', default => 0, ); + has warnings => ( is => 'rw', default => 0, ); + has errors => ( is => 'rw', default => 0, ); - sub NOTE { + around NOTE => sub { + my $orig = shift; my $this = shift; my $text = join( "\n", @_ ) . "\n"; - $this->{notes}++; + $this->notes( $this->notes + 1 ); # Take out block formatting tags $text =~ s/<\/?verbatim>//g; @@ -73,37 +75,42 @@ require Foswiki::Configure::Query; # Take out active elements $text =~ s/<(button|select|option|textarea).*?<\/\1>//g; print $text; - } + }; - sub WARN { + around WARN => sub { + my $orig = shift; my $this = shift; - $this->{warnings}++; + $this->warnings( $this->warnings + 1 ); print "WARNING: "; $this->NOTE(@_); - } + }; - sub ERROR { + around ERROR => sub { + my $orif = shift; my $this = shift; - $this->{errors}++; + $this->errors( $this->errors + 1 ); print "#### ERROR: "; $this->NOTE(@_); - } + }; - sub CHANGED { + around CHANGED => sub { + my $orig = shift; my ( $this, $k ) = @_; - $this->SUPER::CHANGED($k); - print "\$Foswiki::cfg$k = $this->{changes}->{$k};\n"; - } + $orig->( $this, $k ); + + print "\$Foswiki::cfg$k = " . $this->changes->{$k} . ";\n"; + }; - sub WIZARD { + around WIZARD => sub { return ''; - } + }; - sub has_level { + around has_level => sub { + my $orig = shift; my ( $this, $level ) = @_; - return $this->{$level}; - } + return $this->$level; + }; }; # Command-line parameter handling @@ -250,25 +257,31 @@ sub _prompt { #$Foswiki::Configure::LoadSpec::RAW_VALS = 1; # Initialise -if ( Foswiki::Configure::Load::readConfig( 0, 0, 0 ) ) { - $Foswiki::cfg{isVALID} = 1; +my $app = Foswiki::App->new( env => dclone( \%ENV ), ); + +# Force config re-read to be independant of any possible variations in config +# constructor. +my $cfg = $app->cfg; +$cfg->clear_data; +if ( $cfg->readConfig( 0, 0, 0 ) ) { + $cfg->data->{isVALID} = 1; } -my $root = Foswiki::Configure::Root->new(); -my $reporter = Foswiki::Configure::ShellReporter->new(); +my $root = $app->create('Foswiki::Configure::Root'); +my $reporter = $app->create('Foswiki::Configure::ShellReporter'); Foswiki::Configure::LoadSpec::readSpec( $root, $reporter ); if ( $reporter->has_level('errors') ) { exit 1; } -unless ( $Foswiki::cfg{isVALID} ) { - %Foswiki::cfg = (); +unless ( $cfg->data->{isVALID} ) { + $cfg->clear_data; print STDERR "LocalSite.cfg load failed\n" . Foswiki::Configure::Reporter::stripStacktrace($@); # Run the bootstrap process. This guesses all the critical path settings. - Foswiki::Configure::Load::bootstrapConfig(); + $cfg->bootstrapSystemSettings; #SMELL: Another way to do this would be to loop through $Foswiki::cfg{BOOTSTRAP} array # of config keys, But this allows customized prompts and defaults. Anything prompted @@ -299,7 +312,7 @@ unless ( $Foswiki::cfg{isVALID} ) { unless ($@) { _prompt( $root, '{Password}', undef, "Enter a password for the 'admin' sudo account.\n" ); - push( @{ $Foswiki::cfg{BOOTSTRAP} }, '{Password}' ); + push( @{ $cfg->data->{BOOTSTRAP} }, '{Password}' ); } else { print @@ -314,27 +327,27 @@ unless ( $Foswiki::cfg{isVALID} ) { # But the encoding needs to be reversed when passing it through the command prompt _prompt( $root, '{ScriptDir}', - Encode::encode_utf8( $Foswiki::cfg{ScriptDir} ) ); - _prompt( $root, '{ScriptSuffix}', $Foswiki::cfg{ScriptSuffix}, + Encode::encode_utf8( $cfg->data->{ScriptDir} ) ); + _prompt( $root, '{ScriptSuffix}', $cfg->data->{ScriptSuffix}, undef, 1 ); _prompt( $root, '{DataDir}', - Encode::encode_utf8( $Foswiki::cfg{DataDir} ) ); + Encode::encode_utf8( $cfg->data->{DataDir} ) ); _prompt( $root, '{PubDir}', - Encode::encode_utf8( $Foswiki::cfg{PubDir} ) ); + Encode::encode_utf8( $cfg->data->{PubDir} ) ); _prompt( $root, '{TemplateDir}', - Encode::encode_utf8( $Foswiki::cfg{TemplateDir} ) ); + Encode::encode_utf8( $cfg->data->{TemplateDir} ) ); _prompt( $root, '{LocalesDir}', - Encode::encode_utf8( $Foswiki::cfg{LocalesDir} ) ); + Encode::encode_utf8( $cfg->data->{LocalesDir} ) ); _prompt( $root, '{WorkingDir}', - Encode::encode_utf8( $Foswiki::cfg{WorkingDir} ) ); + Encode::encode_utf8( $cfg->data->{WorkingDir} ) ); _prompt( $root, '{ToolsDir}', - Encode::encode_utf8( $Foswiki::cfg{ToolsDir} ) ); + Encode::encode_utf8( $cfg->data->{ToolsDir} ) ); _prompt( $root, '{Store}{Implementation}', - $Foswiki::cfg{Store}{Implementation} ); - _prompt( $root, '{Store}{Encoding}', $Foswiki::cfg{Store}{Encoding}, + $cfg->data->{Store}{Implementation} ); + _prompt( $root, '{Store}{Encoding}', $cfg->data->{Store}{Encoding}, undef, 1 ); _prompt( $root, '{Store}{SearchAlgorithm}', - $Foswiki::cfg{Store}{SearchAlgorithm} ); + $cfg->data->{Store}{SearchAlgorithm} ); print "You should now run tools/configure -check to validate your new configuration!\n"; @@ -449,17 +462,18 @@ sub _set_logger { my $params = shift; unless ( $params->{logger} ) { - if ( $Foswiki::cfg{Log}{Implementation} eq 'none' ) { - $params->{logger} = Foswiki::Logger->new(); + if ( $cfg->data->{Log}{Implementation} eq 'none' ) { + $params->{logger} = $app->create('Foswiki::Logger'); } else { - eval "require $Foswiki::cfg{Log}{Implementation}"; + eval "require " . $cfg->data->{Log}{Implementation}; if ($@) { print STDERR "Logger load failed: $@"; - $params->{logger} = Foswiki::Logger->new(); + $params->{logger} = $app->create('Foswiki::Logger'); } else { - $params->{logger} = $Foswiki::cfg{Log}{Implementation}->new(); + $params->{logger} = + $app->create( $cfg->data->{Log}{Implementation} ); } } }