diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2019-03-21 07:55:38 +0100 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2019-03-21 10:07:28 +0100 |
commit | a9845d6973ca7271437a6fbc659f48cd1100add3 (patch) | |
tree | 2a69fe5d036115192002c719f9397cac5a5ecef5 | |
parent | a297c865dd4611c4fd862e59c70ba1b72a142035 (diff) | |
download | slackbuilder-a9845d6973ca7271437a6fbc659f48cd1100add3.tar.gz slackbuilder-a9845d6973ca7271437a6fbc659f48cd1100add3.tar.bz2 |
Switch to Log::Log4perl for logging
* Makefile.PL: Add Log::Log4perl and Log::Dispatch to the list of
prerequisites.
* lib/SlackBuild/Config.pm (core.logging): New statement.
* lib/SlackBuild/Archive.pm (logger): New method. Use it for diagnostics.
* lib/SlackBuild/Rc.pm: Likewise.
* lib/SlackBuild/URI.pm: Likewise,
* lib/SlackBuilder.pm: Use Log::Log4perl. Rewrite the real-time parser for
the stdout and stderr obtained from the builder.
* slackbuilder: Remove unused functions.
-rw-r--r-- | Makefile.PL | 2 | ||||
-rw-r--r-- | lib/SlackBuild/Archive.pm | 10 | ||||
-rw-r--r-- | lib/SlackBuild/Config.pm | 3 | ||||
-rw-r--r-- | lib/SlackBuild/Rc.pm | 5 | ||||
-rw-r--r-- | lib/SlackBuild/URI.pm | 15 | ||||
-rw-r--r-- | lib/SlackBuilder.pm | 241 | ||||
-rwxr-xr-x | slackbuilder | 11 |
7 files changed, 214 insertions, 73 deletions
diff --git a/Makefile.PL b/Makefile.PL index 776890c..e92a8b5 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -23,12 +23,14 @@ WriteMakefile(NAME => 'slackbuilder', 'HTTP::Response' => 0, 'HTTP::Status' => 0, 'JSON' => 0., 'YAML' => '1.20', 'LWP::UserAgent' => '6.29', 'List::Regexp' => '1.03', + 'Log::Log4perl' => '1.48', + 'Log::Dispatch' => '2.67', #Net::SBo 'POSIX' => 0, 'POSIX::Run::Capture' => 0, 'Safe' => 0, 'Scalar::Util' => 0, 'Text::ParseWords' => 0, diff --git a/lib/SlackBuild/Archive.pm b/lib/SlackBuild/Archive.pm index 2f3663e..03fd17b 100644 --- a/lib/SlackBuild/Archive.pm +++ b/lib/SlackBuild/Archive.pm @@ -4,12 +4,13 @@ use warnings; use parent 'SlackBuild::URI'; use SlackBuild::Archive::Extractor; use SlackBuild::Info; use File::Temp qw/ tempfile tempdir /; use File::Basename; use File::Spec; +use Log::Log4perl; use Carp; *AUTOLOAD = \&SlackBuild::URI::AUTOLOAD; sub new { my ($class, $pname) = (shift, shift); @@ -83,25 +84,22 @@ sub _read_info { sub info { my ($self) = @_; return $self->{_info} ||= new SlackBuild::Info; } -sub download_success { - my $self = shift; - return $self->{_last_success}; -} - sub download_status { my $self = shift; return $self->SUPER::download_status unless exists $self->{_last_status}; return $self->{_last_status}; } +sub logger { shift->{_logger} //= Log::Log4perl::get_logger(__PACKAGE__) } + sub error { my $self = shift; - $self->{_last_success} = 0; $self->{_last_status} = shift; + $self->logger->error($self->{_last_status}); return 0; } 1; diff --git a/lib/SlackBuild/Config.pm b/lib/SlackBuild/Config.pm index 0790c7d..2d9fbb2 100644 --- a/lib/SlackBuild/Config.pm +++ b/lib/SlackBuild/Config.pm @@ -37,14 +37,15 @@ sub check_dir { return 1; } 1; __DATA__ [core] - image = STRING :mandatory + image = STRING :mandatory verbose = NUMBER :mandatory 0 + logging = STRING :mandatory /etc/slackbuilder/logging.conf [dir] root = STRING :check=check_dir :mandatory /srv/slackbuild tmp = STRING :mandatory tmp log = STRING :mandatory log pkg = STRING :mandatory pkg spool = STRING :mandatory spool diff --git a/lib/SlackBuild/Rc.pm b/lib/SlackBuild/Rc.pm index 022386a..c40ccc1 100644 --- a/lib/SlackBuild/Rc.pm +++ b/lib/SlackBuild/Rc.pm @@ -1,18 +1,21 @@ package SlackBuild::Rc; use strict; use warnings; use Carp; use SlackBuild::Registry::Record; use SlackBuild::Registry::Pattern; +use Log::Log4perl; sub new { my ($class, $builder) = @_; return bless { _builder => $builder }, $class; } +sub logger { shift->{_logger} //= Log::Log4perl::get_logger(__PACKAGE__) } + sub builder { shift->{_builder} } sub resolve { my ($self, $reg) = @_; my @packages; my @unresolved; @@ -36,13 +39,13 @@ sub resolve { } sub code { my ($self, $reg) = @_; my ($pkglist, $unresolved) = $self->resolve($reg); if (@$unresolved) { - $self->builder->error("$_: package not resolved") for (@$unresolved); + $self->logger->error("$_: package not resolved") for (@$unresolved); return; } my @code = ('#! /bin/sh', 'set -e', '(. /etc/os-release; echo SLACKBUILDER: DISTRO $NAME; echo SLACKBUILDER: VERSION $VERSION)', map { "/sbin/upgradepkg --install-new /var/pkg/$_" } @$pkglist); diff --git a/lib/SlackBuild/URI.pm b/lib/SlackBuild/URI.pm index 410a9ca..21d19f9 100644 --- a/lib/SlackBuild/URI.pm +++ b/lib/SlackBuild/URI.pm @@ -3,12 +3,13 @@ use strict; use warnings; use URI; use Carp; use LWP::UserAgent; use File::Basename; use File::Spec; +use Log::Log4perl; # use LWP::Protocol::https; # use LWP::Protocol::file; # use LWP::Protocol::ftp; our $AUTOLOAD; @@ -40,12 +41,17 @@ sub new { my $self = bless { _uri => $uri }, $class; croak "$self: unsupported scheme" unless $self->_valid_scheme; return $self; } +sub logger { + my $self = shift; + return $self->{_logger} //= Log::Log4perl::get_logger(__PACKAGE__); +} + sub clone { my $self = shift; return new SlackBuild::URI($self); } sub new_abs { @@ -59,15 +65,15 @@ use overload '""' => sub { shift->as_string }; sub download { my $self = shift; my $dst = shift || basename($self->path); my $scheme = $self->scheme; require "LWP/Protocol/$scheme.pm"; - print "downloading $self\n"; + $self->logger->info("downloading $self"); my $ua = LWP::UserAgent->new(); - $ua->agent('Slackbuilder/0.90'); + $ua->agent('Slackbuilder/$SlackBuilder::VERSION'); my $response = $ua->get($self->as_string, ':content_file' => $dst); $self->download_response($response); return $response->is_success; } sub download_response { @@ -76,17 +82,12 @@ sub download_response { if (my $v = shift) { $self->{_response} = $v; } return $self->{_response}; } -sub download_success { - my $self = shift; - return $self->download_response->is_success; -} - sub download_status { my $self = shift; return $self->download_response->status_line; } sub downloaded_html { diff --git a/lib/SlackBuilder.pm b/lib/SlackBuilder.pm index 2544b5f..924a847 100644 --- a/lib/SlackBuilder.pm +++ b/lib/SlackBuilder.pm @@ -10,12 +10,14 @@ use SlackBuild::Rc; use File::Spec; use File::Basename; use File::Temp qw/ tempfile tempdir /; use File::Copy; use POSIX::Run::Capture qw(:all); use POSIX qw(:sys_wait_h strerror uname); +use Log::Log4perl qw(:levels); +use Carp; use constant { E_OK => 0, E_SYNTAX => 1, E_EXEC => 2, E_BADBUILD => 3, @@ -32,21 +34,50 @@ our @EXPORT = qw(E_OK sub new { my ($class, %args) = @_; my $self = bless {}, $class; $self->{conf} = new SlackBuild::Config( filename => $ENV{SLACKBUILDER_CONFIG} || '/etc/slackbuilder.conf'); + + Log::Log4perl::Layout::PatternLayout::add_global_cspec('N', + sub { + my ($layout, $message, $category, $priority, $caller_level) = @_; + my $pfx = "$0: $priority"; + if ($priority eq 'DEBUG') { + $pfx .= ": $category"; + if ($self->conf->tree->Core->Verbose->value > 1) { + my $caller_offset = Log::Log4perl::caller_depth_offset($caller_level); + my ($package,$filename,$line) = caller($caller_offset); + $pfx .= ": $filename:$line"; + } + } + return $pfx; + }); + $self->logger->level($INFO); + my $layout = new Log::Log4perl::Layout::PatternLayout("%N: %m%n"); + my $appender = new Log::Log4perl::Appender('Log::Dispatch::Screen', + stderr => 1); + $appender->layout($layout); + $self->logger->add_appender($appender); my $v; - if ($v = delete $args{image}) { - $self->conf->set(qw(core image), $v); + if (defined($v = $self->conf->tree->Core->Logging->value) && -f $v) { + Log::Log4perl::init($v); } + if ($v = delete $args{verbose}) { $self->conf->set(qw(core verbose), $v); } + if ($self->conf->tree->Core->Verbose->value) { + $self->logger->level($DEBUG); + } - croak "bad number of arguments" if keys(%args); + if ($v = delete $args{image}) { + $self->conf->set(qw(core image), $v); + } + +# croak "bad number of arguments" if keys(%args); $self->clear; return $self; } @@ -59,27 +90,23 @@ sub logdir { shift->conf->tree->Dir->Log->value }; sub pkgdir { shift->conf->tree->Dir->Pkg->value }; sub ospkgdir { my $self = shift; File::Spec->catfile($self->pkgdir, $self->osversion, @_); } sub image { shift->conf->tree->Core->Image->value }; -sub verbose { shift->conf->tree->Core->Verbose->value }; sub arch { shift->{_arch} }; +sub logger { shift->{_logger} //= Log::Log4perl::get_logger('SlackBuild') } + sub error { my ($self, $diag) = @_; - push @{$self->{_error}}, $diag; + $self->logger->error($diag); } -sub errors { - my $self = shift; - if (wantarray) { - ( @{$self->{_error}} ); - } else { - @{$self->{_error}}; - } +sub errors { # FIXME + shift->{_error_count}; } sub errno { my $self = shift; croak "bad number of arguments" if @_ > 1; if (my $v = shift) { @@ -92,13 +119,13 @@ sub is_success { shift->errno == E_OK; } sub clear { my $self = shift; $self->{_errno} = E_OK; - $self->{_error} = []; + $self->{_error_count} = 0; delete $self->{_request}; delete $self->{_result}; } sub request { my $self = shift; @@ -315,13 +342,137 @@ sub _prepare { my $reg = new SlackBuild::Registry('FS', dir => $self->ospkgdir); my $filename = File::Spec->catfile($self->wd, 'rc'); return unless SlackBuild::Rc->new($self)->write($reg, $filename); return 'rc'; } - + +# Regex created using the following command: +# (find / -type d -not -name '/' -mindepth 1 -maxdepth 1 -printf '%f\n'; +# echo '.'; +# echo 'install') | xargs regexp-opt --pcre +my $file_name_rx = q{(?:b(?:in|oot)|dev|etc|home|install|l(?:ib(?:64)?|ost\+found)|m(?:edia|nt)|opt|proc|r(?:oot|un)|s(?:bin|rv|ys)|tmp|(?:us|va)r|\.)(?:/\w+)*}; + +# Parser states: +use constant { + ST_INIT => 0, # Initial state + # [expect OUT] "Creating Slackware package: foobar" + # goto ST_CREATING + ST_CREATING => 1, # [expect OUT] Empty line + # goto ST_LISTING + # [else] goto ST_INIT + ST_LISTING => 2, # [expect ERR] File name (matching $file_name_rx) + # remain in this state + # [else] goto ST_INIT + # [expect OUT] Empty line + # goto ST_CREATED + # [else] goto ST_INIT + ST_CREATED => 3 # [expect OUT] "Slackware package foo created" + # goto ST_INIT +}; + +# state([$newstate]) +# With argument - switch to that state. +# Return current state. +sub state { + my ($self, $newstate) = @_; + if (defined($newstate)) { + $self->logger->debug("going to $newstate"); + $self->{_state} = $newstate; + } + return $self->{_state}; +} + +# Parsers for each particular state. +# Each parser is named by the corresponding state, converted to lower case, +# prefixed with underscore and suffixed by the channel name ('_err' or '_out'). +# Argument is the line of text obtained from that channel, without trailing +# linefeed character. + +sub _st_init_out { + my ($self, $input) = @_; + if ($input =~ m{^Creating Slackware package:}) { + $self->logger->info($input); + $self->state(ST_CREATING); + } +} + +sub _st_default_err { + my ($self, $input) = @_; + $self->logger->error($input); +} + +sub _st_created_out { + my ($self, $input) = @_; + if ($input =~ m{^Slackware package /tmp/(.+?) created}) { + $self->file($1); + $self->logger->info($input); + } else { + $self->logger->error("unexpected output: $input"); + } + $self->state(ST_INIT); +} + +sub _st_creating_out { + my ($self, $input) = @_; + if ($input eq '') { + $self->state(ST_LISTING); + } else { + $self->state(ST_INIT); + } +} + +sub _st_listing_err { + my ($self, $input) = @_; + if ($input =~ m{$file_name_rx}) { + $self->logger->debug("adding file $input"); + } else { + $self->logger->error($input); + $self->state(ST_INIT); + } +} + +sub _st_listing_out { + my ($self, $input) = @_; + if ($input eq '') { + $self->state(ST_CREATED); + } else { + $self->state(ST_INIT); + } +} + +# Parser tables bring together parsers for each channel: + +my @parser_out = ( + \&_st_init_out, + \&_st_creating_out, + \&_st_listing_out, + \&_st_created_out +); + +my @parser_err = ( + \&_st_default_err, + \&_st_default_err, + \&_st_listing_err, + \&_st_default_err +); + +# Finally, parser functions to be called for each channel: + +sub parser_out { + my ($self, $line) = @_; + $self->logger->debug("OUT: $line"); + $self->${\$parser_out[$self->state]}($line); +} + +sub parser_err { + my ($self, $line) = @_; + $self->logger->debug("ERR: $line"); + $self->${\$parser_err[$self->state]}($line); +} + sub _build { my $self = shift; my $contname = $self->package_name . '_slackbuild'; my $rcfile = $self->_prepare or return $self->errno(E_FAIL); my @args = ( 'docker', @@ -334,54 +485,50 @@ sub _build { '-v', $self->ospkgdir . ':/var/pkg:ro', $self->image, '/bin/sh', $rcfile, $self->slackbuild_name); - printf("building %s on %s version %s (%s)\n", - $self->package_name, - $self->os_release('NAME'), - $self->os_release('VERSION'), - $self->arch); + $self->logger->info( + sprintf("building %s on %s version %s (%s)\n", + $self->package_name, + $self->os_release('NAME'), + $self->os_release('VERSION'), + $self->arch)); open(my $logfd, '>', $self->_logfilename) or do { - $self->error("can't create log file " . - $self->_logfilename . - ": $!"); + $self->logger->fatal("can't create log file " . + $self->_logfilename . + ": $!"); return $self->errno(E_FAIL); }; - - my $obj = new POSIX::Run::Capture(argv => \@args, - stdout => sub { - print $logfd 'OUT: ' . shift - }, - stderr => sub { - my $line = shift; - chomp($line); - $self->error($line); - if ($self->verbose) { - print STDERR "$line\n"; - } - print $logfd "ERR: $line\n"; - }); + + $self->state(ST_INIT); + my $obj = new POSIX::Run::Capture( + argv => \@args, + stdout => sub { + my $line = shift; + print $logfd "OUT: $line"; + chomp($line); + $self->parser_out($line); + }, + stderr => sub { + my $line = shift; + print $logfd "ERR: $line"; + chomp($line); + $self->parser_err($line); + }); + if ($self->state != ST_INIT) { + $self->logger->error("parser left in inconsistent state"); + } $self->{_result}{docker} = $obj; if ($obj->run) { $self->_runcap_diag($obj); } else { - $self->error("can't run docker: ".strerror($obj->errno)); + $self->logger->fatal("can't run docker: ".strerror($obj->errno)); return $self->errno(E_EXEC); } -# $self->errno(E_FAIL) if $self->errors; - - $obj->rewind(SD_STDOUT); - while (my $s = $obj->next_line(SD_STDOUT)) { - chomp($s); - if ($s =~ m{^Slackware package /tmp/(.+?) created}) { - $self->file($1); - } - } return $self->errno(E_OK); } - 1; diff --git a/slackbuilder b/slackbuilder index 9ad2722..36f7bdb 100755 --- a/slackbuilder +++ b/slackbuilder @@ -24,20 +24,12 @@ my $progdescr = "Slackware package builder"; sub abend { my $code = shift; print STDERR "$progname: " if defined($progname); print STDERR "@_\n"; exit $code; } - -sub error { - my $msg = shift; - local %_ = @_; - print STDERR "$progname: " if defined($progname); - print STDERR "$_{prefix}: " if defined($_{prefix}); - print STDERR "$msg\n" -} my %sbargs; GetOptions("h" => sub { pod2usage(-message => "$progname: $progdescr", -exitstatus => EX_OK); }, @@ -72,10 +64,7 @@ if ($builder->is_success) { print "OK. File list:\n"; foreach my $f ($builder->output_files) { print "$f\n"; } } else { print STDERR "ERROR: " . $builder->errno . "\n"; - foreach my $e ($builder->errors) { - print STDERR "$e\n"; - } } |