File Coverage

blib/lib/App/Dothe.pm
Criterion Covered Total %
statement 51 64 79.6
branch 3 6 50.0
condition 0 3 0.0
subroutine 14 17 82.3
pod 1 4 25.0
total 69 94 73.4


line stmt bran cond sub pod time code
1             package App::Dothe;
2             our $AUTHORITY = 'cpan:YANICK';
3             # ABSTRACT: YAML-based task runner
4             $App::Dothe::VERSION = '0.0.1';
5 1     1   65274 use 5.20.0;
  1         11  
6 1     1   5 use warnings;
  1         2  
  1         29  
7              
8 1     1   461 use MooseX::App::Simple;
  1         1014257  
  1         4  
9              
10 1     1   1045107 use YAML::XS qw/ LoadFile /;
  1         2450  
  1         51  
11 1     1   399 use App::Dothe::Task;
  1         3  
  1         42  
12              
13 1     1   493 use Log::Any::Adapter;
  1         316  
  1         3  
14             Log::Any::Adapter->set('Stdout', log_level => 'info' );
15              
16 1     1   40 use List::AllUtils qw/ pairmap /;
  1         2  
  1         51  
17              
18 1     1   6 use Text::Template;
  1         1  
  1         31  
19              
20 1     1   4 use experimental qw/ signatures postderef /;
  1         2  
  1         6  
21              
22             option debug => (
23             is => 'ro',
24             documentation => 'enable debugging logs',
25             default => 0,
26             isa => 'Bool',
27             trigger => sub {
28             Log::Any::Adapter->set('Stdout', log_level => 'debug' );
29             },
30             );
31              
32             option force => (
33             is => 'ro',
34             documentation => 'force the tasks to be run',
35             default => 0,
36             isa => 'Bool',
37             );
38              
39             parameter target => (
40             is => 'ro',
41             required => 1,
42             );
43              
44             has raw_vars => (
45             is => 'ro',
46             isa => 'HashRef',
47             init_arg => 'vars',
48             default => sub($self) {
49             $self->config->{vars} || {}
50             },
51             );
52              
53             has vars => (
54             is => 'ro',
55             lazy => 1,
56             isa => 'HashRef',
57             builder => '_build_vars',
58             init_arg => undef,
59             );
60              
61 1     1   300 use Ref::Util qw/ is_arrayref is_hashref /;
  1         2  
  1         568  
62              
63 3     3 0 5 sub render($self,$template,$vars) {
  3         3  
  3         4  
  3         4  
  3         3  
64 3 100       27 if( is_arrayref $template ) {
65 1         2 return [ map { $self->render($_,$vars) } @$template ];
  2         452  
66             }
67              
68 2 50       6 if( is_hashref $template ) {
69 0     0   0 return { pairmap { $a => $self->render($b,$vars) } %$template }
  0         0  
70             }
71              
72 2         5 return $self->template($template)->fill_in(HASH => $vars );
73             }
74              
75 1     1   2 sub _build_vars($self) {
  1         2  
  1         2  
76 1         2 my %vars;
77              
78             %vars = (
79             %vars,
80 1     1   37 pairmap { $a => $self->render( $b, \%vars ) } $self->raw_vars->%*
  1         5  
81             );
82              
83 1         353 return \%vars;
84             }
85              
86             has tasks => (
87             is => 'ro',
88             lazy => 1,
89             traits => [ 'Hash' ],
90             default => sub($self) { +{} },
91             );
92              
93 0     0 1 0 sub task($self,$name) {
  0         0  
  0         0  
  0         0  
94             return $self->{tasks}{$name} ||= App::Dothe::Task->new(
95 0   0     0 name => $name, tasks => $self, $self->config->{tasks}{$name}->%* );
96             }
97              
98             option file => (
99             is => 'ro',
100             documentation => 'configuration file',
101             isa => 'Str',
102             default => './Dothe.yml',
103             );
104              
105             has config => (
106             is => 'ro',
107             lazy => 1,
108             default => sub($self) { LoadFile( $self->file ) },
109             );
110              
111 0     0 0 0 sub run( $self ) {
  0         0  
  0         0  
112              
113 0 0       0 if ( my $code = $self->config->{code} ) {
114 0         0 eval join '', 'package App::Dothe::Sandbox;', @$code;
115             }
116              
117 0         0 $self->task($self->target)->run;
118              
119             }
120              
121 2     2 0 3 sub template ($self,$source) {
  2         11  
  2         2  
  2         3  
122 2         13 return Text::Template->new( TYPE => 'STRING', DELIMITERS => [ '{{', '}}' ],
123             SOURCE => $source );
124             }
125              
126             1;
127              
128             __END__
129              
130             =pod
131              
132             =encoding UTF-8
133              
134             =head1 NAME
135              
136             App::Dothe - YAML-based task runner
137              
138             =head1 VERSION
139              
140             version 0.0.1
141              
142             =head1 DESCRIPTION
143              
144             Task runner heavily inspired by Task (L<https://github.com/go-task/task>).
145             Basically, I wanted C<Task>, but with a C<foreach> construct.
146              
147             See C<perldoc App::DoThe> for the syntax of the F<Dothe.yml> file.
148              
149             =head1 DOTHE SYNTAX
150              
151             The configuration file is in YAML. It follows, by and large, the
152             format used by Task.
153              
154             By default, `dothe` looks for the file `Dothe.yml`.
155              
156             Where entries can be templates, they are evaluated via L<Text::Template>.
157             Basically, that means that in a template all that is surrounded by double curley braces
158             is evaluated as Perl code. Those code snippets are evaluated within the
159             C<App::Dothe::Sandbox> namespace, and have all the C<vars> variables
160             accessible to them.
161              
162             =head2 C<code> section
163              
164             Takes an array. Each item will be eval'ed in the namespace
165             used by the template code.
166              
167             For example, to have access to L<Path::Tiny>'s
168             C<path>:
169              
170             code:
171             - use Path::Tiny;
172              
173             tasks:
174             import-all:
175             sources:
176             - /home/yanick/work/blog_entries/**/entry
177             foreach: sources
178             cmds:
179             - task: import
180             vars: { dir: '{{ path($item)->parent }}' }
181              
182             =head2 C<vars> section
183              
184             Takes a hash of variable names and values. Those are variables that will be accessible to all
185             tasks.
186              
187             E.g.,
188              
189             vars:
190             entries_file: ./content/_shared/entries.md
191             blog_entries_root: /home/yanick/work/blog_entries
192              
193             =head2 C<tasks> section
194              
195             Takes a hash of task names and their definitions.
196              
197             E.g.,
198              
199             tasks:
200              
201             something:
202             sources: [ ./src/foo.source ]
203             generates: [ ./dest/foo.dest ]
204             foreach: sources
205             cmds:
206             - ./tools/process_entry.pl {{$item}}
207              
208             =head3 C<task>
209              
210             Defines a specific task.
211              
212             =head4 C<vars>
213              
214             Hash of variable names and values to be made accessible to the
215             task and its subtasks.
216              
217             Variable values can be templates, which have visibility of
218             previously declared variables.
219              
220             A locally defined variable will mask the definition of a global
221             variable.
222              
223             =head4 C<deps>
224              
225             Array of task dependencies. If present, Dothe will build the graph
226             of dependencies (via L<Graph::Directed>) and run them in their
227             topological order.
228              
229             deploy:
230             deps: [ clean, build, test ]
231             cmds:
232             - dzil release
233              
234             =head4 C<sources>
235              
236             Array of files. Can take glob patterns that will be expanded using
237             L<Path::Tiny::Glob>. The result is accessible via the C<sources> variable.
238              
239             foo:
240             sources: [ './lib/**/*.pm' ]
241             foreach: sources
242             cmds:
243             - perl -c {{$item}}
244              
245             =head4 C<generates>
246              
247             Array of files. If C<sources> and C<generates> are both given, the task will
248             only be run if any of the sources (or the F<Dothe.yml> file itself) has been
249             modified after the C<generates> files.
250              
251             Can take glob patterns that will be expanded using
252             L<Path::Tiny::Glob>. The result is accessible via the C<generates> variable.
253              
254             =head4 C<foreach>
255              
256             Takes the name of a variable that must hold an array. If presents,
257             the C<cmds> will be run for each value of that variable, which will
258             be accessible via C<$item>.
259              
260             =head4 C<cmds>
261              
262             List of shell commands to run. The entries can be templates.
263             As soon as one command fails, the task aborts.
264              
265             deploy:
266             vars:
267             important_test: ./xt/test.t
268             cmds:
269             - dzil build
270             - perl {{ $important_test }}
271             - dzil release
272              
273             A command can also be a subtask, with potentially some associated variables:
274              
275             stuff:
276             cmds:
277             - task: other_stuff
278             vars:
279             foo: bar
280             baz: quux
281              
282             =head1 AUTHOR
283              
284             Yanick Champoux <yanick@babyl.ca>
285              
286             =head1 COPYRIGHT AND LICENSE
287              
288             This software is copyright (c) 2019 by Yanick Champoux.
289              
290             This is free software; you can redistribute it and/or modify it under
291             the same terms as the Perl 5 programming language system itself.
292              
293             =cut