File Coverage

blib/lib/Script/Resume.pm
Criterion Covered Total %
statement 15 100 15.0
branch 0 40 0.0
condition 0 20 0.0
subroutine 5 17 29.4
pod 7 11 63.6
total 27 188 14.3


line stmt bran cond sub pod time code
1             package Script::Resume;
2              
3 1     1   22900 use strict;
  1         2  
  1         40  
4 1     1   5 use vars qw($VERSION);
  1         2  
  1         43  
5 1     1   1037 use Data::Dumper;
  1         10931  
  1         69  
6 1     1   8 use File::Basename;
  1         2  
  1         66  
7 1     1   808 use FileHandle;
  1         13159  
  1         6  
8              
9             $VERSION = '1.0';
10              
11             our $NAME = "Script::Resume";
12              
13             # SCRIPT_STATE - Script specific state (ref to a ref to an object or hash or array or scalar)
14             # STATE_FILE - File to store state of everything
15             # RESUME - Continue where left off (default = 1)
16             # DEBUG - Print out debug info
17             # RETAIN_STATE - Keep the state around even after the script finishes
18             # (You'll want to delete this by hand before running the script again)
19             # STAGES - The list of stage names
20             # STOP_AFTER - Stop after state X is run.
21             sub new
22             {
23 0     0 1   my $this = shift;
24 0   0       my $class = ref($this) || $this;
25 0           my %opts = @_;
26 0   0       my $tmpdir = $ENV{TEMP} || $ENV{TMP} || "/tmp";
27 0           my $def_state_file = "$tmpdir/" . basename($0) . ".state";
28              
29 0   0       my $self = { _istate => {ORDER => 0,
30             STOP_AFTER => $opts{STOP_AFTER},
31             SFILE => $opts{STATE_FILE} || $def_state_file,
32             DEBUG => $opts{DEBUG},
33             RETAIN_STATE => $opts{RETAIN_STATE}},
34             _stages => {},
35             _estate => {RESULTS => {}}};
36              
37 0 0         $self->{_estate}->{SCRIPT} = ${$opts{SCRIPT_STATE}} if $opts{SCRIPT_STATE};
  0            
38 0           bless $self, $class;
39              
40 0 0 0       $self->debug("Resume: unlinking file $opts{RESUME}"), unlink($self->{_istate}->{SFILE}) if (defined $opts{RESUME} && $opts{RESUME} == 0);
41 0 0         $self->{_istate}->{SFH} = new FileHandle($self->{_istate}->{SFILE}, O_RDWR|O_CREAT) or die "$NAME: Couldn't open state file $self->{_istate}->{SFILE}: $!\n";
42              
43 0 0         $self->addStages(@{$opts{STAGES}}) if $opts{STAGES};
  0            
44 0           $self->readState($opts{SCRIPT_STATE});
45              
46 0           return $self;
47             }
48              
49             # NAME
50             # FUNC
51             # ALWAYS
52             # ORDER
53             sub addStage
54             {
55 0     0 1   my $self = shift;
56 0           my $name = shift;
57 0           my $caller_name = $name;
58 0 0         $caller_name = $self->getCallingPackage() . "::$caller_name" unless (index($caller_name, "::") >= 0);
59              
60 0 0         die "$NAME: addStage: Need a name for the stage" unless $name;
61 0           %{$self->{_stages}->{$name}} = @_;
  0            
62 0 0         $self->{_stages}->{$name}->{FUNC} = \&{$caller_name} unless $self->{_stages}->{$name}->{FUNC};
  0            
63 0 0         $self->{_stages}->{$name}->{ORDER} = ++$self->{_istate}->{ORDER} unless defined $self->{_stages}->{$name}->{ORDER};
64 0           $self->debug("Adding stage = $name order = $self->{_stages}->{$name}->{ORDER}");
65 0 0         die "$NAME: FUNC for stage $name not defined\n" unless defined &{$self->{_stages}->{$name}->{FUNC}};
  0            
66             }
67              
68             sub getCallingPackage
69             {
70 0     0 0   my $self = shift;
71 0           my $i = 0;
72 0           my $caller;
73 0           while ( ($caller = (caller($i))[0]) eq $NAME) {
74 0           $i++;
75             }
76            
77 0           return $caller;
78             }
79              
80              
81             sub addStages
82             {
83 0     0 1   my $self = shift;
84 0           $self->addStage($_) foreach @_;
85             }
86              
87             sub setStageAttributes
88             {
89 0     0 1   my $self = shift;
90 0           my $name = shift;
91 0           my %opts = @_;
92              
93 0 0         die "$NAME: addStage: Need a name for the stage" unless $name;
94 0 0         die "$NAME: No such stage $name\n" unless $self->{_stages}->{$name};
95              
96 0           $self->{_stages}->{$name}->{$_} = $opts{$_} foreach (keys %opts);
97             }
98              
99             sub debug
100             {
101 0     0 0   my $self = shift;
102              
103 0 0         return unless $self->{_istate}->{DEBUG};
104 0           my $msg = shift;
105 0           print "$NAME: $msg\n";
106             }
107              
108             sub readState
109             {
110 0     0 0   my $self = shift;
111 0           my $script_state = shift;
112 0           my $fh = $self->{_istate}->{SFH};
113 0           my $dumpy;
114              
115 0           $fh->seek(0,0);
116              
117 0           $dumpy = join("", <$fh>);
118              
119 0 0         if ($dumpy) {
120 0           my $VAR1;
121 0           $self->{_estate} = eval($dumpy);
122 0 0         die "$NAME: Couldn't read in state: $@\n" if $@;
123 0 0         $$script_state = $self->{_estate}->{SCRIPT} if ($script_state);
124 0           return 1;
125             }
126 0           return 0;
127             }
128              
129             sub runAllStages
130             {
131 0     0 1   my $self = shift;
132 0           my $stage;
133 0           foreach $stage (sort {$self->{_stages}->{$a}->{ORDER} <=> $self->{_stages}->{$b}->{ORDER}} keys %{$self->{_stages}}) {
  0            
  0            
134 0           $self->runStage($stage, @_);
135             }
136             }
137              
138             sub runStage
139             {
140 0     0 1   my $self = shift;
141 0           my $name = shift;
142              
143 0 0 0       $self->debug("Running Stage: $name"), $self->{_estate}->{RESULTS}->{$name} = [&{$self->{_stages}->{$name}->{FUNC}}(@_)] if ($self->{_stages}->{$name}->{ALWAYS} || ! defined $self->{_estate}->{RESULTS}->{$name}); # RJP: remove the "defined" and replace RESULTS with RUN
  0            
144             #$self->{_estate}->{RUN}->{$name} = 1; #RJP
145              
146 0           $self->writeState();
147 0 0         $self->debug("Stopping after $name because STOP_AFTER = $name"), exit(0) if $self->{_istate}->{STOP_AFTER} eq $name;
148 0 0         return wantarray ? @{$self->{_estate}->{RESULTS}->{$name}} : $self->{_estate}->{RESULTS}->{$name}->[0];
  0            
149             }
150              
151             sub writeState
152             {
153 0     0 0   my $self = shift;
154              
155 0 0         return if $self->{_istate}->{DONE};
156 0           my $fh = $self->{_istate}->{SFH};
157 0           $fh->seek(0,0);
158 0           print $fh Dumper($self->{_estate});
159 0           $fh->flush();
160             }
161              
162             sub doneEarly
163             {
164 0     0 1   my $self = shift;
165 0           $self->{_istate}->{DONE} = 1;
166             }
167              
168             sub DESTROY
169             {
170 0     0     my $self = shift;
171 0           $self->writeState();
172 0           $self->{_istate}->{SFH}->close();
173              
174 0 0 0       unlink $self->{_istate}->{SFILE} if (!$self->{_istate}->{RETAIN_STATE} && ($self->{_istate}->{DONE} || scalar keys %{$self->{_stages}} == scalar keys %{$self->{_estate}->{RESULTS}}));#RUN - RJP
      0        
175             }
176              
177             1;
178              
179             __END__