File Coverage

blib/lib/Dist/Zilla/Plugin/RPM.pm
Criterion Covered Total %
statement 40 87 45.9
branch 0 16 0.0
condition 2 6 33.3
subroutine 12 17 70.5
pod 0 3 0.0
total 54 129 41.8


line stmt bran cond sub pod time code
1             package Dist::Zilla::Plugin::RPM;
2             # ABSTRACT: Build an RPM from your Dist::Zilla release
3              
4 1     1   2717349 use Moose;
  1         3  
  1         7  
5 1     1   6384 use Moose::Autobox;
  1         166301  
  1         6  
6 1     1   711 use Moose::Util::TypeConstraints;
  1         2  
  1         9  
7 1     1   2186 use Path::Tiny;
  1         2  
  1         56  
8 1     1   7 use namespace::autoclean;
  1         1  
  1         9  
9              
10             our $VERSION = '0.014'; # VERSION
11              
12             with 'Dist::Zilla::Role::Releaser',
13             'Dist::Zilla::Role::FilePruner';
14              
15             has spec_file => (
16             is => 'ro',
17             isa => 'Str',
18             default => 'build/dist.spec',
19             );
20              
21             has build => (
22             is => 'ro',
23             isa => enum([qw/source all/]),
24             default => 'all',
25             );
26              
27             has sign => (
28             is => 'ro',
29             isa => 'Bool',
30             default => 0,
31             );
32              
33             has ignore_build_deps => (
34             is => 'ro',
35             isa => 'Bool',
36             default => 0,
37             );
38              
39             has push_packages => ( is => 'ro', isa => 'Bool', default => 0 );
40             has push_command => ( is => 'ro', isa => 'Str', default => 'rhnpush -s' );
41              
42 1         1 use constant _CoercedRegexp => do {
43 1         5 my $tc = subtype as 'RegexpRef';
44 1         1480 coerce $tc, from 'Str', via { qr/$_/ };
  1         83  
45 1         750 $tc;
46 1     1   242 };
  1         3  
47              
48             has push_ignore_packages => (
49             is => 'ro', isa => _CoercedRegexp, coerce => 1, default => '.src.rpm$' );
50              
51 1     1   6 use Carp;
  1         3  
  1         51  
52 1     1   6 use File::Temp ();
  1         1  
  1         17  
53 1     1   561 use Path::Class qw(dir);
  1         11951  
  1         53  
54 1     1   9 use Text::Template ();
  1         2  
  1         15  
55 1     1   745 use IPC::Run;
  1         21390  
  1         1066  
56              
57             sub prune_files {
58 0     0 0 0 my($self) = @_;
59 0         0 my $spec = $self->spec_file;
60 0         0 for my $file ($self->zilla->files->flatten) {
61 0 0       0 if ($file->name eq $self->spec_file) {
62 0         0 $self->zilla->prune_file($file);
63             }
64             }
65 0         0 return;
66             }
67              
68             has '_rpmbuild_options' => (
69             is => 'ro', isa => 'ArrayRef[Str]', lazy => 1,
70             default => sub {
71             my $self = shift;
72             return( [
73             $self->sign ? '--sign' : (),
74             $self->ignore_build_deps ? '--nodeps' : (),
75             ] );
76             },
77             );
78              
79             has '_rpmbuild_stage' => (
80             is => 'ro', isa => 'Str', lazy => 1,
81             default => sub {
82             my $self = shift;
83              
84             if ($self->build eq 'source') {
85             return('-bs');
86             } elsif ($self->build eq 'all') {
87             return('-ba');
88             }
89              
90             $self->log_fatal(q{invalid build type }.$self->build);
91             },
92             );
93              
94             has '_rpmbuild_command' => (
95             is => 'ro',
96             isa => 'ArrayRef[Str]',
97             lazy => 1,
98             default => sub {
99             my $self = shift;
100             return( [
101             'rpmbuild',
102             $self->_rpmbuild_stage,
103             @{$self->_rpmbuild_options},
104             $self->_tmpspecfile->stringify,
105             ] );
106             },
107             );
108              
109             has '_tmpdir' => (
110             is => 'ro', isa => 'File::Temp::Dir', lazy => 1,
111             default => sub {
112             my $self = shift;
113             return File::Temp->newdir();
114             },
115             );
116              
117             has '_tmpspecfile' => (
118             is => 'ro', isa => 'Path::Class::File', lazy => 1,
119             default => sub {
120             my $self = shift;
121             return dir($self->_tmpdir)->file($self->zilla->name . '.spec');
122             },
123             );
124              
125             sub _write_spec {
126 0     0   0 my ($self, $archive) = @_;
127 0         0 my $fh = $self->_tmpspecfile->openw();
128 0         0 $fh->print($self->mk_spec($archive));
129 0         0 $fh->flush;
130 0         0 $fh->close;
131 0         0 return;
132             }
133              
134             has '_sourcedir' => (
135             is => 'ro', isa => 'Str', lazy => 1,
136             default => sub {
137             my $self = shift;
138             my $sourcedir = qx/rpm --eval '%{_sourcedir}'/
139             or $self->log_fatal(q{couldn't determine RPM sourcedir});
140             $sourcedir =~ s/[\r\n]+$//;
141             $sourcedir .= '/';
142              
143             unless( -d $sourcedir) {
144             $sourcedir = "$self->_tmpdir";
145             }
146              
147             return($sourcedir);
148             },
149             );
150              
151             sub release {
152 0     0 0 0 my($self,$archive) = @_;
153              
154 0         0 $self->_write_spec($archive);
155              
156 0 0       0 if(! -f $archive ) {
157 0         0 $self->log_fatal('archive '.$archive.' does not exist!');
158             }
159              
160 0 0       0 system('cp',$archive,$self->_sourcedir)
161             && $self->log_fatal('cp failed');
162              
163 0 0       0 if ($ENV{DZIL_PLUGIN_RPM_TEST}) {
164 0         0 $self->log("test: would have executed ".join(' ', @{$self->_rpmbuild_command}));
  0         0  
165 0         0 return;
166             }
167              
168 0         0 $self->_execute_rpmbuild;
169 0         0 $self->log('RPMs build: '.join(', ', @{$self->_packages_build} ));
  0         0  
170              
171 0 0       0 if( $self->push_packages ) {
172 0         0 $self->_execute_push_command;
173             }
174              
175 0         0 return;
176             }
177              
178             has '_packages_build' => ( is => 'ro', isa => 'ArrayRef[Str]', lazy => 1,
179             default => sub { [] }
180             );
181              
182             sub _execute_rpmbuild {
183 0     0   0 my $self = shift;
184 0         0 my ($in, $out, $err);
185 0         0 my $lang = $ENV{'LANG'};
186 0         0 $ENV{'LANG'} = 'C';
187 0         0 $self->log('building RPM...');
188 0 0       0 IPC::Run::run( $self->_rpmbuild_command, \$in, \$out, \$err )
189             or $self->log_fatal('rpmbuild failed: '.$err);
190 0         0 foreach my $line ( split(/\n/, $out ) ) {
191 0 0       0 if( $line =~ m/^Wrote: (.*)$/) {
192 0         0 push(@{$self->_packages_build}, $1);
  0         0  
193             }
194             }
195 0         0 $ENV{'LANG'} = $lang;
196 0         0 return;
197             }
198              
199             has _packages_to_push => (
200             is => 'ro', isa => 'ArrayRef[Str]', lazy => 1,
201             default => sub {
202             my $self = shift;
203             my $regex = $self->push_ignore_packages;
204             return( [ grep { $_ !~ m/$regex/ } @{$self->_packages_build} ] );
205             },
206             );
207              
208             has _push_command => (
209             is => 'ro', isa => 'ArrayRef', lazy => 1,
210             default => sub {
211             my $self = shift;
212             return( [ split(/ /, $self->push_command) ] );
213             },
214             );
215              
216             sub _execute_push_command {
217 0     0   0 my $self = shift;
218 0         0 my ($in, $out, $err);
219              
220 0         0 $in = join("\n", @{$self->_packages_to_push});
  0         0  
221              
222 0         0 $self->log('pushing packages: '.join(', ', @{$self->_packages_to_push}));
  0         0  
223 0 0       0 IPC::Run::run( $self->_push_command, \$in, \$out, $err )
224             or $self->log_fatal('push command failed: '.$err);
225              
226 0         0 return;
227             }
228              
229             sub mk_spec {
230 1     1 0 52779 my($self,$archive) = @_;
231 1   33     26 my $t = Text::Template->new(
232             TYPE => 'FILE',
233             SOURCE => path($self->zilla->root)->child($self->spec_file),
234             DELIMITERS => [ '<%', '%>' ],
235             ) || $self->log_fatal($Text::Template::ERROR);
236 1   33     364 return $t->fill_in(
237             HASH => {
238             zilla => \($self->zilla),
239             archive => \$archive,
240             },
241             ) || $self->log_fatal($Text::Template::ERROR);
242             }
243              
244             __PACKAGE__->meta->make_immutable;
245              
246              
247             1;
248              
249             __END__
250              
251             =pod
252              
253             =encoding UTF-8
254              
255             =head1 NAME
256              
257             Dist::Zilla::Plugin::RPM - Build an RPM from your Dist::Zilla release
258              
259             =head1 VERSION
260              
261             version 0.014
262              
263             =head1 SYNOPSIS
264              
265             In your dist.ini:
266              
267             [RPM]
268             spec_file = build/dist.spec
269             sign = 1
270             ignore_build_deps = 0
271              
272             push_packages = 0
273             push_command = rhnpush -s
274             push_ignore_packages = .src.rpm$
275              
276             After adding the [RPM] section to the dist.ini file, the mkrpmspec command will be available. Running this command allow you to make the dzil.spec file from the template. Then dzil release will build the RPM file.
277              
278             It keeps track of build RPM files and can be used to push generated
279             packages into a repository.
280              
281             =head1 DESCRIPTION
282              
283             This plugin is a Releaser for Dist::Zilla that builds an RPM of your
284             distribution.
285              
286             =head1 ATTRIBUTES
287              
288             =over
289              
290             =item spec_file (default: "build/dist.spec")
291              
292             The spec file to use to build the RPM.
293              
294             The spec file is run through L<Text::Template|Text::Template> before calling
295             rpmbuild, so you can substitute values from Dist::Zilla into the final output.
296             The template uses <% %> tags (like L<Mason|Mason>) as delimiters to avoid
297             conflict with standard spec file markup.
298              
299             Two variables are available in the template:
300              
301             =over
302              
303             =item $zilla
304              
305             The main Dist::Zilla object
306              
307             =item $archive
308              
309             The filename of the release tarball
310              
311             =back
312              
313             =item sign (default: False)
314              
315             If set to a true value, rpmbuild will be called with the --sign option.
316              
317             =back
318              
319             =over
320              
321             =item ignore_build_deps (default: False)
322              
323             If set to a true value, rpmbuild will be called with the --nodeps option.
324              
325             =item push_packages (default: false)
326              
327             This allowes you to specify a command to push your generated RPM packages to a repository.
328             RPM filenames are writen one-per-line to stdin.
329              
330             =item push_command (default: rhnpush -s)
331              
332             Command used to push packages.
333              
334             =item push_ignore_packages (default: .src.rpm$)
335              
336             A regular expression for packages which should NOT be pushed.
337              
338             =back
339              
340             =head1 SAMPLE SPEC FILE TEMPLATE
341              
342             Name: <% $zilla->name %>
343             Version: <% (my $v = $zilla->version) =~ s/^v//; $v %>
344             Release: 1
345              
346             Summary: <% $zilla->abstract %>
347             License: GPL+ or Artistic
348             Group: Applications/CPAN
349             BuildArch: noarch
350             URL: <% $zilla->license->url %>
351             Source: <% $archive %>
352            
353             BuildRoot: %{_tmppath}/%{name}-%{version}-BUILD
354            
355             %description
356             <% $zilla->abstract %>
357            
358             %prep
359             %setup -q
360            
361             %build
362             perl Makefile.PL
363             make test
364            
365             %install
366             if [ "%{buildroot}" != "/" ] ; then
367             rm -rf %{buildroot}
368             fi
369             make install DESTDIR=%{buildroot}
370             find %{buildroot} | sed -e 's#%{buildroot}##' > %{_tmppath}/filelist
371            
372             %clean
373             if [ "%{buildroot}" != "/" ] ; then
374             rm -rf %{buildroot}
375             fi
376            
377             %files -f %{_tmppath}/filelist
378             %defattr(-,root,root)
379              
380             =head1 SEE ALSO
381              
382             L<Dist::Zilla|Dist::Zilla>
383              
384             =head1 AUTHOR
385              
386             Vincent Lequertier <vi.le@autistici.org>
387              
388             =head1 COPYRIGHT AND LICENSE
389              
390             This software is copyright (c) 2017 by vincent Lequertier, Stephen Clouse.
391              
392             This is free software; you can redistribute it and/or modify it under
393             the same terms as the Perl 5 programming language system itself.
394              
395             =cut