| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
############################################################################# |
|
2
|
|
|
|
|
|
|
# |
|
3
|
|
|
|
|
|
|
# Manipulate (and probably abuse) a RPM spec |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# Author: Chris Weyl (cpan:RSRCHBOY), <cweyl@alumni.drew.edu> |
|
6
|
|
|
|
|
|
|
# Company: No company, personal work |
|
7
|
|
|
|
|
|
|
# Created: 05/04/2009 09:36:47 PM PDT |
|
8
|
|
|
|
|
|
|
# |
|
9
|
|
|
|
|
|
|
# Copyright (c) 2009 Chris Weyl <cweyl@alumni.drew.edu> |
|
10
|
|
|
|
|
|
|
# |
|
11
|
|
|
|
|
|
|
# This library is free software; you can redistribute it and/or |
|
12
|
|
|
|
|
|
|
# modify it under the terms of the GNU Lesser General Public |
|
13
|
|
|
|
|
|
|
# License as published by the Free Software Foundation; either |
|
14
|
|
|
|
|
|
|
# version 2.1 of the License, or (at your option) any later version. |
|
15
|
|
|
|
|
|
|
# |
|
16
|
|
|
|
|
|
|
############################################################################# |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
package RPM::Spec; |
|
19
|
|
|
|
|
|
|
|
|
20
|
1
|
|
|
1
|
|
30761
|
use Moose; |
|
|
1
|
|
|
|
|
729389
|
|
|
|
1
|
|
|
|
|
9
|
|
|
21
|
1
|
|
|
1
|
|
7940
|
use namespace::autoclean; |
|
|
1
|
|
|
|
|
1372
|
|
|
|
1
|
|
|
|
|
6
|
|
|
22
|
|
|
|
|
|
|
|
|
23
|
1
|
|
|
1
|
|
762
|
use MooseX::Types::Moose ':all'; |
|
|
1
|
|
|
|
|
66116
|
|
|
|
1
|
|
|
|
|
10
|
|
|
24
|
1
|
|
|
1
|
|
9349
|
use MooseX::Types::Path::Class ':all'; |
|
|
1
|
|
|
|
|
82007
|
|
|
|
1
|
|
|
|
|
9
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
1
|
|
|
1
|
|
1518
|
use Path::Class; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
1345
|
|
|
27
|
|
|
|
|
|
|
#use RPM::Spec::DependencyInfo; |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
our $VERSION = '0.05'; |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# debugging |
|
32
|
|
|
|
|
|
|
#use Smart::Comments '###', '####'; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
############################################################################# |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
has specfile => (is => 'ro', isa => File, coerce => 1, required => 1); |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
has filter_magic => (is => 'ro', isa => Bool, coerce => 1, default => 1); |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
############################################################################# |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
has _content => ( |
|
43
|
|
|
|
|
|
|
traits => [ 'Array' ], is => 'ro', isa => 'ArrayRef[Str]', lazy_build => 1, |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
handles => { |
|
46
|
|
|
|
|
|
|
has_content => 'count', |
|
47
|
|
|
|
|
|
|
num_lines_in_content => 'count', |
|
48
|
|
|
|
|
|
|
grep_content => 'grep', |
|
49
|
|
|
|
|
|
|
content => 'elements', |
|
50
|
|
|
|
|
|
|
}, |
|
51
|
|
|
|
|
|
|
); |
|
52
|
|
|
|
|
|
|
|
|
53
|
0
|
|
|
0
|
|
|
sub _build__content { [ split /\n/, shift->specfile->slurp ] } |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
has license => (is => 'ro', isa => 'Str', lazy_build => 1); |
|
56
|
|
|
|
|
|
|
has epoch => (is => 'ro', isa => 'Maybe[Str]', lazy_build => 1); |
|
57
|
|
|
|
|
|
|
has version => (is => 'ro', isa => 'Str', lazy_build => 1); |
|
58
|
|
|
|
|
|
|
has release => (is => 'ro', isa => 'Str', lazy_build => 1); |
|
59
|
|
|
|
|
|
|
has summary => (is => 'ro', isa => 'Str', lazy_build => 1); |
|
60
|
|
|
|
|
|
|
has source0 => (is => 'ro', isa => 'Str', lazy_build => 1); |
|
61
|
|
|
|
|
|
|
has name => (is => 'ro', isa => 'Str', lazy_build => 1); |
|
62
|
|
|
|
|
|
|
# FIXME should we be a Uri type? |
|
63
|
|
|
|
|
|
|
has url => (is => 'ro', isa => 'Str', lazy_build => 1); |
|
64
|
|
|
|
|
|
|
|
|
65
|
0
|
|
|
0
|
|
|
sub _build_license { shift->_find(sub { /^License:/i }) } |
|
|
0
|
|
|
0
|
|
|
|
|
66
|
0
|
|
|
0
|
|
|
sub _build_epoch { shift->_find(sub { /^Epoch:/i }) } |
|
|
0
|
|
|
0
|
|
|
|
|
67
|
0
|
|
|
0
|
|
|
sub _build_version { shift->_find(sub { /^Version:/i }) } |
|
|
0
|
|
|
0
|
|
|
|
|
68
|
0
|
|
|
0
|
|
|
sub _build_release { shift->_find(sub { /^Release:/i }) } |
|
|
0
|
|
|
0
|
|
|
|
|
69
|
0
|
|
|
0
|
|
|
sub _build_summary { shift->_find(sub { /^Summary:/i }) } |
|
|
0
|
|
|
0
|
|
|
|
|
70
|
0
|
|
|
0
|
|
|
sub _build_source0 { shift->_find(sub { /^Source(0|):/i }) } |
|
|
0
|
|
|
0
|
|
|
|
|
71
|
0
|
|
|
0
|
|
|
sub _build_name { shift->_find(sub { /^Name:/i }) } |
|
|
0
|
|
|
0
|
|
|
|
|
72
|
0
|
|
|
0
|
|
|
sub _build_url { shift->_find(sub { /^URL:/i }) } |
|
|
0
|
|
|
0
|
|
|
|
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# LineToken: value_returned |
|
75
|
0
|
|
|
0
|
|
|
sub _find { (split /\s+/, (shift->grep_content(shift))[0], 2)[1] } |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
has _build_requires => ( |
|
78
|
|
|
|
|
|
|
traits => [ 'Hash' ], is => 'ro', isa => 'HashRef', lazy_build => 1, |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
handles => { |
|
81
|
|
|
|
|
|
|
has_build_requires => 'count', |
|
82
|
|
|
|
|
|
|
has_build_require => 'exists', |
|
83
|
|
|
|
|
|
|
build_require_version => 'get', |
|
84
|
|
|
|
|
|
|
num_build_requires => 'count', |
|
85
|
|
|
|
|
|
|
build_requires => 'keys', |
|
86
|
|
|
|
|
|
|
full_build_requires => 'elements', |
|
87
|
|
|
|
|
|
|
}, |
|
88
|
|
|
|
|
|
|
); |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub _build__build_requires { |
|
91
|
0
|
|
|
0
|
|
|
my $self = shift @_; |
|
92
|
|
|
|
|
|
|
|
|
93
|
0
|
|
|
|
|
|
my %brs = |
|
94
|
0
|
0
|
|
|
|
|
map { my @p = split /\s+/, $_; $p[0] => $p[2] ? $p[2] : 0 } |
|
|
0
|
|
|
|
|
|
|
|
95
|
0
|
|
|
|
|
|
map { $_ =~ s/^BuildRequires:\s*//; $_ } |
|
96
|
0
|
|
|
0
|
|
|
$self->grep_content(sub { /^BuildRequires:/i } ) |
|
97
|
0
|
|
|
|
|
|
; |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
### %brs |
|
100
|
0
|
|
|
|
|
|
return \%brs; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
has _requires => ( |
|
104
|
|
|
|
|
|
|
traits => [ 'Hash' ], is => 'ro', isa => 'HashRef', lazy_build => 1, |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
handles => { |
|
107
|
|
|
|
|
|
|
has_requires => 'count', |
|
108
|
|
|
|
|
|
|
has_require => 'exists', |
|
109
|
|
|
|
|
|
|
require_version => 'get', |
|
110
|
|
|
|
|
|
|
num_requires => 'count', |
|
111
|
|
|
|
|
|
|
requires => 'keys', |
|
112
|
|
|
|
|
|
|
full_requires => 'elements', |
|
113
|
|
|
|
|
|
|
}, |
|
114
|
|
|
|
|
|
|
); |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub _build__requires { |
|
117
|
0
|
|
|
0
|
|
|
my $self = shift @_; |
|
118
|
|
|
|
|
|
|
|
|
119
|
0
|
|
|
|
|
|
my %brs = |
|
120
|
0
|
0
|
|
|
|
|
map { my @p = split /\s+/, $_; $p[0] => $p[2] ? $p[2] : 0 } |
|
|
0
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
|
map { $_ =~ s/^Requires:\s*//; $_ } |
|
122
|
0
|
|
|
0
|
|
|
$self->grep_content(sub { /^Requires:/i } ) |
|
123
|
0
|
|
|
|
|
|
; |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# only one "magic" requires at the moment |
|
126
|
0
|
0
|
|
|
|
|
delete $brs{'perl(:MODULE_COMPAT_%(eval'} if $self->filter_magic; |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
### %brs |
|
129
|
0
|
|
|
|
|
|
return \%brs; |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
has _middle => ( |
|
133
|
|
|
|
|
|
|
traits => ['Array'], is => 'ro', isa => 'ArrayRef[Str]', lazy_build => 1, |
|
134
|
|
|
|
|
|
|
handles => { middle => 'elements' }, |
|
135
|
|
|
|
|
|
|
); |
|
136
|
|
|
|
|
|
|
|
|
137
|
0
|
|
|
0
|
|
|
sub _build__middle { [ _after('%description', _before('%changelog', shift->content)) ] } |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
has _changelog => ( |
|
140
|
|
|
|
|
|
|
traits => ['Array'], is => 'ro', isa => 'ArrayRef[Str]', lazy_build => 1, |
|
141
|
|
|
|
|
|
|
handles => { |
|
142
|
|
|
|
|
|
|
has_changelog => 'count', |
|
143
|
|
|
|
|
|
|
grep_changelog => 'grep', |
|
144
|
|
|
|
|
|
|
num_lines_in_changelog => 'count', |
|
145
|
|
|
|
|
|
|
changelog => 'elements', |
|
146
|
|
|
|
|
|
|
}, |
|
147
|
|
|
|
|
|
|
); |
|
148
|
|
|
|
|
|
|
|
|
149
|
0
|
|
|
0
|
|
|
sub _build__changelog { [ _after('%changelog', shift->content) ] } |
|
150
|
|
|
|
|
|
|
|
|
151
|
0
|
0
|
|
0
|
|
|
sub _before { my $sep = shift @_; my @l; do { return @l if /^$sep/; push @l, $_ } for @_ } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
152
|
0
|
|
|
0
|
|
|
sub _after { reverse _before(shift, reverse @_) } |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
__END__ |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=head1 NAME |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
RPM::Spec - A very simplistic read-only method of accessing RPM spec files |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
use RPM::Spec; |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
my $spec = RPM::Spec->new('path/to/my.spec'); |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
say 'Version is: ' . $spec->version; |
|
170
|
|
|
|
|
|
|
say 'Spec has an epoch' if $spec->has_epoch; |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
B<WARNING: This code is actively being worked on, and the API may change.> |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
RPM::Spec provides simplistic access to the different bits of information a |
|
177
|
|
|
|
|
|
|
spec file provides... It is basically a collection of different parsing |
|
178
|
|
|
|
|
|
|
routines that were scattered through a bunch of other modules. |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=head1 CLASS FUNCTIONS |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=over 4 |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=item B<new(specfile =E<gt> [Str|File])> |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Create a new RPM::Specfile object. The only required parameter is 'specfile', |
|
187
|
|
|
|
|
|
|
which is either a string or L<Path::Class::File> object pointing to the |
|
188
|
|
|
|
|
|
|
location of the specfile. |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=back |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=head1 METHODS |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head2 Tag Functions |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
These methods each return the value of the given tag. If the tag is not |
|
197
|
|
|
|
|
|
|
present, undef is returned. |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=over 4 |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=item B<license> |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=item B<epoch> |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=item B<release> |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=item B<version> |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=item B<source0> |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
Note this will pick up from either of "Source" or "Source0" tags. |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=item B<name> |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=item B<url> |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=item B<summary> |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=item B<middle> |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
The "middle" of a spec; e.g. everything from the first %description until the |
|
222
|
|
|
|
|
|
|
changelog starts. |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=back |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head2 Dependency Functions |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Documentation as this interface is likely to change in the Very Near Future. |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=head2 Content Functions |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=over 4 |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=item B<content()> |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
Returns an array of strings representing the specfile. |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=item B<has_content> |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Is the file empty? |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=item B<num_lines_in_content> |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
Returns the line count of the specfile. |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=item B<grep_content(sub { ... })> |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
Given a coderef, greps through the content with it. See also L<grep>. |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=back |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=head1 CAVEATS |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=head2 No macro parsing |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Macros are not evaluated. e.g., if "Release: 1%{?dist}" is in your spec file, |
|
257
|
|
|
|
|
|
|
"1%{?dist}" will be returned by release(). |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=head2 Read only! |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
We can't make any changes. |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
L<...> |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=head1 BUGS AND LIMITATIONS |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
Please report problems to Chris Weyl <cweyl@alumni.drew.edu>, or (preferred) |
|
270
|
|
|
|
|
|
|
to this package's RT tracker at <bug-RPM-Spec@rt.cpan.org>. |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
Patches are welcome. |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head1 AUTHOR |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
Chris Weyl <cweyl@alumni.drew.edu> |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
Copyright (c) 2009 Chris Weyl <cweyl@alumni.drew.edu> |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or |
|
284
|
|
|
|
|
|
|
modify it under the terms of the GNU Lesser General Public |
|
285
|
|
|
|
|
|
|
License as published by the Free Software Foundation; either |
|
286
|
|
|
|
|
|
|
version 2.1 of the License, or (at your option) any later version. |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful, |
|
289
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
290
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
291
|
|
|
|
|
|
|
Lesser General Public License for more details. |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public |
|
294
|
|
|
|
|
|
|
License along with this library; if not, write to the |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
Free Software Foundation, Inc. |
|
297
|
|
|
|
|
|
|
59 Temple Place, Suite 330 |
|
298
|
|
|
|
|
|
|
Boston, MA 02111-1307 USA |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=cut |
|
301
|
|
|
|
|
|
|
|