File Coverage

blib/lib/BioX/Workflow/Command/run/Utils/WriteMeta.pm
Criterion Covered Total %
statement 12 173 6.9
branch 0 44 0.0
condition n/a
subroutine 4 19 21.0
pod 10 15 66.6
total 26 251 10.3


line stmt bran cond sub pod time code
1             package BioX::Workflow::Command::run::Utils::WriteMeta;
2              
3 1     1   3629 use MooseX::App::Role;
  1         2  
  1         10  
4 1     1   6197 use namespace::autoclean;
  1         2  
  1         8  
5              
6 1     1   63 use YAML;
  1         48  
  1         55  
7 1     1   6 use File::Slurp;
  1         2  
  1         1688  
8              
9             =head1 BioX::Workflow::Command::run::Utils::WriteMeta;
10              
11             Debug information containing metadata per rule.
12              
13             Useful for tracking the evolution of an analysis
14              
15             =head2 Variables
16              
17             =head3 comment_char
18              
19             Default comment char is '#'.
20              
21             =cut
22              
23             option 'comment_char' => (
24             is => 'rw',
25             isa => 'Str',
26             default => '#',
27             );
28              
29             =head3 verbose
30              
31             Output some more things
32              
33             =cut
34              
35             option 'verbose' => (
36             is => 'rw',
37             isa => 'Bool',
38             default => 1,
39             clearer => 'clear_verbose',
40             predicate => 'has_verbose',
41             );
42              
43             =head2 Subroutines
44              
45             =cut
46              
47             =head3 print_opts
48              
49             Get the command line opts and config data - print those to cached workflow and
50             our workflow file.
51              
52             =cut
53              
54             sub print_opts {
55 0     0 1   my $self = shift;
56              
57 0           my $cmd_opts = $self->print_cmd_line_opts;
58 0           my $config_data = $self->print_config_data;
59              
60 0           write_file( $self->cached_workflow, $cmd_opts );
61 0           write_file( $self->cached_workflow, { append => 1 }, $config_data );
62 0           write_file(
63             $self->cached_workflow,
64             { append => 1 },
65             Dump( $self->workflow_data )
66             );
67              
68 0           my $now = DateTime->now();
69 0           $self->fh->say("#!/usr/bin/env bash\n\n");
70              
71 0           $self->fh->print($cmd_opts);
72 0           $self->fh->say($config_data);
73             }
74              
75             =head3 write_workflow_meta
76              
77             Write out the global variables in the start, and the ending variables in the end
78              
79             =cut
80              
81             sub write_workflow_meta {
82 0     0 1   my $self = shift;
83 0           my $type = shift;
84              
85 0 0         return unless $self->verbose;
86              
87 0 0         $self->write_workflow_meta_start if $type eq 'start';
88 0 0         $self->write_workflow_meta_end if $type eq 'end';
89             }
90              
91             sub write_workflow_meta_start {
92 0     0 0   my $self = shift;
93 0           $self->fh->say("$self->{comment_char}\n");
94 0           $self->fh->say("$self->{comment_char} Starting Workflow\n");
95 0           $self->fh->say("$self->{comment_char}");
96 0           $self->fh->say("$self->{comment_char}");
97              
98 0           $self->fh->say("$self->{comment_char} Samples:");
99             $self->fh->say(
100 0           "$self->{comment_char} \t" . join( ', ', @{ $self->samples } ) );
  0            
101 0           $self->fh->say("$self->{comment_char}");
102 0           $self->fh->say("$self->{comment_char}");
103              
104 0           $self->fh->say("$self->{comment_char} Global Variables:");
105              
106 0           foreach my $k ( $self->all_global_keys ) {
107 0 0         next unless $k;
108 0           my $v = $self->global_attr->$k;
109 0           $self->fh->print( $self->write_pretty_meta( $k, $v ) );
110             }
111 0           $self->fh->say("$self->{comment_char}");
112             }
113              
114             sub write_workflow_meta_end {
115 0     0 0   my $self = shift;
116 0           $self->fh->say("$self->{comment_char}");
117 0           $self->fh->say("$self->{comment_char} Ending Workflow");
118 0           $self->fh->say("$self->{comment_char}");
119             }
120              
121             =head2 write_rule_meta
122              
123             =cut
124              
125             sub write_rule_meta {
126 0     0 1   my $self = shift;
127 0           my $meta = shift;
128              
129 0           my @meta_text = ();
130              
131 0           push( @meta_text, "\n$self->{comment_char}" );
132              
133 0 0         if ( $meta eq "after_meta" ) {
134              
135 0           push( @meta_text, "$self->{comment_char} Ending $self->{key}" );
136             }
137              
138 0           push( @meta_text, "$self->{comment_char}\n" );
139              
140 0 0         return \@meta_text unless $meta eq "before_meta";
141              
142 0           push( @meta_text, "$self->{comment_char}" );
143 0           push( @meta_text, "$self->{comment_char} Starting $self->{rule_name}" );
144 0           push( @meta_text, "$self->{comment_char}" );
145              
146 0 0         return \@meta_text unless $self->verbose;
147              
148 0           push( @meta_text, "\n\n$self->{comment_char}" );
149              
150 0           push( @meta_text, "$self->{comment_char} Variables" );
151              
152 0           push( @meta_text,
153             "$self->{comment_char} Indir: " . $self->local_attr->indir );
154              
155 0           push( @meta_text,
156             "$self->{comment_char} Outdir: " . $self->local_attr->outdir );
157              
158 0 0         if ( exists $self->local_rule->{ $self->rule_name }->{local} ) {
159              
160 0           push( @meta_text, "$self->{comment_char}" );
161              
162 0           push( @meta_text, "$self->{comment_char} Local Variables:\n#" );
163              
164 0           foreach my $k ( $self->all_local_rule_keys ) {
165 0           my ($v) = $self->local_attr->$k;
166              
167 0           push( @meta_text, $self->write_pretty_meta( $k, $v ) );
168             }
169             }
170              
171 0 0         my $t = $self->write_sample_meta if $self->resample;
172 0 0         push( @meta_text, $t ) if $t;
173              
174 0           $self->write_hpc_meta;
175              
176 0           push( @meta_text, "$self->{comment_char}\n" );
177              
178 0           push( @meta_text, "$self->{comment_char}" );
179 0           my @tmp_before_meta = split( "\n", $self->local_attr->before_meta );
180              
181 0           map { push( @meta_text, $self->decide_comment( trim($_) ) ) }
  0            
182             @tmp_before_meta;
183              
184 0           push( @meta_text, "$self->{comment_char}\n" );
185              
186 0           return \@meta_text;
187             }
188              
189             =head3 decide_comment
190              
191             In order to keep backwards compatibility with beforemeta
192             If the before_meta starts with a #, don't add another one
193              
194             =cut
195              
196             sub decide_comment {
197 0     0 1   my $self = shift;
198 0           my $current = shift;
199 0           my $comment_char = $self->comment_char;
200 0 0         if ( $current =~ m/^$comment_char/ ) {
201 0           return $current;
202             }
203             else {
204 0           return $self->comment_char . $current;
205             }
206              
207             }
208              
209             sub trim {
210 0     0 0   my $text = shift;
211              
212 0           $text =~ s/^\s+|\s+$//g;
213 0           return $text;
214             }
215              
216             =head3 write_hpc_meta
217              
218             =cut
219              
220             sub write_hpc_meta {
221 0     0 1   my $self = shift;
222              
223             ##TODO Fix this for mixed data types
224              
225 0           $self->local_attr->add_before_meta( ' ### HPC Directives' . "\n" );
226 0 0         if ( ref( $self->local_attr->HPC ) eq 'HASH' ) {
    0          
227 0           $self->write_hpc_hash_meta;
228             }
229             elsif ( ref( $self->local_attr->HPC ) eq 'ARRAY' ) {
230 0           $self->write_hpc_array_meta;
231             }
232              
233             }
234              
235             =head3 write_hpc_hash_meta
236              
237             Write meta when HPC is a HashRef
238              
239             If its a hash we can merge it
240              
241             =cut
242              
243             sub write_hpc_hash_meta {
244 0     0 1   my $self = shift;
245              
246 0           my $jobname = '';
247 0 0         if ( !exists $self->local_attr->HPC->{jobname} ) {
248 0           $self->local_attr->add_before_meta(
249             'HPC jobname=' . $self->rule_name . "\n" );
250 0           $jobname = $self->rule_name;
251             }
252             else {
253             $self->local_attr->add_before_meta(
254 0           'HPC jobname=' . $self->local_attr->HPC->{jobname} . "\n" );
255 0           $jobname = $self->local_attr->HPC->{jobname};
256 0           delete $self->local_attr->HPC->{jobname};
257             }
258              
259 0           $self->iter_hpc_hash( $self->local_attr->HPC );
260 0           $self->local_attr->HPC->{jobname} = $jobname;
261             }
262              
263             =head3 write_hpc_array_meta
264              
265             Write meta when HPC is an ArrayRef
266              
267             =cut
268              
269             sub write_hpc_array_meta {
270 0     0 1   my $self = shift;
271              
272             #First we look for keys to see if we get jobname
273              
274 0           my %lookup = ();
275              
276 0 0         if ( ref( $self->global_attr->HPC ) eq 'ARRAY' ) {
    0          
277             %lookup =
278 0           %{ $self->iter_hpc_array( $self->global_attr->HPC, \%lookup ) };
  0            
279             }
280             elsif ( ref( $self->global_attr->HPC ) eq 'HASH' ) {
281 0           %lookup = %{ $self->global_attr->HPC };
  0            
282             }
283              
284 0           %lookup = %{ $self->iter_hpc_array( $self->local_attr->HPC, \%lookup ) };
  0            
285              
286 0 0         if ( !exists $lookup{jobname} ) {
287 0           $self->local_attr->add_before_meta(
288             'HPC jobname=' . $self->rule_name . "\n" );
289             unshift(
290 0           @{ $self->local_attr->HPC },
  0            
291             { 'jobname' => $self->rule_name }
292             );
293             }
294             else {
295             $self->local_attr->add_before_meta(
296 0           'HPC jobname=' . $lookup{jobname} . "\n" );
297 0           delete $lookup{jobname};
298             }
299              
300 0           $self->iter_hpc_hash( \%lookup );
301             }
302              
303             =head3 iter_hpc_array
304              
305             =cut
306              
307             sub iter_hpc_array {
308 0     0 1   my $self = shift;
309 0           my $aref = shift;
310 0           my $lookup = shift;
311              
312 0           foreach my $href ( @{$aref} ) {
  0            
313 0 0         if ( ref($href) eq 'HASH' ) {
314 0           my @keys = keys %{$href};
  0            
315 0           map { $lookup->{$_} = $href->{$_} } @keys;
  0            
316             }
317             else {
318 0           $self->warn_hpc_meta;
319 0           return;
320             }
321             }
322              
323 0           return $lookup;
324             }
325              
326             =head3 iter_hpc_hash
327              
328             =cut
329              
330             sub iter_hpc_hash {
331 0     0 1   my $self = shift;
332 0           my $href = shift;
333              
334             #TODO Add in a lookup here that will check deps for any undeclared rules
335              
336 0           while ( my ( $k, $v ) = each %{$href} ) {
  0            
337 0 0         if ( !ref($k) ) {
338 0           $self->local_attr->add_before_meta( 'HPC ' . $k . '=' . $v . "\n" );
339             }
340             else {
341 0           $self->warn_hpc_meta;
342             }
343             }
344             }
345              
346             sub warn_hpc_meta {
347 0     0 0   my $self = shift;
348              
349 0           my $hpc = <<EOF;
350             Key/Value:
351              
352             HPC:
353             mem: 40GB
354             walltime: '02:00:00'
355              
356             List of Key/Value:
357             HPC:
358             - mem: 40GB
359             - walltime: '02:00:00'
360             EOF
361 0           $self->app_log->warn(
362             'You are using an unsupported data structure for HPC.');
363 0           $self->app_log->warn('HPC should be key/value or a list of key/value');
364 0           $self->app_log->warn(
365             'HPC data structure should look resemble the following:' . "\n"
366             . $hpc );
367             }
368              
369             =head3 write_sample_meta
370              
371             Write the meta for samples
372              
373             =cut
374              
375             #TODO add this to app log
376              
377             sub write_sample_meta {
378 0     0 1   my $self = shift;
379              
380 0 0         return unless $self->verbose;
381 0           my $meta_text = "";
382              
383 0           $meta_text .= "$self->{comment_char}\n";
384             $meta_text .= "$self->{comment_char} Samples: "
385 0           . join( ', ', @{ $self->samples } ) . "\n";
  0            
386 0           $meta_text .= "$self->{comment_char}\n\n";
387              
388             $self->app_log->info(
389 0           'Found samples: ' . join( ', ', @{ $self->samples } ) . "\n" );
  0            
390              
391 0           return $meta_text;
392             }
393              
394             sub write_pretty_meta {
395 0     0 0   my $self = shift;
396 0           my $k = shift;
397 0           my $v = shift;
398              
399 0           my $t = '';
400 0 0         if ( !ref($v) ) {
401 0           $t = "$self->{comment_char}\t$k: " . $v . "\n";
402             }
403             else {
404 0           $v = Dump($v);
405 0           my %seen = ();
406 0           my @uniq_array = ();
407 0           my @array = split( "\n", $v );
408 0           shift(@array);
409 0           for ( my $x = 0 ; $x <= $#array ; $x++ ) {
410 0           my $t = $self->comment_char . "\t\t" . $array[$x];
411 0 0         next if $seen{$t};
412 0           push( @uniq_array, $t );
413 0           $seen{$t} = 1;
414             }
415 0           $v = join( "\n", @uniq_array );
416 0           $t = "$self->{comment_char}\t$k:\n" . $v . "\n";
417             }
418              
419 0           return $t;
420             }
421              
422             1;