File Coverage

blib/lib/RPM/Spec.pm
Criterion Covered Total %
statement 15 58 25.8
branch 0 8 0.0
condition n/a
subroutine 5 31 16.1
pod n/a
total 20 97 20.6


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