source: trunk/soft/ObsData/ObsData/Repository.pm @ 182

Last change on this file since 182 was 182, checked in by thauvin, 18 years ago
  • remove complex code, no longer in use
  • Property cvs2svn:cvs-rev set to 1.63
  • Property svn:keywords set to Author Date Id Revision
File size: 13.2 KB
Line 
1# $Id$
2
3package ObsData::Repository;
4
5use strict;
6use warnings;
7use File::Path;
8use POSIX qw(getcwd);
9use ObsData;
10use ObsData::Archive;
11use ObsData::Event;
12use Config::IniFiles;
13
14our $CVSID = q$Id$;
15our $CVSREV = (q$Revision$ =~ /^Revision: (.*) $/)[0];
16
17=head1 METHODS
18
19=head2 ObsData::Repository
20
21=head3 new($parent, %param)
22
23Create a new ObsData::Repository object
24
25=over 4
26
27=item $parent
28
29A ObsData::Repository to take information
30
31=item %param
32
33A list of paramter to set in new object:
34
35=over 4
36
37=item datatype
38
39If set, only this datatype will be checked
40
41=item obs
42
43The obsveratory where data come from, informationnal only
44
45=item dir
46
47The based directory where archive are located
48
49=item glob
50
51Apply this glob to search files in dir
52
53=item statusfile
54
55The file where status info should be written
56
57=item status
58
59The Config::IniFiles object
60
61=back
62
63=back
64
65=cut
66
67sub new {
68    my ($class, $parent, %param) = @_;
69
70    my $or = { %$parent };
71    foreach (keys %param) {
72        $or->{$_} = $param{$_};
73    }
74   
75    $or->{obsdata} or die "Error #1de8d015, please insult programmer";
76    $or->{dir} or die "No dir given";
77    -d $or->{dir} or return undef;
78   
79    $or->{status} ||= new Config::IniFiles(
80        -file => (($or->{statusfile} && -f $or->{statusfile}) ? $or->{statusfile} : undef),
81        # -default => '.', # Is this a good idea
82    );
83    $or->{statusfile} ||= $or->{status}->GetFileName;
84    $or->{interactive_callback} ||= $or->{obsdata}->{interactive_callback};
85
86    bless($or, $class);
87
88    $or;
89}
90
91sub DESTROY {
92    my ($self) = @_;
93    $self->logging(0, "Destroy ObsData::Repository for %s", ref($self));
94    $self->save_status;
95}
96
97=head3 update_global_status
98
99Set standard information into status ini file
100
101=cut
102
103sub update_global_status {
104    my ($self) = @_;
105    $self->{status}->AddSection('.');
106    $self->{status}->SetSectionComment('.',
107        $ObsData::CVSID,
108        $ObsData::Repository::CVSID,
109        scalar(localtime),
110    );
111
112    my $hostname = `hostname`;
113    chomp($hostname);
114    $self->{status}->newval('.', 'hostname', $hostname);
115    $self->{status}->SetParameterComment(
116        '.',
117        'hostname',
118        'The computer host name'
119    );
120
121    $self->{status}->newval('.', 'directory', $self->{dir});
122    $self->{status}->SetParameterComment(
123        '.',
124        'directory', 
125        'Directory where archive where located'
126    );
127   
128    $self->{status}->newval('.', 'runfrom', getcwd());
129    $self->{status}->SetParameterComment(
130        '.',
131        'runfrom',
132        'The current directory'
133    );
134}
135
136=head3 save_status
137
138Save current information about parsed files into status file
139
140=cut
141
142sub save_status {
143    my ($self) = @_;
144    $self->{statusfile} or return;
145    if (!$self->{dry_run}) {
146        $self->update_global_status;
147        $self->{status}->WriteConfig($self->{statusfile});
148    }
149}
150
151=head3 dump_status($output)
152
153Dump current status file into $output, see Config::IniFiles,
154function WriteConfig
155
156=cut
157
158sub dump_status {
159    my ($self, $output) = @_;
160    $self->update_global_status;
161    $self->{status}->WriteConfig($output);
162}
163
164=head3 logging($level, $msg, ...)
165
166Pass a message for logging to ObsData Object. See L<ObsData>
167
168=cut
169
170sub logging {
171    my $self = shift;
172    $self->{obsdata}->logging(@_);
173}
174
175=head2 ObsData::Repository::dir
176
177The child class to handle directory
178
179=cut
180
181package ObsData::Repository::dir;
182
183our @ISA = qw(ObsData::Repository);
184
185=head3 new
186
187=cut
188
189sub new {
190    my ($class, $infos, %param) = @_;
191
192    my $or = ObsData::Repository->new($infos, %param) or return;
193
194    bless($or, $class);
195}
196
197=head3 findfile
198
199Return the list of files needing to be checked
200
201=cut
202
203sub findfile {
204    my ($self) = @_;
205    my @files;
206
207    if (!-d $self->{dir}) {
208        $self->logging(3,
209            "directory %s does not exists",
210            $self->{dir},
211        );
212        return;
213    }
214
215    my $patern = $self->{patern} || '*';
216    foreach my $f (glob("$self->{dir}/$patern")) {
217
218        -f $f or next; # skip no regular files
219        $f =~ m/obsdata\.ini$/ and next; # avoid default status file
220       
221        my $bf = $f;
222        $bf =~ s!^\Q$self->{dir}\E/*!!;
223        push(@files, $bf);
224    }
225    @files
226}
227
228=head3 process
229
230Process all files in directory
231
232=cut
233
234sub process {
235    my ($self) = @_;
236    $self->logging(0, "%s() start for %s", (caller(0))[3], $self->{dir});
237
238    foreach my $file ($self->findfile) {
239        my $orda = ObsData::Repository::dir::archive->new(
240            $self,
241            archivefile => $file,
242        );
243
244        my $oe = ObsData::Event->new('do_archive', "Should I parse $file");
245        if (defined(my $oldsize = $orda->getvalue('size'))) {
246            my $size = (stat("$orda->{dir}/$orda->{archivefile}"))[7];
247           
248            $oe->add_test('archive_size',
249                ($size <=> $oldsize) == 0 ?
250                (sprintf("does not differ (%d)", $size), 1) :
251                (sprintf("differ %d => %d", $oldsize, $size), 0)
252            );
253        }
254
255        if (defined(my $oldmtime = $orda->getvalue('mtime'))) {
256            my $mtime = (stat("$orda->{dir}/$orda->{archivefile}"))[9];
257            $oe->add_test('archive_mtime',
258                ($mtime <=> $oldmtime) == 0 ?
259                (sprintf("does not differ (%d)", $mtime), 1) :
260                (sprintf("differ %d => %d", $oldmtime, $mtime), 0)
261            );
262        }
263       
264        $oe->add_test('archive_exists',
265            $self->{status}->SectionExists($orda->{archivefile}) ?
266            ("Archive file found in index", 1) :
267            ("Archive file not found in index", 0)
268        );
269       
270        $orda->ask_user($oe) or next;
271       
272        $orda->process;
273    }
274}
275
276=head2 ObsData::Repository::dir::archive
277
278Object to handle archive and to dispatch data
279
280=cut
281
282package ObsData::Repository::dir::archive;
283
284our @ISA = qw(ObsData::Repository);
285
286=head3 new
287
288=cut
289
290sub new {
291    my ($class, $infos, %param) = @_;
292
293    my $or = ObsData::Repository->new($infos, %param) or return;
294    # dir directory to parse
295    $or->{archivefile} or die "No archivefile given";
296
297    # $or->{interactive_callback}
298    $or->{_cache_checks} = {};
299   
300    $or->logging(0,
301        "Preparing to parse %s/%s",
302         $or->{dir},
303         $or->{archivefile}
304    );
305
306    bless($or, $class);
307}
308
309=head3 load_archive
310
311Try to read archive, return 1 on success
312
313=cut
314
315sub load_archive {
316    my ($self) = @_;
317    if ($self->{Oarchive}) {
318        return 1;
319    } else {
320        $self->{Oarchive} = ObsData::Archive->new("$self->{dir}/$self->{archivefile}");
321        if ($self->{Oarchive}) {
322            $self->logging(0,
323                "Archive %s/%s properly load",
324                $self->{dir}, $self->{archivefile}
325            );
326            return 1;
327        } else {
328            $self->logging(4, 
329                "Can't handle archive %s/%s: %s, skipping",
330                $self->{dir}, $self->{archivefile},
331                ObsData::Archive->error
332            );
333            return 0;
334        }
335    }
336}
337
338=head2 getvalue
339
340=cut
341
342sub getvalue {
343    my ($self, $var, $default) = @_;
344    return $self->{status}->val($self->{archivefile}, $var, $default);
345}
346
347=head2 setvalue
348
349=cut
350
351sub setvalue {
352    my ($self, $var, $val, $comment) = @_;
353    if (!$self->{status}->SectionExists($self->{archivefile})) {
354        $self->{status}->AddSection($self->{archivefile});
355    }
356    $self->{status}->newval($self->{archivefile}, $var, $val) if(defined($val));
357    $self->{status}->SetParameterComment(
358        $self->{archivefile}, $var, $comment
359    ) if(defined($comment));
360}
361
362=head2 get_data_value
363
364=cut
365
366sub get_data_value {
367    my ($self, $datafile, $var, $default) = @_;
368    return $self->getvalue(
369        sprintf('data_%s_%s', $var, $datafile),
370        $var, 
371        $default
372    );
373}
374
375=head2 set_data_value
376
377=cut
378
379sub set_data_value {
380    my ($self, $datafile, $var, $val, $comment) = @_;
381    $self->setvalue(
382        sprintf('data_%s_%s', $var, $datafile),
383        $val,
384        $comment
385    );
386}
387
388=head3 checks
389
390=cut
391
392#sub DESTROY {
393#    my ($self) = @_;
394#    $self->logging(0, "Destroy ObsData::Repository::archive for %s", ref($self));
395#    $self->SUPER::DESTROY();
396#}
397
398=head3 default_choice($oevent)
399
400=cut
401
402sub default_choice {
403    my ($self, $oevent) = @_;
404
405    for ($oevent->id) {
406        /^do_archive$/ and do {
407            return($oevent->test_result('archive_exists') ? 0 : 1);
408            last;
409        };
410        /^do_data$/ and do {
411            return 1; # TODO
412            last;
413        };
414        /^overwrite$/ and do {
415            return($oevent->test_result('dest_exists') ? 0 : 1);
416            last;
417        };
418    }
419}
420
421sub ask_user {
422    my ($self, $oevent) = @_;
423
424    $self->logging(0, "Event(%s): %s",
425        $oevent->id,
426        $oevent->message);
427    foreach ($oevent->list_test) {
428        $self->logging(0, "  (%s) %s: %s",
429            $_,
430            $oevent->test_message($_),
431            $oevent->test_result($_),
432        );
433    }
434
435    my $res =
436        $self->{interactive_callback} ?
437        $self->{interactive_callback}->($self, $oevent) :
438        $self->default_choice($oevent);
439
440    $self->logging(0, "Event(%s): Result: %s", $oevent->id, $res);
441    return($res);
442}
443
444=head3 list_archive
445
446Return archive content
447
448=cut
449
450sub list_archive {
451    my ($self) = @_;
452    $self->load_archive or return;
453   
454    return $self->{Oarchive}->ls;
455}
456
457=head3 update_status
458
459Update status information about current archive
460
461=cut
462
463sub update_status {
464    my ($self) = @_;
465    my @filestats = stat("$self->{dir}/$self->{archivefile}");
466   
467    $self->setvalue('mtime', $filestats[9]);
468    $self->setvalue('size', $filestats[7]);
469    $self->setvalue('configtime', $self->{obsdata}->config_mtime);
470}
471
472# Sub data function:
473
474
475
476=head3 get_data_dest($datafile)
477
478Return the datatype and destination for $datafile
479
480=cut
481
482sub get_data_dest {
483    my ($self, $datafile) = @_;
484
485    my ($t, $d) = $self->{obsdata}->build_dest_filename(
486        $datafile,
487        $self->{datatype}
488    );
489    $self->logging(0, "%s/%s file, datatype %s, destination %s",
490        $self->{archivefile},
491        $datafile,
492        $t || '(none)',
493        $d || '(none)',
494    );
495    if ($t) {
496        $self->set_data_value($datafile, 'type', $t);
497    }
498    return($t, $d);
499}
500
501=head3 extract_data($datafile, $datatype, $destfile)
502
503Extract data file into $destfile, $datafile is informationnal only.
504
505$datatype and $destfile are the result of L<get_data_dest>.
506
507A basic call is:
508    $o->extract_data($file, $self->get_data_dest($file));
509
510Return 1 on success
511
512=cut
513
514sub extract_data {
515    # $datatype, informationnal only here
516    my ($self, $datafile, $datatype, $destfile) = @_;
517    $self->load_archive or return 0;
518    my $ltime = time;
519
520    $self->set_data_value(
521        $datafile,
522        'processtime',
523        $ltime,
524        scalar(localtime($ltime)) .
525        ", $ObsData::VERSION: $ObsData::CVSREV, $ObsData::Repository::CVSREV",
526    );
527    $self->set_data_value(
528        $datafile,
529        'processversion',
530        $ObsData::VERSION,
531    );
532   
533    if (!$destfile) {
534        $self->logging(3,
535            "%s/%s has no destination",
536            $self->{archivefile}, $datafile,
537        );
538        return 0;
539    }
540   
541    my $oe = ObsData::Event->new('overwrite',
542        "Should I overwrite $destfile"
543    );
544
545    $oe->add_test(
546        'dest_exists',
547        -e $destfile ? ("$destfile exists", 1) : ("$destfile don't exists", 0)
548    );
549    $self->ask_user($oe) or return 0;
550   
551    $self->logging(0,
552        "Trying to extract %s from %s/%s",
553        $destfile,
554        $self->{archivefile}, $datafile
555    );
556
557    my ($dirname) = $destfile =~ m!(?:(.*)/)?(.*)$!; #! vim syntax sux
558   
559    if ($dirname && ! -d $dirname) {
560        $self->logging(1, "Creating directory %s", $dirname);
561        if ($self->{dry_run}) {
562            $self->logging(1,
563                "Testing mode, assume %s was correctly created",
564                $dirname
565            );
566        } else {
567            if( ! File::Path::mkpath($dirname)) { 
568                $self->logging(
569                    4, "Can't create directory %s", 
570                    $dirname
571                );
572                return 0;
573            }
574        }
575    }
576
577    if ($self->{dry_run}) {
578        $self->logging(2,
579            "Testing mode, %s/%s would be extracted as %s",
580            $self->{archivefile},
581            $datafile,
582            $destfile,
583        );
584    } else {
585        if ($self->{Oarchive}->extract($datafile, $destfile)) {
586            $self->set_data_value($datafile, 'dest', $destfile);
587            $self->logging(
588                2, "Extraction of %s/%s done as %s",
589                $self->{archivefile},
590                $datafile,
591                $destfile,
592            );
593        } else {
594            $self->logging(
595                4, "Can't extract %s/%s to %s: %s",
596                $self->{archivefile}, $datafile, $destfile,
597                $self->{Oarchive}->error,
598            );
599            return 0;
600        }
601    }
602   
603    return 1;
604}
605
606=head3 process
607
608Process all files in the archive
609
610=cut
611
612sub process {
613    my ($self) = @_;
614
615    foreach my $data ($self->list_archive) {
616        my $oe = ObsData::Event->new('do_data',
617            "Should I extract $data from $self->{archivefile}"
618        );
619       
620        $self->ask_user($oe) or next;
621
622        $self->extract_data($data, $self->get_data_dest($data));
623    }
624   
625    $self->update_status;
626
627    return 1;
628}
629
630=head1 AUTHOR
631
632Olivier Thauvin <olivier.thauvin@aerov.jussieu.fr>
633
634=cut
635
6361;
Note: See TracBrowser for help on using the repository browser.