[3] | 1 | # $Id$ |
---|
| 2 | |
---|
| 3 | package ObsData; |
---|
| 4 | |
---|
| 5 | use strict; |
---|
| 6 | use warnings; |
---|
[21] | 7 | use Config::IniFiles; |
---|
[44] | 8 | use POSIX qw(strftime); |
---|
[48] | 9 | use ObsData::Repository; |
---|
[211] | 10 | use Mail::Sendmail; |
---|
| 11 | use MIME::QuotedPrint; |
---|
[218] | 12 | use File::Basename; |
---|
[3] | 13 | |
---|
[274] | 14 | my @loglevel = ( 'DEBUG', 'INFO', 'RESULT', 'WARNING', 'ERROR', 'FATAL', ); |
---|
[43] | 15 | |
---|
[289] | 16 | our $VERSION = "0.3.3"; |
---|
[274] | 17 | our $CVSID = q$Id$; |
---|
| 18 | our $CVSREV = ( q$Revision$ =~ /^Revision: (.*) $/ )[0]; |
---|
[3] | 19 | |
---|
[25] | 20 | =head1 NAME |
---|
| 21 | |
---|
| 22 | ObsData - Main object to manage data files |
---|
| 23 | |
---|
| 24 | =head1 SYNOPSIS |
---|
| 25 | |
---|
| 26 | use ObsData; |
---|
| 27 | my $conf = "configfile"; |
---|
| 28 | my $obsdata = ObsData->new($conf); |
---|
| 29 | |
---|
| 30 | =head1 METHODS |
---|
| 31 | |
---|
| 32 | =head2 new($configfile) |
---|
| 33 | |
---|
| 34 | Create a new Obsdata object from $configfile |
---|
| 35 | |
---|
| 36 | =cut |
---|
| 37 | |
---|
[21] | 38 | sub new { |
---|
[274] | 39 | my ( $class, $configfile, %options ) = @_; |
---|
[30] | 40 | my $obsdata = { |
---|
| 41 | config => new Config::IniFiles( |
---|
[274] | 42 | -file => $configfile, |
---|
| 43 | -default => 'global', |
---|
[30] | 44 | -allowcontinue => 1 |
---|
| 45 | ), |
---|
[274] | 46 | verbose => defined( $options{verbose} ) ? $options{verbose} : 1, |
---|
| 47 | logcallback => $options{logcallback}, |
---|
| 48 | logfile => $options{logfile}, |
---|
| 49 | dry_run => $options{dry_run}, |
---|
[174] | 50 | interactive_callback => $options{interactive_callback}, |
---|
[274] | 51 | processed_lists => [], |
---|
[30] | 52 | }; |
---|
[43] | 53 | |
---|
[274] | 54 | if ( !( $configfile && -f $configfile && -r _ ) ) { |
---|
[100] | 55 | return undef; |
---|
[29] | 56 | } |
---|
| 57 | |
---|
[30] | 58 | $obsdata->{config} or return undef; |
---|
| 59 | |
---|
[218] | 60 | # directory where to search plugins |
---|
[274] | 61 | @{ $obsdata->{plugindir} } = grep { $_ && -d $_ } ( |
---|
[218] | 62 | $options{plugindir}, |
---|
| 63 | dirname($0), |
---|
[274] | 64 | split( /\s+/, $obsdata->{config}->val( 'global', 'plugindir' ) || '' ), |
---|
[218] | 65 | ); |
---|
[229] | 66 | |
---|
[274] | 67 | $obsdata->{logfile} ||= $obsdata->{config}->val( 'global', 'logfile' ) |
---|
| 68 | || 'obsdata.log'; |
---|
[189] | 69 | |
---|
[274] | 70 | bless( $obsdata, $class ); |
---|
[21] | 71 | } |
---|
| 72 | |
---|
[43] | 73 | sub DESTROY { |
---|
| 74 | my ($self) = @_; |
---|
| 75 | |
---|
[274] | 76 | $self->logging( 0, "END process: %s (%s)", $VERSION, $CVSID, ); |
---|
[238] | 77 | |
---|
[274] | 78 | if ( $self->{loghandle} ) { |
---|
| 79 | close( $self->{loghandle} ); |
---|
[43] | 80 | $self->{loghandle} = undef; |
---|
| 81 | } |
---|
| 82 | } |
---|
| 83 | |
---|
[103] | 84 | =head2 load |
---|
| 85 | |
---|
| 86 | Prepare the object for usage |
---|
| 87 | |
---|
| 88 | =cut |
---|
| 89 | |
---|
[43] | 90 | sub load { |
---|
| 91 | my ($self) = @_; |
---|
| 92 | |
---|
[274] | 93 | if ( !open( $self->{loghandle}, ">> $self->{logfile}" ) ) { |
---|
[46] | 94 | $self->{loghandle} = undef; |
---|
[274] | 95 | $self->logging( 5, "Can't open log file %s, exiting", |
---|
| 96 | "$self->{logfile}" ); |
---|
[43] | 97 | return 0; |
---|
| 98 | } |
---|
[238] | 99 | |
---|
[274] | 100 | $self->logging( 0, "BEGIN process: %s (%s)", $VERSION, $CVSID, ); |
---|
[245] | 101 | |
---|
| 102 | my $path = `pwd`; |
---|
| 103 | chomp($path); |
---|
[274] | 104 | $self->logging( |
---|
| 105 | 0, |
---|
| 106 | "Using config file `%s' (%s)", |
---|
| 107 | $self->{config}->GetFileName(), $path, |
---|
[245] | 108 | ); |
---|
[274] | 109 | |
---|
[237] | 110 | $self->load_plugins() or return 0; |
---|
[274] | 111 | |
---|
[43] | 112 | return 1; |
---|
| 113 | } |
---|
| 114 | |
---|
[219] | 115 | =head2 load_plugins |
---|
| 116 | |
---|
| 117 | Load plugins files and get code reference. |
---|
| 118 | |
---|
| 119 | =cut |
---|
| 120 | |
---|
[218] | 121 | sub load_plugins { |
---|
| 122 | my ($self) = @_; |
---|
[274] | 123 | |
---|
| 124 | $self->logging( |
---|
| 125 | 0, |
---|
[229] | 126 | "Plugin will be searched in: %s", |
---|
[274] | 127 | join( ', ', @{ $self->{plugindir} } ), |
---|
[229] | 128 | ); |
---|
[274] | 129 | |
---|
| 130 | foreach my $datatype ( $self->list_datatype() ) { |
---|
[218] | 131 | foreach my $plugin (qw/match_plugin/) { |
---|
[274] | 132 | my ( $plugfile, @plugarg ) = |
---|
| 133 | split( /\s+/, $self->getvalue( $datatype, $plugin ) || '' ); |
---|
| 134 | $plugfile or next; # if no plugin, skipping |
---|
[218] | 135 | my ($plugfilename) = grep { -f $_ } |
---|
[274] | 136 | map { "$_/$plugfile" } @{ $self->{plugindir} }; |
---|
| 137 | if ( !$plugfilename ) { |
---|
| 138 | $self->logging( 5, "Cannot find plugin %s (%s) for %s datatype", |
---|
| 139 | $plugfile, $plugin, $datatype, ); |
---|
[237] | 140 | return 0; |
---|
[218] | 141 | } |
---|
| 142 | my $sub = do $plugfilename; |
---|
[237] | 143 | if ($@) { |
---|
[274] | 144 | $self->logging( 4, |
---|
[237] | 145 | "Cannot load plugin %s for %s: %s, exiting !", |
---|
[274] | 146 | $plugin, $datatype, $@, ); |
---|
[237] | 147 | return 0; |
---|
| 148 | } |
---|
[274] | 149 | if ( $sub && ref $sub eq 'CODE' ) { |
---|
[227] | 150 | $self->{plugin}{$datatype}{$plugin} = { |
---|
[274] | 151 | code => $sub, |
---|
| 152 | arg => \@plugarg, |
---|
[227] | 153 | }; |
---|
[274] | 154 | $self->logging( 0, "loading plugin %s for %s (%s)", |
---|
| 155 | $plugin, $datatype, $sub, ); |
---|
| 156 | } |
---|
| 157 | else { |
---|
| 158 | $self->logging( |
---|
| 159 | 4, "Cannot load plugin %s for %s (is %s)", |
---|
| 160 | $plugin, $datatype, $sub ? ref $sub : 'undef or empty', |
---|
[218] | 161 | ); |
---|
| 162 | } |
---|
| 163 | } |
---|
| 164 | } |
---|
[237] | 165 | return 1; |
---|
[218] | 166 | } |
---|
| 167 | |
---|
[220] | 168 | =head2 get_sub_plugin |
---|
| 169 | |
---|
| 170 | Return code ref of plugintype for datatype |
---|
| 171 | |
---|
| 172 | =cut |
---|
| 173 | |
---|
| 174 | sub get_sub_plugin { |
---|
[274] | 175 | my ( $self, $datatype, $plugintype ) = @_; |
---|
| 176 | if ( exists( $self->{plugin}{$datatype}{$plugintype} ) ) { |
---|
[227] | 177 | my $ref = $self->{plugin}{$datatype}{$plugintype}; |
---|
[274] | 178 | return ( $ref->{code}, @{ $ref->{arg} } ); |
---|
| 179 | } |
---|
| 180 | else { |
---|
[220] | 181 | return undef; |
---|
| 182 | } |
---|
| 183 | } |
---|
| 184 | |
---|
[120] | 185 | =head2 logging($level, $message, ...) |
---|
[103] | 186 | |
---|
[120] | 187 | Pass a message into the logging process. |
---|
[103] | 188 | |
---|
| 189 | $level is the level of message |
---|
| 190 | $message and or other arguments are printf format string |
---|
| 191 | |
---|
| 192 | =cut |
---|
| 193 | |
---|
[120] | 194 | sub logging { |
---|
[274] | 195 | my ( $self, $level, $fmt, @val ) = @_; |
---|
| 196 | my $msg = sprintf( $fmt, @val ); |
---|
[46] | 197 | my $logh = $self->{loghandle}; |
---|
[274] | 198 | if ( $self->{logcallback} ) { |
---|
| 199 | $self->{logcallback}->( $level, $msg ); |
---|
[71] | 200 | } |
---|
[274] | 201 | if ( $level >= 0 && $level >= $self->{verbose} ) { |
---|
[46] | 202 | if ($logh) { |
---|
[274] | 203 | printf $logh "%-9s %s %s\n", |
---|
| 204 | sprintf( "[%s]", $self->loglevel($level) ), |
---|
| 205 | strftime( "%b %d %H:%M:%S %Y", gmtime ), $msg; |
---|
[46] | 206 | } |
---|
[43] | 207 | } |
---|
[274] | 208 | $msg; |
---|
[43] | 209 | } |
---|
| 210 | |
---|
[104] | 211 | =head2 loglevel($level) |
---|
| 212 | |
---|
| 213 | Return the text human readable log level associate to $level number |
---|
| 214 | |
---|
| 215 | =cut |
---|
| 216 | |
---|
[55] | 217 | sub loglevel { |
---|
| 218 | my $l = pop(@_); |
---|
| 219 | defined($l) or $l = pop(@_); |
---|
[274] | 220 | return $loglevel[$l] || "?????"; |
---|
[55] | 221 | } |
---|
| 222 | |
---|
[25] | 223 | =head2 checkconfig() |
---|
| 224 | |
---|
| 225 | Check the validity of information contains in configfile. |
---|
| 226 | |
---|
| 227 | Notice: This test does not include the syntaxe validity |
---|
| 228 | |
---|
| 229 | =cut |
---|
| 230 | |
---|
[22] | 231 | sub checkconfig { |
---|
| 232 | my ($self) = @_; |
---|
[118] | 233 | my $result = 1; |
---|
[274] | 234 | foreach my $g ( $self->{config}->GroupMembers('Obs') ) { |
---|
[22] | 235 | my ($obs) = $g =~ /\S+\s+(.*)/; |
---|
[274] | 236 | if ( !$self->{config}->SectionExists($obs) ) { |
---|
[25] | 237 | print STDERR "E: '$obs' is listed as Obs but it does not exists\n"; |
---|
[22] | 238 | next; |
---|
| 239 | } |
---|
[274] | 240 | foreach my $param ( $self->{config}->Parameters($obs) ) { |
---|
[22] | 241 | } |
---|
[274] | 242 | foreach my $datatype ( $self->list_datatype ) { |
---|
[195] | 243 | foreach my $var (qw(match match_archive)) { |
---|
[274] | 244 | my $regexp = $self->getvalue( $datatype, $var ) |
---|
| 245 | or next; # next ? are we sure ? |
---|
| 246 | eval { qr/$regexp/ }; # Many thanks Rafael |
---|
[195] | 247 | if ($@) { |
---|
[274] | 248 | $self->logging( 4, "error in regexp for %s: '%s': %s", |
---|
| 249 | $datatype, $regexp, $@, ); |
---|
[195] | 250 | $result = 0; |
---|
[274] | 251 | |
---|
[195] | 252 | # TODO set this reg unavalable |
---|
| 253 | } |
---|
[117] | 254 | } |
---|
| 255 | } |
---|
[22] | 256 | } |
---|
[274] | 257 | return ($result); |
---|
[22] | 258 | } |
---|
| 259 | |
---|
[25] | 260 | =head2 getvalue($section, $var, $default) |
---|
| 261 | |
---|
| 262 | Return a value from the configuration, $default is assumed if the value is not set |
---|
| 263 | |
---|
| 264 | =cut |
---|
| 265 | |
---|
[22] | 266 | sub getvalue { |
---|
[274] | 267 | my ( $self, $section, $var, $default ) = @_; |
---|
| 268 | $self->{config}->val( $section, $var, $default ); |
---|
[22] | 269 | } |
---|
| 270 | |
---|
[104] | 271 | =head2 config_mtime |
---|
| 272 | |
---|
| 273 | Return the modification time of config file currently used |
---|
| 274 | |
---|
| 275 | =cut |
---|
| 276 | |
---|
[74] | 277 | sub config_mtime { |
---|
| 278 | my ($self) = @_; |
---|
[274] | 279 | return $self->{configmtime} ||= ( stat( $self->{config}->GetFileName ) )[9]; |
---|
[74] | 280 | } |
---|
| 281 | |
---|
[25] | 282 | =head2 list_obs |
---|
| 283 | |
---|
| 284 | Return the list of observatories defined in configuration |
---|
| 285 | |
---|
| 286 | =cut |
---|
| 287 | |
---|
[22] | 288 | sub list_obs { |
---|
| 289 | my ($self) = @_; |
---|
| 290 | grep { $self->{config}->SectionExists($_) } |
---|
[274] | 291 | map { s/^\S+\s+//; $_ } $self->{config}->GroupMembers('Obs'); |
---|
[22] | 292 | } |
---|
| 293 | |
---|
[25] | 294 | =head2 is_obs($obsname) |
---|
| 295 | |
---|
| 296 | Return True if $obsname is an observatory |
---|
| 297 | |
---|
| 298 | =cut |
---|
| 299 | |
---|
[23] | 300 | sub is_obs { |
---|
[274] | 301 | my ( $self, $obs ) = @_; |
---|
| 302 | scalar( grep { $_ eq "Obs $obs" } $self->{config}->GroupMembers('Obs') ); |
---|
[23] | 303 | } |
---|
| 304 | |
---|
[25] | 305 | =head2 list_obsdatadir($obsname) |
---|
| 306 | |
---|
| 307 | Return a hash of data directories per data type for $obsname observatories |
---|
| 308 | |
---|
| 309 | =cut |
---|
| 310 | |
---|
| 311 | sub list_obsdatadir { |
---|
[274] | 312 | my ( $self, $obs ) = @_; |
---|
[23] | 313 | $self->is_obs($obs) or return undef; |
---|
[274] | 314 | map { |
---|
| 315 | m,^datadir/(.*),; |
---|
| 316 | ( ( $1 || "" ) => $self->{config}->val( $obs, $_ ) ) |
---|
| 317 | } |
---|
| 318 | grep { m,^datadir/, || $_ eq 'datadir' } |
---|
| 319 | $self->{config}->Parameters($obs); |
---|
[22] | 320 | } |
---|
| 321 | |
---|
[25] | 322 | =head2 list_typedatadir($type) |
---|
| 323 | |
---|
| 324 | List all directories for $type data |
---|
| 325 | |
---|
| 326 | =cut |
---|
| 327 | |
---|
| 328 | sub list_typedatadir { |
---|
[274] | 329 | my ( $self, $type ) = @_; |
---|
[25] | 330 | my %dirs; |
---|
[274] | 331 | foreach my $obs ( $self->list_obs ) { |
---|
| 332 | $dirs{$_} = 1 foreach ( grep { $_ } $self->get_datadir( $obs, $type ) ); |
---|
[25] | 333 | } |
---|
[274] | 334 | keys %dirs; |
---|
| 335 | |
---|
[25] | 336 | } |
---|
| 337 | |
---|
| 338 | =head2 get_datadir($obs, $type) |
---|
| 339 | |
---|
| 340 | Return a list of directories for $type data on $obs observatory |
---|
| 341 | |
---|
| 342 | =cut |
---|
| 343 | |
---|
[23] | 344 | sub get_datadir { |
---|
[274] | 345 | my ( $self, $obs, $type ) = @_; |
---|
[23] | 346 | $self->is_obs($obs) or return undef; |
---|
[274] | 347 | grep { defined($_) } ( |
---|
| 348 | $self->getvalue( $obs, "datadir/$type" ), |
---|
| 349 | $self->getvalue( $obs, "datadir" ) |
---|
| 350 | ); |
---|
[23] | 351 | } |
---|
| 352 | |
---|
[33] | 353 | =head2 list_datatype |
---|
| 354 | |
---|
| 355 | Return a list of datatype handle by config |
---|
| 356 | |
---|
| 357 | =cut |
---|
| 358 | |
---|
| 359 | sub list_datatype { |
---|
| 360 | my ($self) = @_; |
---|
| 361 | grep { $_ ne 'global' } |
---|
[274] | 362 | grep { $_ !~ /^Obs\s+/ } |
---|
| 363 | grep { !$self->is_obs($_) } $self->{config}->Sections; |
---|
[33] | 364 | } |
---|
| 365 | |
---|
[105] | 366 | =head2 get_obs_data_handle($obs, $datatype) |
---|
[96] | 367 | |
---|
[105] | 368 | Return an ObsData::Repository object about directory for $obs station |
---|
| 369 | about $datatype data. $datatype can be undefined if you want to get default |
---|
| 370 | directory |
---|
| 371 | |
---|
| 372 | =cut |
---|
| 373 | |
---|
[96] | 374 | sub get_obs_data_handle { |
---|
[274] | 375 | my ( $self, $obs, $datatype ) = @_; |
---|
[96] | 376 | |
---|
[274] | 377 | my $dir = |
---|
| 378 | $self->getvalue( $obs, ( $datatype ? "datadir/$datatype" : "datadir" ) ); |
---|
| 379 | if ( !$dir ) { |
---|
| 380 | $self->logging( 4, "Can't find data directory for %s, type: %s", |
---|
| 381 | $obs, $datatype || '(none)' ); |
---|
[96] | 382 | return undef; |
---|
| 383 | } |
---|
| 384 | my $or = ObsData::Repository::dir->new( |
---|
| 385 | { |
---|
[274] | 386 | obsdata => $self, |
---|
| 387 | dir => $dir, |
---|
| 388 | obs => $obs, |
---|
[96] | 389 | datatype => $datatype, |
---|
[141] | 390 | dry_run => $self->{dry_run}, # FIXME does this have a better place ? |
---|
[274] | 391 | patern => $self->getvalue( |
---|
| 392 | $obs, ( $datatype ? "searchfiles/$datatype" : "searchfiles" ) |
---|
[126] | 393 | ), |
---|
[123] | 394 | statusfile => $self->getvalue( |
---|
[274] | 395 | $obs, ( $datatype ? "index/$datatype" : "index" ), |
---|
[123] | 396 | "$dir/obsdata.ini" |
---|
| 397 | ), |
---|
[55] | 398 | } |
---|
[96] | 399 | ); |
---|
[274] | 400 | if ( !defined($or) ) { |
---|
| 401 | $self->logging( 4, "Can't parse %s, check directory exists", $dir ); |
---|
[96] | 402 | return undef; |
---|
[46] | 403 | } |
---|
[274] | 404 | |
---|
| 405 | return ($or); |
---|
[46] | 406 | } |
---|
| 407 | |
---|
[105] | 408 | =head2 process_obs($obs) |
---|
| 409 | |
---|
| 410 | Process all data handle by $obs station |
---|
| 411 | |
---|
| 412 | =cut |
---|
| 413 | |
---|
| 414 | sub process_obs { |
---|
[274] | 415 | my ( $self, $obs ) = @_; |
---|
[105] | 416 | my %datadir = $self->list_obsdatadir($obs); |
---|
[274] | 417 | $self->logging( 0, "Starting %s() for %s", ( caller(0) )[3], $obs ); |
---|
| 418 | |
---|
| 419 | foreach my $datatype ( keys %datadir ) { |
---|
| 420 | my $or = $self->get_obs_data_handle( $obs, $datatype ); |
---|
[105] | 421 | $or or next; |
---|
| 422 | $or->process; |
---|
| 423 | } |
---|
| 424 | } |
---|
| 425 | |
---|
[208] | 426 | sub processed { |
---|
[274] | 427 | my ( $self, $obs, $archive, $datafile, $datatype, $dest ) = @_; |
---|
| 428 | push( |
---|
| 429 | @{ $self->{processed_lists} }, |
---|
[208] | 430 | { |
---|
[274] | 431 | obs => $obs, |
---|
| 432 | archive => $archive, |
---|
[209] | 433 | datafile => $datafile, |
---|
[208] | 434 | datatype => $datatype, |
---|
| 435 | destfile => $dest, |
---|
| 436 | } |
---|
| 437 | ); |
---|
[274] | 438 | $self->logging( 2, "Extraction of %s/%s done as %s", |
---|
| 439 | $archive, $datafile, $dest, ) |
---|
| 440 | if ($dest); |
---|
[208] | 441 | } |
---|
| 442 | |
---|
[211] | 443 | sub generated_reported { |
---|
| 444 | my ($self) = @_; |
---|
| 445 | my $result = { |
---|
[274] | 446 | all => [], |
---|
[211] | 447 | users => {}, |
---|
| 448 | }; |
---|
| 449 | |
---|
[274] | 450 | foreach my $entry ( @{ $self->{processed_lists} } ) { |
---|
[268] | 451 | my %people = map { $_ => 1 } grep { $_ } ( |
---|
[274] | 452 | ( |
---|
| 453 | $entry->{datatype} |
---|
| 454 | ? split( /\s*,\s*/, |
---|
| 455 | $self->getvalue( $entry->{datatype}, 'reportto' ) || "" ) |
---|
| 456 | : split( |
---|
| 457 | /\s*,\s*/, |
---|
| 458 | $self->getvalue( 'global', 'nodestreportto' ) || "" |
---|
| 459 | ) |
---|
[272] | 460 | ), |
---|
[274] | 461 | split( |
---|
| 462 | /\s*,\s*/, $self->getvalue( $entry->{obs}, 'reportto' ) || "" |
---|
| 463 | ), |
---|
| 464 | split( |
---|
| 465 | /\s*,\s*/, $self->getvalue( 'global', 'allreportto' ) || "" |
---|
| 466 | ) |
---|
[268] | 467 | ); |
---|
| 468 | keys %people or next; |
---|
[274] | 469 | foreach my $p ( keys %people ) { |
---|
| 470 | push( @{ $result->{users}{$p} }, $entry ); |
---|
[211] | 471 | } |
---|
| 472 | } |
---|
| 473 | |
---|
[274] | 474 | foreach my $p ( keys( %{ $result->{users} || {} } ) ) { |
---|
[253] | 475 | my %obs_entries = (); |
---|
[274] | 476 | foreach ( @{ $result->{users}{$p} } ) { |
---|
| 477 | push( @{ $obs_entries{ $_->{obs} } }, $_ ); |
---|
[253] | 478 | } |
---|
| 479 | |
---|
[274] | 480 | foreach my $obs ( keys %obs_entries ) { |
---|
[253] | 481 | my %datatype_entries = (); |
---|
[274] | 482 | foreach ( @{ $obs_entries{$obs} } ) { |
---|
| 483 | push( @{ $datatype_entries{ $_->{datatype} || '!' } }, $_ ); |
---|
[211] | 484 | } |
---|
[253] | 485 | |
---|
| 486 | my %msg = ( |
---|
[278] | 487 | Subject => 'ObsData Report: ' |
---|
| 488 | . $self->getvalue( $obs, 'description', $obs ), |
---|
[274] | 489 | To => $p, |
---|
[253] | 490 | 'X-ObsData-Version' => $VERSION, |
---|
[279] | 491 | 'X-ObsData-Obs' => $obs, |
---|
| 492 | 'Content-Type' => "TEXT/PLAIN;\n charset=ISO-8859-15", |
---|
[253] | 493 | 'Content-Transfer-Encoding' => 'QUOTED-PRINTABLE', |
---|
[279] | 494 | From => $self->getvalue( |
---|
| 495 | 'global', 'reportfrom', |
---|
| 496 | 'ObsData <robot@aero.jussieu.fr>' |
---|
| 497 | ), |
---|
[253] | 498 | ); |
---|
| 499 | my $message = ""; |
---|
[274] | 500 | foreach my $d ( sort keys(%datatype_entries) ) { |
---|
| 501 | if ( $d eq '!' ) { |
---|
[272] | 502 | $message .= "\nNot proceed:\n"; |
---|
[274] | 503 | foreach ( @{ $datatype_entries{$d} || [] } ) { |
---|
| 504 | $message .= sprintf( " file %s from %s\n", |
---|
| 505 | $_->{datafile}, $_->{archive}, ); |
---|
[272] | 506 | } |
---|
[274] | 507 | } |
---|
| 508 | else { |
---|
[272] | 509 | $message .= "\nDataType: $d\n"; |
---|
[274] | 510 | foreach ( @{ $datatype_entries{$d} || [] } ) { |
---|
| 511 | $message .= sprintf( " file %s from %s => %s\n", |
---|
| 512 | $_->{datafile}, $_->{archive}, $_->{destfile}, ); |
---|
[272] | 513 | } |
---|
[253] | 514 | } |
---|
| 515 | } |
---|
[292] | 516 | $message .= |
---|
| 517 | sprintf( |
---|
| 518 | "\n-- \nMail automatically generated by:\nObsdata Robot %s (SVN: %s)\n", |
---|
| 519 | $VERSION, $CVSREV, ); |
---|
[282] | 520 | if ( |
---|
| 521 | sendmail( |
---|
| 522 | %msg, |
---|
| 523 | smtp => 'mailhost', |
---|
| 524 | Message => encode_qp($message), |
---|
| 525 | ) |
---|
[274] | 526 | ) |
---|
[282] | 527 | { |
---|
[290] | 528 | $self->logging( |
---|
[282] | 529 | 1, |
---|
| 530 | "Mail sent to %s for %s (%d files done)", |
---|
| 531 | $p, $obs, |
---|
| 532 | scalar( |
---|
| 533 | map { @{ $datatype_entries{$_} || [] } } |
---|
| 534 | keys(%datatype_entries) |
---|
| 535 | ), |
---|
| 536 | ); |
---|
| 537 | } |
---|
| 538 | else { |
---|
[290] | 539 | $self->logging( |
---|
[282] | 540 | 4, "Cannot send mail to %s: %s", |
---|
| 541 | $msg{To}, $Mail::Sendmail::error, |
---|
| 542 | ); |
---|
| 543 | } |
---|
[211] | 544 | } |
---|
[282] | 545 | return $result; |
---|
[211] | 546 | } |
---|
| 547 | } |
---|
| 548 | |
---|
[214] | 549 | sub postprocessed { |
---|
| 550 | my ($self) = @_; |
---|
| 551 | my %datastype; |
---|
[274] | 552 | foreach my $entry ( @{ $self->{processed_lists} } ) { |
---|
[272] | 553 | $entry->{datatype} or next; |
---|
[274] | 554 | push( @{ $datastype{ $entry->{datatype} } }, $entry ); |
---|
[214] | 555 | } |
---|
| 556 | |
---|
[274] | 557 | foreach my $datatype ( keys %datastype ) { |
---|
| 558 | my $command = $self->getvalue( $datatype, 'postexec' ); |
---|
| 559 | $self->logging( |
---|
| 560 | 0, 'postexec for %s is %s', |
---|
| 561 | $datatype, $command ? "`$command'" : 'not set, skipping', |
---|
[214] | 562 | ); |
---|
| 563 | if ($command) { |
---|
[274] | 564 | if ( open( my $posthandle, "| $command" ) ) { |
---|
| 565 | foreach ( @{ $datastype{$datatype} } ) { |
---|
[214] | 566 | print $posthandle "$_->{destfile}\n" or do { |
---|
[274] | 567 | $self->logging( 4, |
---|
| 568 | "cannot write to postexec handle for `%s': %s", |
---|
| 569 | $datatype, $!, ); |
---|
[214] | 570 | last; |
---|
| 571 | }; |
---|
| 572 | } |
---|
| 573 | my $exitstatus = close($posthandle); |
---|
[274] | 574 | $self->logging( |
---|
| 575 | $exitstatus ? 0 : 4, |
---|
[214] | 576 | "postexec for %s exit %s", |
---|
| 577 | $datatype, |
---|
[274] | 578 | $exitstatus |
---|
| 579 | ? "correctly" |
---|
| 580 | : "with failure : " . ( $! ? ($!) : "(??)" ), |
---|
[214] | 581 | ); |
---|
[274] | 582 | } |
---|
| 583 | else { |
---|
| 584 | $self->logging( 4, "Cannot exec post `%s' for `%s'", |
---|
| 585 | $command, $datatype, ); |
---|
[214] | 586 | next; |
---|
| 587 | } |
---|
| 588 | } |
---|
| 589 | } |
---|
| 590 | } |
---|
| 591 | |
---|
[21] | 592 | 1; |
---|
[105] | 593 | |
---|
[216] | 594 | =head1 LICENSE |
---|
| 595 | |
---|
| 596 | This software is under GPL version 2 or highter |
---|
| 597 | (c) 2005, 2006 CNRS Service d'Aeronomie |
---|
| 598 | |
---|
[105] | 599 | =head1 AUTHOR |
---|
| 600 | |
---|
| 601 | Olivier Thauvin <olivier.thauvin@aerov.jussieu.fr> |
---|
| 602 | |
---|
| 603 | =cut |
---|
[274] | 604 | |
---|