line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!perl |
2
|
|
|
|
|
|
|
# lib/Data/Hopen.pm: utility routines for hopen(1). This file is also the |
3
|
|
|
|
|
|
|
# source of the repo's README.md, which is autogenerated from this POD. |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Data::Hopen; |
6
|
22
|
|
|
22
|
|
131814
|
use strict; |
|
22
|
|
|
|
|
52
|
|
|
22
|
|
|
|
|
718
|
|
7
|
22
|
|
|
22
|
|
552
|
use Data::Hopen::Base; |
|
22
|
|
|
|
|
47
|
|
|
22
|
|
|
|
|
127
|
|
8
|
|
|
|
|
|
|
|
9
|
22
|
|
|
22
|
|
4838
|
use parent 'Exporter'; |
|
22
|
|
|
|
|
47
|
|
|
22
|
|
|
|
|
136
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# TODO move more of these to a separate utility package? |
12
|
|
|
|
|
|
|
# Probably keep hnew, hlog, $VERBOSE, and $QUIET here. |
13
|
|
|
|
|
|
|
use vars::i { |
14
|
22
|
|
|
|
|
196
|
'@EXPORT' => [qw(hnew hlog getparameters)], |
15
|
|
|
|
|
|
|
'@EXPORT_OK' => [qw(loadfrom *VERBOSE *QUIET UNSPECIFIED NOTHING)], |
16
|
22
|
|
|
22
|
|
9707
|
}; #^ * => can be localized |
|
22
|
|
|
|
|
16844
|
|
17
|
22
|
|
|
|
|
194
|
use vars::i '%EXPORT_TAGS' => { |
18
|
|
|
|
|
|
|
default => [@EXPORT], |
19
|
|
|
|
|
|
|
v => [qw(*VERBOSE *QUIET)], |
20
|
|
|
|
|
|
|
all => [@EXPORT, @EXPORT_OK], |
21
|
22
|
|
|
22
|
|
3070
|
}; |
|
22
|
|
|
|
|
51
|
|
22
|
|
|
|
|
|
|
|
23
|
22
|
|
|
22
|
|
11763
|
use Data::Hopen::Util::NameSet; |
|
22
|
|
|
|
|
63
|
|
|
22
|
|
|
|
|
671
|
|
24
|
22
|
|
|
22
|
|
10745
|
use Getargs::Mixed; |
|
22
|
|
|
|
|
23048
|
|
|
22
|
|
|
|
|
1250
|
|
25
|
22
|
|
|
22
|
|
16749
|
use Storable (); |
|
22
|
|
|
|
|
83122
|
|
|
22
|
|
|
|
|
1333
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our $VERSION = '0.000019'; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Docs {{{1 |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 NAME |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Data::Hopen - A dataflow library with first-class edges |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 SYNOPSIS |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
C is a dataflow library that runs actions you specify, moves data |
38
|
|
|
|
|
|
|
between those actions, and permits transforming data as the data moves. It is |
39
|
|
|
|
|
|
|
the underlying engine of the L cross-platform software build |
40
|
|
|
|
|
|
|
generator, but can be used for any dataflow task that can be represented as a |
41
|
|
|
|
|
|
|
directed acyclic graph (DAG). |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=head1 INSTALLATION |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
Easiest: install C if you don't have it - see |
46
|
|
|
|
|
|
|
L. Then run |
47
|
|
|
|
|
|
|
C. |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Manually: clone or untar into a working directory. Then, in that directory, |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
perl Makefile.PL |
52
|
|
|
|
|
|
|
make |
53
|
|
|
|
|
|
|
make test |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
(you may need to install dependencies as well - |
56
|
|
|
|
|
|
|
see L for resources). |
57
|
|
|
|
|
|
|
If all the tests pass, |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
make install |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
If some of the tests fail, please check the issues and file a new one if |
62
|
|
|
|
|
|
|
no one else has reported the problem yet. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=head1 VARIABLES |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
Not exported by default, except as noted. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head2 $VERBOSE |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
Set to a positive integer to get debug output on stderr from hopen's internals. |
71
|
|
|
|
|
|
|
The higher the value, the more output you are likely to get. See also L. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=head2 $QUIET |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
Set to truthy to suppress output. Quiet overrides L$VERBOSE>. |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=cut |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# }}}1 |
80
|
|
|
|
|
|
|
|
81
|
22
|
|
|
22
|
|
730
|
our $VERBOSE; BEGIN { $VERBOSE = 0; } |
82
|
22
|
|
|
22
|
|
18347
|
our $QUIET; BEGIN { $QUIET = false; } |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=head1 FUNCTIONS |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
All are exported by default unless indicated. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=head2 hnew |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
Creates a new Data::Hopen instance. For example: |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
hnew DAG => 'foo'; |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
is the same as |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
Data::Hopen::G::DAG->new( name => 'foo' ); |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
The first parameter (C<$class>) is an abbreviated package name. It is tried |
99
|
|
|
|
|
|
|
as the following, in order. The first one that succeeds is used. |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=over |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=item 1. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
C. This is tried only if C<$class> |
106
|
|
|
|
|
|
|
does not include a double-colon. |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=item 2. |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
C |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=item 3. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
C<$class> |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=back |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
The second parameter |
119
|
|
|
|
|
|
|
must be the name of the new instance. All other parameters are passed |
120
|
|
|
|
|
|
|
unchanged to the relevant constructor. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=cut |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub hnew { |
125
|
36
|
100
|
|
36
|
1
|
16792
|
my $class = shift or croak 'Need a class'; |
126
|
35
|
|
|
|
|
130
|
my @stems = ('Data::Hopen::G::', 'Data::Hopen::', ''); |
127
|
35
|
100
|
|
|
|
212
|
shift @stems if $class =~ /::/; |
128
|
|
|
|
|
|
|
|
129
|
35
|
|
|
|
|
83
|
my $found_class = false; |
130
|
|
|
|
|
|
|
|
131
|
35
|
|
|
|
|
90
|
foreach my $stem (@stems) { |
132
|
37
|
|
|
|
|
2929
|
eval "require $stem$class"; |
133
|
37
|
100
|
|
|
|
327
|
next if $@; |
134
|
34
|
|
|
|
|
101
|
$found_class = "$stem$class"; |
135
|
34
|
|
|
|
|
462
|
my $instance = "$found_class"->new('name', @_); |
136
|
|
|
|
|
|
|
# put 'name' in front of the name parameter. |
137
|
34
|
100
|
|
|
|
2588
|
return $instance if $instance; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
2
|
100
|
|
|
|
54
|
if($found_class) { |
141
|
1
|
|
|
|
|
96
|
croak "Could not create instance for $found_class"; |
142
|
|
|
|
|
|
|
} else { |
143
|
1
|
|
|
|
|
242
|
croak "Could not find class for $class"; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
} #hnew() |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head2 hlog |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Log information if L$VERBOSE> is set. Usage: |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
hlog { } [optional min verbosity level (default 1)]; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
The items in the list are joined by C<' '> on output, and a C<'\n'> is added. |
154
|
|
|
|
|
|
|
Each line is prefixed with C<'# '> for the benefit of test runs. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
The list is in C<{}> so that it won't be evaluated if logging is turned off. |
157
|
|
|
|
|
|
|
It is a full block, so you can run arbitrary code to decide what to log. |
158
|
|
|
|
|
|
|
If the block returns an empty list, hlog will not produce any output. |
159
|
|
|
|
|
|
|
However, if the block returns at least one element, hlog will produce at |
160
|
|
|
|
|
|
|
least a C<'# '>. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
The message will be output only if L$VERBOSE> is at least the given minimum |
163
|
|
|
|
|
|
|
verbosity level (1 by default). |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
If C<< $VERBOSE > 2 >>, the filename and line from which hlog was called |
166
|
|
|
|
|
|
|
will also be printed. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=cut |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub hlog (&;$) { |
171
|
440
|
100
|
|
440
|
1
|
20211
|
return if $QUIET; |
172
|
427
|
100
|
100
|
|
|
1592
|
return unless $VERBOSE >= ($_[1] // 1); |
173
|
|
|
|
|
|
|
|
174
|
321
|
|
|
|
|
486
|
my @log = &{$_[0]}(); |
|
321
|
|
|
|
|
680
|
|
175
|
321
|
100
|
|
|
|
12616
|
return unless @log; |
176
|
|
|
|
|
|
|
|
177
|
320
|
100
|
|
|
|
964
|
chomp $log[$#log] if $log[$#log]; |
178
|
|
|
|
|
|
|
# TODO add an option to number the lines of the output |
179
|
320
|
|
|
|
|
2489
|
my $msg = (join(' ', @log)) =~ s/^/# /gmr; |
180
|
320
|
100
|
|
|
|
798
|
if($VERBOSE>2) { |
181
|
314
|
|
|
|
|
2131
|
my ($package, $filename, $line) = caller; |
182
|
314
|
|
|
|
|
1082
|
$msg .= " (at $filename:$line)"; |
183
|
|
|
|
|
|
|
} |
184
|
320
|
|
|
|
|
30905
|
say STDERR $msg; |
185
|
|
|
|
|
|
|
} #hlog() |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head2 getparameters |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
An alias of the C function from L, but with |
190
|
|
|
|
|
|
|
C<-undef_ok> set. |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=cut |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
my $GM = Getargs::Mixed->new(-undef_ok => true); |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub getparameters { |
197
|
2698
|
|
|
2698
|
1
|
6313
|
unshift @_, $GM; |
198
|
2698
|
|
|
|
|
7582
|
goto &Getargs::Mixed::parameters; |
199
|
|
|
|
|
|
|
} #getparameters() |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head2 loadfrom |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
(Not exported by default) Load a package given a list of stems. Usage: |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
my $fullname = loadfrom($name[, @stems]); |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Returns the full name of the loaded package, or falsy on failure. |
208
|
|
|
|
|
|
|
If C<@stems> is omitted, no stem is used, i.e., C<$name> is tried as-is. |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=cut |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub loadfrom { |
213
|
6
|
100
|
|
6
|
1
|
7017
|
my $class = shift or croak 'Need a class'; |
214
|
|
|
|
|
|
|
|
215
|
5
|
|
|
|
|
14
|
foreach my $stem (@_, '') { |
216
|
5
|
|
|
2
|
|
30
|
hlog { loadfrom => "$stem$class" } 3; |
|
2
|
|
|
|
|
8
|
|
217
|
5
|
|
|
|
|
362
|
eval "require $stem$class"; |
218
|
5
|
100
|
|
|
|
138
|
if($@) { |
219
|
2
|
|
|
1
|
|
15
|
hlog { loadfrom => "$stem$class", 'load result was', $@ } 3; |
|
1
|
|
|
|
|
4
|
|
220
|
|
|
|
|
|
|
} else { |
221
|
3
|
|
|
|
|
17
|
return "$stem$class"; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
2
|
|
|
|
|
10
|
return undef; |
226
|
|
|
|
|
|
|
} #loadfrom() |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head1 CONSTANTS |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=head2 UNSPECIFIED |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
A L that matches any non-empty string. |
233
|
|
|
|
|
|
|
Always returns the same reference, so that it can be tested with C<==>. |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=cut |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
my $_UNSPECIFIED = Data::Hopen::Util::NameSet->new(qr/.(*ACCEPT)/); |
238
|
45
|
|
|
45
|
1
|
4932
|
sub UNSPECIFIED () { $_UNSPECIFIED }; |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=head2 NOTHING |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
A L that never matches. Always returns the |
243
|
|
|
|
|
|
|
same reference, so that it can be tested with C<==>. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=cut |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
my $_NOTHING = Data::Hopen::Util::NameSet->new(); |
248
|
13
|
|
|
13
|
1
|
3928
|
sub NOTHING () { $_NOTHING }; |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
1; # End of Data::Hopen |
251
|
|
|
|
|
|
|
__END__ |