File Coverage

lib/CPAN/Patches.pm
Criterion Covered Total %
statement 80 111 72.0
branch 10 26 38.4
condition 6 18 33.3
subroutine 17 20 85.0
pod 9 9 100.0
total 122 184 66.3


line stmt bran cond sub pod time code
1             package CPAN::Patches;
2              
3 3     3   1116597 use warnings;
  3         32  
  3         246  
4 3     3   27 use strict;
  3         7  
  3         265  
5              
6             our $VERSION = '0.05';
7              
8 3     3   2143 use Moose;
  3         1317442  
  3         21  
9 3     3   18609 use CPAN::Patches::SPc;
  3         8  
  3         46  
10 3     3   63 use Carp;
  3         13  
  3         143  
11 3     3   13 use IO::Any;
  3         4  
  3         27  
12 3     3   34 use JSON::Util;
  3         3  
  3         23  
13 3     3   1349 use YAML::Syck;
  3         4577  
  3         227  
14 3     3   897 use File::chdir;
  3         4841  
  3         425  
15 3     3   19 use Scalar::Util 'blessed';
  3         3  
  3         147  
16 3     3   1394 use Module::Pluggable require => 1;
  3         17292  
  3         18  
17              
18             has 'patch_set_locations' => (
19             is => 'rw',
20             isa => 'ArrayRef',
21             lazy => 1,
22             default => sub { [ File::Spec->catdir(CPAN::Patches::SPc->sharedstatedir, 'cpan-patches', 'set') ] }
23             );
24             has 'verbose' => ( is => 'rw', isa => 'Int', default => 1 );
25              
26             sub BUILD {
27 2     2 1 4 my $self = shift;
28            
29 2         3 my $pkg = __PACKAGE__;
30 2         8 foreach my $plugin ($self->plugins) {
31             # ignore nested package names, only one level
32 0 0       0 next if $plugin =~ m/^ $pkg :: Plugin :: [^:]+ ::/xms;
33 0         0 $plugin->meta->apply($self);
34             }
35             };
36              
37             sub patch {
38 2     2 1 8193 my $self = shift;
39 2   50     72 my $path = shift || '.';
40            
41 2 50       30 $self = $self->new()
42             if not blessed $self;
43            
44 2         10 local $CWD = $path;
45 2         89 my $name = $self->clean_meta_name();
46            
47 2         7 foreach my $patch_filename ($self->get_patch_series) {
48 3 50       212 print 'patching ', $name,' with ', $patch_filename, "\n"
49             if $self->verbose;
50 3 100       20630 system('cat '.$patch_filename.' | patch --quiet --force -p1') and die 'failed';
51             }
52            
53 1         56 return;
54             }
55              
56             sub cmd_list {
57 0     0 1 0 my $self = shift;
58 0         0 foreach my $patch_filename ($self->get_patch_series) {
59 0         0 print $patch_filename, "\n";
60             }
61             }
62              
63             sub cmd_patch {
64 0     0 1 0 shift->patch();
65             }
66              
67             sub get_patch_series {
68 3     3 1 7 my $self = shift;
69 3   33     13 my $name = shift || $self->clean_meta_name;
70            
71 3         9 my $patches_folder = File::Spec->catdir($self->get_module_folder($name), 'patches');
72 3         20 my $series_filename = File::Spec->catfile($patches_folder, 'series');
73              
74 3 50       48 return if not -r $series_filename;
75            
76             return
77 5         44 map { File::Spec->catfile($patches_folder, $_) }
  5         16  
78 5         7 map { s/^\s*//;$_; }
  5         30  
79 5         7 map { s/\s*$//;$_; }
  3         637  
80             map { split "\n" }
81 3         5 eval { IO::Any->slurp([$series_filename]) };
  3         31  
82             }
83              
84             sub get_module_folder {
85 4     4 1 71 my $self = shift;
86 4   66     16 my $name = shift || $self->clean_meta_name;
87            
88 4         5 foreach my $patch_set_location (@{$self->patch_set_locations}) {
  4         157  
89 8         42 my $folder = File::Spec->catdir($patch_set_location, $name);
90 8 100       215 return $folder
91             if -d $folder;
92             }
93            
94 0         0 return;
95             }
96              
97             sub clean_meta_name {
98 6     6 1 9 my $self = shift;
99 6   33     23 my $name = shift || $self->read_meta->{'name'};
100            
101 6         32 $name =~ s/::/-/xmsg;
102 6         38 $name =~ s/\s*$//;
103 6         14 $name =~ s/^\s*//;
104 6         14 $name = lc $name;
105              
106 6         15 return $name;
107             }
108              
109             sub read_meta {
110 6     6 1 8 my $self = shift;
111 6   50     22 my $path = shift || '.';
112            
113 6         67 my $yml = File::Spec->catfile($path, 'META.yml');
114 6         32 my $json = File::Spec->catfile($path, 'META.json');
115 6 50       56 if (-f $json) {
116 0         0 my $meta = eval { JSON::Util->decode([$json]) };
  0         0  
117 0 0       0 return $meta
118             if $meta;
119             }
120 6 50       53 if (-f $yml) {
121 6         8 my $meta = eval { YAML::Syck::LoadFile($yml) };
  6         28  
122 6 50       1006 return $meta
123             if $meta;
124             }
125 0           croak 'failed to read META.(yml|json)';
126             }
127              
128             sub read_meta_intrusive {
129 0     0 1   my $self = shift;
130 0   0       my $path = shift || '.';
131              
132 0           my $buildpl = File::Spec->catfile($path, 'Build.PL');
133 0           my $makefilepl = File::Spec->catfile($path, 'Makefile.PL');
134 0 0 0       if (-f $buildpl or -f $makefilepl) {
135 0           warn 'going to generate META.yml';
136            
137 0           my $meta;
138 0           my $distmeta = 'perl Makefile.PL && make distmeta && cp */META.yml ./';
139 0           my $distclean = 'make distclean';
140 0 0         if (-f $buildpl) {
141 0           $distmeta = 'perl Build.PL && ./Build distmeta';
142 0           $distclean = './Build distclean';
143             }
144            
145 0           do {
146 0           local $CWD = $path;
147 0           system($distmeta);
148 0           $meta = eval { $self->read_meta };
  0            
149 0           system($distclean);
150             };
151            
152 0 0         return $meta
153             if $meta;
154             }
155            
156 0           croak 'failed to read META.(yml|json)';
157             }
158              
159             __PACKAGE__->meta->make_immutable;
160              
161             1;
162              
163              
164             __END__
165              
166             =encoding utf8
167              
168             =head1 NAME
169              
170             CPAN::Patches - patch CPAN distributions
171              
172             =head1 SYNOPSIS
173              
174             cd Some-Distribution
175             cpan-patches list
176             cpan-patches patch
177             cpan-patches --patch-set $HOME/cpan-patches-set list
178             cpan-patches --patch-set $HOME/cpan-patches-set patch
179              
180             =head1 DESCRIPTION
181              
182             This module allows to apply custom patches to the CPAN distributions.
183              
184             See L</patch> and L</update_debian> for a detail description how.
185              
186             See L<http://github.com/jozef/CPAN-Patches-Example-Set> for example generated
187             Debian patches set folder.
188              
189             =head1 PROPERTIES
190              
191             =head2 patch_set_locations
192              
193             An array ref of folders where are the distribution patches located. Default is
194             F<< Sys::Path->sharedstatedir/cpan-patches/set >> which is
195             F</var/lib/cpan-patches/set> on Linux.
196              
197             =head2 verbose
198              
199             Turns on/off some verbose output. By default it is on.
200              
201             =head1 METHODS
202              
203             =head2 new()
204              
205             Object constructor.
206              
207             =head2 BUILD
208              
209             All plugins (Moose roles) from C<CPAN::Patches::Plugin::*> will be loaded.
210              
211             =head2 patch
212              
213             Apply all patches that are listed in F<.../module-name/patches/series>.
214              
215             =head1 cpan-patch commands
216              
217             =head2 cmd_list
218              
219             Print out list of all patches files.
220              
221             =head2 cmd_patch
222              
223             Apply all patches to the current CPAN distribution.
224              
225             =head1 INTERNAL METHODS
226              
227             =head2 get_patch_series($module_name)
228              
229             Return an array of patches filenames for given C<$module_name>.
230              
231             =head2 get_module_folder($module_name)
232              
233             Returns a folder that exists in one of the C<patch_set_locations> for a
234             given C<$module_name>.
235              
236             =head2 clean_meta_name($name)
237              
238             Returns lowercased :: by - substituted and trimmed module name.
239              
240             =head2 read_meta([$path])
241              
242             Reads a F<META.yml> or F<META.json> from C<$path>. If C<$path> is not provided
243             than tries to read from current folder.
244              
245             =head2 read_meta_intrusive
246              
247             Generates and reads the F<META.yml> using F<Build.PL> or F<Makefile.PL>.
248              
249             =head1 CONTRIBUTORS
250              
251             The following people have contributed to the CPAN::Patches by committing their
252             code, sending patches, reporting bugs, asking questions, suggesting useful
253             advises, nitpicking, chatting on IRC or commenting on my blog (in no particular
254             order):
255              
256             Slaven Rezić
257              
258             =head1 AUTHOR
259              
260             jozef@kutej.net, C<< <jkutej at cpan.org> >>
261              
262             =head1 BUGS
263              
264             Please report any bugs or feature requests to C<bug-cpan-patches at rt.cpan.org>, or through
265             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=CPAN-Patches>. I will be notified, and then you'll
266             automatically be notified of progress on your bug as I make changes.
267              
268              
269              
270              
271             =head1 SUPPORT
272              
273             You can find documentation for this module with the perldoc command.
274              
275             perldoc CPAN::Patches
276              
277              
278             You can also look for information at:
279              
280             =over 4
281              
282             =item * RT: CPAN's request tracker
283              
284             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=CPAN-Patches>
285              
286             =item * AnnoCPAN: Annotated CPAN documentation
287              
288             L<http://annocpan.org/dist/CPAN-Patches>
289              
290             =item * CPAN Ratings
291              
292             L<http://cpanratings.perl.org/d/CPAN-Patches>
293              
294             =item * Search CPAN
295              
296             L<http://search.cpan.org/dist/CPAN-Patches/>
297              
298             =back
299              
300              
301             =head1 ACKNOWLEDGEMENTS
302              
303              
304             =head1 LICENSE AND COPYRIGHT
305              
306             This program is free software; you can redistribute it and/or modify it
307             under the terms of either: the GNU General Public License as published
308             by the Free Software Foundation; or the Artistic License.
309              
310             See http://dev.perl.org/licenses/ for more information.
311              
312              
313             =cut
314              
315             1; # End of CPAN::Patches