line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# App::hopen::Gen - base class for hopen generators |
2
|
|
|
|
|
|
|
package App::hopen::Gen; |
3
|
1
|
|
|
1
|
|
467
|
use Data::Hopen qw(:default $QUIET); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
125
|
|
4
|
1
|
|
|
1
|
|
7
|
use strict; use warnings; |
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
|
|
19
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
23
|
|
5
|
1
|
|
|
1
|
|
5
|
use Data::Hopen::Base; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.000012'; # TRIAL |
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
1280
|
use parent 'Data::Hopen::Visitor'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
6
|
|
10
|
|
|
|
|
|
|
use Class::Tiny qw(proj_dir dest_dir), { |
11
|
|
|
|
|
|
|
architecture => '', |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# private |
14
|
|
|
|
|
|
|
_assets => undef, # A Data::Hopen::G::DAG of the assets |
15
|
2
|
|
|
|
|
30
|
_assetop_by_asset => sub { +{} }, # Indexed by refaddr($asset) |
16
|
1
|
|
|
1
|
|
1990
|
}; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
10
|
|
17
|
|
|
|
|
|
|
|
18
|
1
|
|
|
1
|
|
781
|
use App::hopen::BuildSystemGlobals; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
113
|
|
19
|
1
|
|
|
1
|
|
6
|
use App::hopen::Util::String qw(eval_here); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
48
|
|
20
|
1
|
|
|
1
|
|
6
|
use Data::Hopen::G::DAG; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
21
|
1
|
|
|
1
|
|
8
|
use Data::Hopen::Util::Data qw(forward_opts); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
61
|
|
22
|
1
|
|
|
1
|
|
460
|
use File::pushd qw(pushd); |
|
1
|
|
|
|
|
1279
|
|
|
1
|
|
|
|
|
75
|
|
23
|
1
|
|
|
1
|
|
8
|
use Path::Class (); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
24
|
1
|
|
|
1
|
|
6
|
use Scalar::Util qw(refaddr); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
830
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# Docs {{{1 |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 NAME |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
Data::Hopen::Gen - Base class for hopen generators |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=head1 SYNOPSIS |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
The code that generates blueprints for specific build systems |
35
|
|
|
|
|
|
|
lives under C<Data::Hopen::Gen>. L<Data::Hopen::Phase::Gen> calls modules |
36
|
|
|
|
|
|
|
under C<Data::Hopen::Gen> to create the blueprints. Those modules must |
37
|
|
|
|
|
|
|
implement the interface defined here. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head2 proj_dir |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
(Required) A L<Path::Class::Dir> instance specifying the root directory of |
44
|
|
|
|
|
|
|
the project. |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head2 dest_dir |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
(Required) A L<Path::Class::Dir> instance specifying where the generated output |
49
|
|
|
|
|
|
|
(e.g., blueprint or other files) should be written. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head2 _assets (Internal) |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
A L<Data::Hopen::G::DAG> of L<App::hopen::G::AssetOp> instances representing |
54
|
|
|
|
|
|
|
the L<App::Hopen::Asset>s to be created when a build is run. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 FUNCTIONS |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
A generator (C<Data::Hopen::Gen> subclass) is a Visitor plus some. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
B<Note>: |
61
|
|
|
|
|
|
|
The generator does not have access to L<Data::Hopen::G::Link> instances. |
62
|
|
|
|
|
|
|
That lack of access is the primary distinction between Ops and Links. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=cut |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# }}}1 |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head2 asset |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
Called by an Op (L<App::hopen::G::Op> subclass) to add an asset |
71
|
|
|
|
|
|
|
(L<App::hopen::G::AssetOp> instance) to the build. Usage: |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
$Generator->asset([-asset=>]$asset, [-from=>]$from[, [-how=>]$how]); |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
If C<$how> is specified, it will be saved in the C<AssetOp> for use later. |
76
|
|
|
|
|
|
|
Later calls with the same asset and a defined C<$how> will overwrite the |
77
|
|
|
|
|
|
|
C<how> value in the C<AssetOp>. Specify 'UNDEF' as the C<$how> to |
78
|
|
|
|
|
|
|
expressly undefine a C<how>. |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
Returns the C<AssetOp>. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=cut |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub asset { |
85
|
6
|
|
|
6
|
1
|
44
|
my ($self, %args) = getparameters('self', [qw(asset; how)], @_); |
86
|
6
|
|
|
0
|
|
575
|
hlog { 'Generator adding asset at',refaddr($args{asset}),$args{asset} } 3; |
|
0
|
|
|
|
|
0
|
|
87
|
|
|
|
|
|
|
|
88
|
6
|
|
|
|
|
168
|
my $existing_op = $self->_assetop_by_asset->{refaddr($args{asset})}; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Update an existing op |
91
|
6
|
50
|
|
|
|
38
|
if(defined $existing_op) { |
92
|
0
|
0
|
0
|
|
|
0
|
if( ($args{how}//'') eq 'UNDEF') { |
|
|
0
|
|
|
|
|
|
93
|
0
|
|
|
|
|
0
|
$existing_op->how(undef); |
94
|
|
|
|
|
|
|
} elsif(defined $args{how}) { |
95
|
0
|
|
|
|
|
0
|
$existing_op->how($args{how}); |
96
|
|
|
|
|
|
|
} |
97
|
0
|
|
|
|
|
0
|
return $existing_op; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# Need to create an op. First, load its class. |
101
|
6
|
|
|
|
|
24
|
my $class = $self->_assetop_class; |
102
|
|
|
|
|
|
|
|
103
|
6
|
|
|
|
|
34
|
eval_here <<EOT; |
104
|
|
|
|
|
|
|
require $class; |
105
|
|
|
|
|
|
|
EOT |
106
|
6
|
50
|
|
|
|
34
|
die "$@" if $@; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# Create a new op |
109
|
6
|
|
|
|
|
30
|
my $op = $class->new(name => 'Op:<<' . $args{asset}->target . '>>', |
110
|
|
|
|
|
|
|
forward_opts(\%args, qw(asset how))); |
111
|
6
|
|
|
|
|
166
|
$self->_assetop_by_asset->{refaddr($args{asset})} = $op; |
112
|
6
|
|
|
|
|
136
|
$self->_assets->add($op); |
113
|
6
|
|
|
|
|
2926
|
return $op; |
114
|
|
|
|
|
|
|
} #asset() |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head2 connect |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
Add a dependency edge between two assets or goals. Any assets must have already |
119
|
|
|
|
|
|
|
been added using L</asset>. Usage: |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
$Generator->connect([-from=>]$from, [-to=>$to]); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
TODO add missing assets automatically? |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=cut |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub connect { |
128
|
6
|
|
|
6
|
1
|
28
|
my ($self, %args) = getparameters('self', [qw(from to)], @_); |
129
|
6
|
|
|
|
|
540
|
my %nodes; |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# Get the nodes if we were passed assets. |
132
|
6
|
|
|
|
|
16
|
foreach my $field (qw(from to)) { |
133
|
12
|
100
|
|
|
|
61
|
if(eval { $args{$field}->DOES('App::hopen::Asset') }) { |
|
12
|
|
|
|
|
62
|
|
134
|
10
|
|
|
|
|
194
|
$nodes{$field} = $self->_assetop_by_asset->{refaddr($args{$field})}; |
135
|
|
|
|
|
|
|
} else { |
136
|
2
|
|
|
|
|
7
|
$nodes{$field} = $args{$field}; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# TODO better error messages |
141
|
6
|
50
|
|
|
|
431
|
croak "No From node for asset " . refaddr($args{from}) unless $nodes{from}; |
142
|
6
|
50
|
|
|
|
117
|
croak "No To node for asset " . refaddr($args{to}) unless $nodes{to}; |
143
|
6
|
|
|
|
|
206
|
$self->_assets->connect($nodes{from}, $nodes{to}); |
144
|
|
|
|
|
|
|
} #connect() |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head2 run_build |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
Runs the build tool for which this generator has created blueprint files. |
149
|
|
|
|
|
|
|
Runs the tool with the destination directory as the current dir. |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=cut |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub run_build { |
154
|
0
|
0
|
|
0
|
1
|
0
|
my $self = shift or croak 'Need an instance'; |
155
|
0
|
|
|
|
|
0
|
my $abs_dir = $DestDir->absolute; |
156
|
|
|
|
|
|
|
# NOTE: You have to call this *before* pushd() or chdir(), because |
157
|
|
|
|
|
|
|
# it may be a relative path, and absolute() converts with respect |
158
|
|
|
|
|
|
|
# to cwd at the time of the call. |
159
|
0
|
|
|
|
|
0
|
my $dir = pushd($abs_dir); |
160
|
0
|
0
|
|
|
|
0
|
say "Building in ${abs_dir}..." unless $QUIET; |
161
|
0
|
|
|
|
|
0
|
$self->_run_build(); |
162
|
|
|
|
|
|
|
} #run_build() |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=head2 BUILD |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Constructor. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=cut |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub BUILD { |
171
|
4
|
|
|
4
|
1
|
448
|
my ($self, $args) = @_; |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Enforce the required argument types |
174
|
|
|
|
|
|
|
croak "Need a project directory (Path::Class::Dir)" |
175
|
4
|
50
|
|
|
|
7
|
unless eval { $self->proj_dir->DOES('Path::Class::Dir') }; |
|
4
|
|
|
|
|
108
|
|
176
|
|
|
|
|
|
|
croak "Need a destination directory (Path::Class::Dir)" |
177
|
4
|
50
|
|
|
|
58
|
unless eval { $self->dest_dir->DOES('Path::Class::Dir') }; |
|
4
|
|
|
|
|
82
|
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# Create the asset graph |
180
|
4
|
|
|
|
|
46
|
$self->_assets(hnew DAG => 'asset graph'); |
181
|
|
|
|
|
|
|
} #BUILD() |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=head1 FUNCTIONS TO BE IMPLEMENTED BY SUBCLASSES |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=head2 _assetop_class |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
(Required) Returns the name of the L<App::hopen::G::AssetOp> subclass that |
188
|
|
|
|
|
|
|
should be used to represent assets in the C<_assets> graph. |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=cut |
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
0
|
|
|
sub _assetop_class { ... } |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head2 default_toolset |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
(Required) Returns the package stem of the default toolset for this generator. |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
When a hopen file invokes C<use language "Foo">, hopen will load |
199
|
|
|
|
|
|
|
C<< Data::Hopen::T::<stem>::Foo >>, where C<< <stem> >> is the return |
200
|
|
|
|
|
|
|
value of this function. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
As a sanity check, hopen will first try to load C<< Data::Hopen::T::<stem> >>, |
203
|
|
|
|
|
|
|
so make sure that is a valid package. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=cut |
206
|
|
|
|
|
|
|
|
207
|
0
|
|
|
0
|
1
|
|
sub default_toolset { ... } |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head2 finalize |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
(Optional) |
212
|
|
|
|
|
|
|
Do whatever the generator wants to do to finish up. By default, no-op. |
213
|
|
|
|
|
|
|
Is provided the L<Data::Hopen::G::DAG> instance as a parameter. Usage: |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
$generator->finalize(-phase=>$Phase, -graph=>$dag) |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=cut |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
0
|
1
|
|
sub finalize { } |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head2 _run_build |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
(Optional) |
224
|
|
|
|
|
|
|
Implementation of L</run_build>. The default does not die, but does warn(). |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=cut |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub _run_build { |
229
|
0
|
|
|
0
|
|
|
warn "This generator is not configured to run a build tool. Sorry!"; |
230
|
|
|
|
|
|
|
} #_run_build() |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=head2 visit_goal |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
(Optional) |
235
|
|
|
|
|
|
|
Do whatever the generator wants to do with a L<Data::Hopen::G::Goal>. |
236
|
|
|
|
|
|
|
For example, the generator may change the goal's C<outputs>. |
237
|
|
|
|
|
|
|
By default, no-op. Usage: |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
$generator->visit_goal($goal); |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=cut |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
0
|
1
|
|
sub visit_goal { } |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=head2 visit_node |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
(Optional) |
248
|
|
|
|
|
|
|
Do whatever the generator wants to do with a L<Data::Hopen::G::Node> that |
249
|
|
|
|
|
|
|
is not a Goal (see L</visit_goal>). By default, no-op. Usage: |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
$generator->visit_node($node) |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=cut |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
6
|
1
|
|
sub visit_node { } |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
1; |
258
|
|
|
|
|
|
|
__END__ |
259
|
|
|
|
|
|
|
# vi: set fdm=marker: # |