File Coverage

blib/lib/CloudCron/Compiler.pm
Criterion Covered Total %
statement 77 78 98.7
branch 4 4 100.0
condition 2 3 66.6
subroutine 23 23 100.0
pod 0 2 0.0
total 106 110 96.3


line stmt bran cond sub pod time code
1             package CloudCron::Compiler;
2 1     1   108882 use Moose;
  1         380365  
  1         11  
3 1     1   7023 use namespace::autoclean;
  1         6266  
  1         5  
4              
5 1     1   363 use CloudCron::Parser;
  1         3  
  1         30  
6 1     1   368 use CloudCron::TargetInput;
  1         3  
  1         30  
7 1     1   376 use CloudCron::CronLineRule;
  1         3  
  1         27  
8 1     1   474 use Cfn;
  1         498624  
  1         50  
9 1     1   635 use Cfn::Resource::AWS::Events::Rule;
  1         70323  
  1         38  
10 1     1   8 use Cfn::Resource::Properties::AWS::Events::Rule;
  1         3  
  1         17  
11 1     1   5 use Path::Class;
  1         3  
  1         58  
12 1     1   5 use Carp;
  1         2  
  1         44  
13 1     1   590 use ParseCron;
  1         3370  
  1         648  
14              
15             has target => (is => 'ro', isa => 'CloudCron::TargetQueue', required => 1);
16             has content => (is => 'ro', isa => 'Str', lazy => 1, default => sub {
17             my $self = shift;
18             croak 'Attribute file or content is required!' unless defined $self->file;
19             Path::Class::file($self->file)->slurp;
20             });
21             has parser => (is => 'ro', isa => 'CloudCron::Parser', lazy => 1, builder => '_parser');
22             has file => (is => 'ro');
23             has translator => (is => 'ro', isa => 'ParseCron', lazy => 1, builder => '_translator');
24              
25             sub _translator {
26 6     6   7 my $self;
27 6         28 return ParseCron->new;
28             }
29              
30             sub _parser {
31 8     8   16 my $self = shift;
32 8         171 return CloudCron::Parser->new({ content => $self->content });
33             }
34              
35             sub rules {
36 7     7 0 41 my $self = shift;
37              
38 7 100       168 die "Invalid crontab specification" if !$self->parser->is_valid;
39 6         244 my @jobs = $self->parser->jobs;
40 6         64 return map { $self->_as_line_rule($_); } @jobs;
  8         23  
41             }
42              
43             sub _as_line_rule {
44 8     8   17 my ($self, $job) = @_;
45 8         34 return CloudCron::CronLineRule->new({
46             line => $job->line_number,
47             rule => $self->_as_rule($job),
48             });
49             }
50              
51             sub envs {
52 9     9 0 20 my $self = shift;
53 9         225 return $self->parser->envs;
54             }
55              
56             sub _as_rule {
57 8     8   14 my ($self, $job) = @_;
58 8         22 return Cfn::Resource::AWS::Events::Rule->new({
59             Properties => $self->_get_properties($job),
60             });
61             }
62              
63             sub _cron {
64 8     8   13 my $self = shift;
65 8         13 my $job = shift;
66 8         12 return join ' ', map { $job->$_->entity } qw/minute hour day month day_of_week/;
  40         433  
67             }
68              
69             sub _name {
70 16     16   24 my ($self, $job) = @_;
71 16         42 my @parts = split /\//, $job->command;
72 16         37 return $parts[$#parts];
73             }
74              
75             sub _input {
76 8     8   19 my ($self, $job, @envars) = @_;
77 8         17 my @aux = map { ($_->key, $_->value) } @envars;
  0         0  
78 8         16 my %envs_hash = @aux;
79 8         206 return CloudCron::TargetInput->new({
80             command => $job->command,
81             env => \%envs_hash,
82             });
83             }
84              
85             sub _description { # name. human cron schedule
86 8     8   16 my ($self, $job) = @_;
87 8         15 my $name = $self->_name($job);
88 8         216 my $human = $self->translator->parse_cron(join ' ', map { $job->$_->entity } qw/minute hour day month day_of_week/);
  40         379  
89 8         2832 return $name . " " . $human;
90             }
91              
92             # This method makes possible that crontab files that are valid could be "compiled"
93             # to AWS::Events::Rule. There are some restrictions that needs to be taken
94             # into account. For more information see the "Limits" section on AWS doc here:
95             # http://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html#CronExpressions
96             sub _patch_days {
97 8     8   17 my ($self, $cron) = @_;
98 8         39 my @parts = split /\s/, $cron;
99 8 100 66     43 if (($parts[2] eq '*') && ($parts[4] eq '*')) {
100 6         10 $parts[2] = '?';
101             }
102 8         28 return (join ' ', @parts) . ' *';
103             }
104              
105             sub _get_properties {
106 8     8   13 my $self = shift;
107 8         13 my $job = shift;
108 8         29 my $cron = $self->_cron($job);
109 8         107 $cron = $self->_patch_days($cron);
110 8         23 my $name = $self->_name($job);
111 8         18 my $description = $self->_description($job);
112 8         24 my $input = $self->_input($job, $self->envs);
113 8         186 return Cfn::Resource::Properties::AWS::Events::Rule->new({
114             Description => $description,
115             ScheduleExpression => "cron($cron)",
116             State => 'ENABLED',
117             Targets => [
118             {
119             Arn => $self->target->Arn,
120             Id => $self->target->Id,
121             Input => $input->json,
122             },
123             ],
124             });
125             }
126              
127             __PACKAGE__->meta->make_immutable;
128             1;