File Coverage

blib/lib/Software/Packager/Rpm.pm
Criterion Covered Total %
statement 112 189 59.2
branch 29 72 40.2
condition n/a
subroutine 20 22 90.9
pod 11 11 100.0
total 172 294 58.5


line stmt bran cond sub pod time code
1             ################################################################################
2             # Name: Software::Packager::RPM.pm
3             # Description: This module is used to package software into Redhat's RPM
4             # Package Format.
5             # Author: Bernard Davison
6             # Contact: rbdavison@cpan.org
7             #
8              
9             package Software::Packager::Rpm;
10              
11             ####################
12             # Standard Modules
13 1     1   875 use strict;
  1         2  
  1         30  
14 1     1   5 use File::Path;
  1         1  
  1         49  
15 1     1   899 use File::Copy;
  1         2274  
  1         51  
16 1     1   6 use File::Basename;
  1         1  
  1         60  
17 1     1   4 use Cwd;
  1         1  
  1         48  
18             # Custom modules
19 1     1   5 use Software::Packager;
  1         2  
  1         15  
20 1     1   615 use Software::Packager::Object::Rpm;
  1         2  
  1         24  
21              
22             ####################
23             # Variables
24 1     1   4 use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
  1         2  
  1         2454  
25             @ISA = qw( Software::Packager );
26             @EXPORT = qw();
27             @EXPORT_OK = qw();
28             $VERSION = 0.06;
29              
30             ####################
31             # Functions
32              
33             ################################################################################
34             # Function: new()
35             # Description: This function creates and returns a new Packager object.
36             # Arguments: none.
37             # Return: new Packager object.
38             #
39             sub new
40             {
41 1     1 1 7 my $class = shift;
42 1         3 my $self = bless {}, $class;
43              
44 1         8 return $self;
45             }
46              
47             ################################################################################
48             # Function: add_item()
49              
50             =head2 B
51              
52             my %object_data = (
53             'SOURCE' => '/source/file1',
54             'TYPE' => 'file',
55             'KIND' => 'doc',
56             'DESTINATION' => '/usr/local/file1',
57             'USER' => 'joe',
58             'GROUP' => 'staff',
59             'MODE' => 0750,
60             );
61             $packager->add_item(%object_data);
62              
63             This method overrides the add_item method in Software::Packager. It adds the
64             ability to add extra features used by RPM for each object in the package.
65              
66             For more details see the documentation in:
67             Software::Packager
68             Software::Packager::Object::Rpm
69              
70             =cut
71             sub add_item
72             {
73 12     12 1 1282 my $self = shift;
74 12         41 my %data = @_;
75 12         99 my $object = new Software::Packager::Object::Rpm(%data);
76              
77 12 50       1050 return undef unless $object;
78              
79             # check that the object has a unique destination
80 12 50       40 return undef if $self->{'OBJECTS'}->{$object->destination()};
81              
82 12         98 $self->{'OBJECTS'}->{$object->destination()} = $object;
83             }
84              
85             ################################################################################
86             # Function: program_name()
87              
88             =head2 B
89              
90             $packager->program_name('SoftwarePackager');
91             my $program_name = $packager->program_name();
92              
93             This method is used to set the name of the program that the package is
94             installing. This may in should be the same as the package name but that is
95             not required.
96             It must not contain spaces or a dash "-" and must be all on one line.
97              
98             =cut
99             sub program_name
100             {
101 4     4 1 33 my $self = shift;
102 4         5 my $value = shift;
103              
104 4 100       7 if ($value)
105             {
106 1 50       6 if ($value =~ /\s|-|\n/)
107             {
108 1         19 warn "Warning: The program name passed contains invalid charaters. Removing them\n";
109 1         8 $value =~ s/\s|-|\n//g;
110             }
111 1         3 $self->{'PROGRAM_NAME'} = $value;
112             }
113             else
114             {
115 3         13 return $self->{'PROGRAM_NAME'};
116             }
117             }
118              
119             ################################################################################
120             # Function: version()
121              
122             =head2 B
123              
124             $packager->version(1.2.3.4.5.6);
125             my $version = $packager->version();
126              
127             This method sets the version for the package to the passed value.
128             The version passed cannot contain a dash "-" or spaces and must be on one line.
129              
130             =cut
131             sub version
132             {
133 5     5 1 83 my $self = shift;
134 5         9 my $value = shift;
135              
136 5 100       9 if ($value)
137             {
138 2 100       10 if ($value =~ /\s|-|\n/)
139             {
140 1         13 warn "Warning: The version passed contains invalid charaters. Removing them\n";
141 1         7 $value =~ s/\s|-|\n//g;
142             }
143 2         10 $self->{'PACKAGE_VERSION'} = $value;
144             }
145             else
146             {
147 3         9 return $self->{'PACKAGE_VERSION'};
148             }
149             }
150              
151             ################################################################################
152             # Function: release()
153              
154             =head2 B
155              
156             This method sets the release version for the package.
157             The release is the number of times the package has been recreated.
158             If the release is not set then a default of 1 is used.
159             It cannot contain spaces, a dash or new lines.
160              
161             =cut
162             sub release
163             {
164 2     2 1 5 my $self = shift;
165 2         3 my $value = shift;
166              
167 2 50       4 if ($value)
168             {
169 0 0       0 if ($value =~ /\s|-|\n/)
170             {
171 0         0 warn "Warning: The release passed contains invalid charaters. Removing them\n";
172 0         0 $value =~ s/\s|-|\n//g;
173             }
174 0         0 $self->{'RELEASE'} = $value;
175             }
176             else
177             {
178 2 100       13 unless ($self->{'RELEASE'})
179             {
180 1         2 $self->{'RELEASE'} = 1;
181             }
182 2         10 return $self->{'RELEASE'};
183             }
184             }
185              
186             ################################################################################
187             # Function: copyright()
188              
189             =head2 B
190              
191             This method sets the copyright type for the package.
192             This should be the name of the copyright
193              
194             =cut
195             sub copyright
196             {
197 2     2 1 10 my $self = shift;
198 2         14 my $value = shift;
199              
200 2 100       20 if ($value)
201             {
202 1 50       17 if ($value =~ /\n/)
203             {
204 0         0 warn "Warning: The copyright contains new lines. Removing them\n";
205 0         0 $value =~ s/\n//g;
206             }
207 1         9 $self->{'COPYRIGHT'} = $value;
208             }
209             else
210             {
211 1         7 return $self->{'COPYRIGHT'};
212             }
213             }
214              
215             ################################################################################
216             # Function: source()
217              
218             =head2 B
219              
220             This method sets the source location for the package. This should be the URL for
221             the source package used to create this package.
222              
223             =cut
224             sub source
225             {
226 2     2 1 118 my $self = shift;
227 2         4 my $value = shift;
228              
229 2 100       15 if ($value)
230             {
231 1         9 $self->{'SOURCE'} = $value;
232             }
233             else
234             {
235 1         11 return $self->{'SOURCE'};
236             }
237             }
238              
239             ################################################################################
240             # Function: architecture()
241              
242             =head2 B
243              
244             $packager->architecture("sparc");
245             my $arch = $packager->architecture();
246              
247             This method sets the architecture for the package to the passed value. If no
248             argument is passed then the current architecture is returned.
249             This is the output "from uname -p"
250              
251             =cut
252             sub architecture
253             {
254 3     3 1 3888 my $self = shift;
255 3         8 my $value = shift;
256              
257 3 100       28 if ($value)
258             {
259 1         20 $self->{'ARCHITECTURE'} = $value;
260             }
261             else
262             {
263 2 100       11 unless ($self->{'ARCHITECTURE'})
264             {
265 1         6568 $self->{'ARCHITECTURE'} = `uname -m`;
266 1         48 $self->{'ARCHITECTURE'} =~ s/\n//g;
267             }
268 2         37 return $self->{'ARCHITECTURE'};
269             }
270             }
271              
272             ################################################################################
273             # Function: package_name()
274              
275             =head2 B
276              
277             my $name = $packager->package_name();
278            
279             This method returns the name of the package that will be created.
280              
281             =cut
282             sub package_name
283             {
284 1     1 1 7004 my $self = shift;
285             # my $value = shift;
286              
287             # if ($value)
288             # {
289             # $self->{'PACKAGE_NAME'} = $value;
290             # }
291             # else
292             # {
293             # return $self->{'PACKAGE_NAME'};
294             # }
295 1         21 my $package_name = $self->program_name();
296 1         11 $package_name .= "-";
297 1         12 $package_name .= $self->version();
298 1         2 $package_name .= "-";
299 1         8 $package_name .= $self->release();
300 1         3 $package_name .= ".";
301 1         16 $package_name .= $self->architecture();
302 1         6 $package_name .= ".rpm";
303              
304 1         172 return $package_name;
305             }
306              
307             ################################################################################
308             # Function: short_description()
309              
310             =head2 B
311              
312             $packager->short_description("This is a short description.");
313             my $description = $packager->short_description();
314            
315             The short description is just that a short description of the program.
316             It must be all on one line.
317              
318             =cut
319             sub short_description
320             {
321 2     2 1 72 my $self = shift;
322 2         5 my $value = shift;
323              
324 2 100       18 if ($value)
325             {
326 1 50       14 if ($value =~ /\n/)
327             {
328 0         0 warn "Warning: The short description contains new lines. Removing them\n";
329 0         0 $value =~ s/\n//g;
330             }
331 1         7 $self->{'SHORT_DESCRIPTION'} = $value;
332             }
333             else
334             {
335 1         4 return $self->{'SHORT_DESCRIPTION'};
336             }
337             }
338              
339             ################################################################################
340             # Extra documentation is added between here and the package method
341              
342             =head2 B
343              
344             $packager->description("This is the description.");
345             my $description = $packager->description();
346            
347             The description method sets the package description to the passed value. If no
348             arguments are passed the package description is returned.
349              
350             The discription can be of any length. It will be formatted by RPM in the
351             following way:
352              
353             =item *
354              
355             If a line starts with a space it will be printed verbatim.
356              
357             =item *
358              
359             A blank line signifies a new paragraph.
360              
361             =item *
362              
363             All other lines will be assumed to be part of a paragraph and will be formatted
364             by RPM.
365              
366             =cut
367              
368             ################################################################################
369             # Function: package()
370              
371             =head2 B
372              
373             This method creates the package and returns true if it is successful else it
374             returns undef
375              
376             =cut
377             sub package
378             {
379 1     1 1 21 my $self = shift;
380              
381 1 0       7 return undef unless $self->_setup_in_tmp();
382 0 0       0 return undef unless $self->_build_package();
383 0 0       0 return undef unless $self->_cleanup();
384 0         0 return 1;
385             }
386              
387             ################################################################################
388             # Function: _setup_in_tmp
389             # DEscription: This method sets up the package to before it is created
390             # Arguments: None.
391             # Returns: True on success else undef
392             #
393             sub _setup_in_tmp
394             {
395 1     1   3 my $self = shift;
396 1         2829 my $tmp_dir = $self->tmp_dir();
397            
398 1 50       23 unless (-d $tmp_dir)
399             {
400 1         486 mkpath("$tmp_dir", 0, 0755);
401             }
402 1         10 my $cwd = getcwd();
403 1         27 chdir $tmp_dir;
404 1         7 $tmp_dir = getcwd();
405 1         640 rmtree($tmp_dir, 0, 0);
406 1         5 $self->tmp_dir($tmp_dir);
407 1         123 chdir $cwd;
408 1 50       25 unless (-d $tmp_dir)
409             {
410 0         0 mkpath("$tmp_dir/BUILD", 0, 0755);
411 0         0 mkpath("$tmp_dir/RPMS", 0, 0755);
412 0         0 mkpath("$tmp_dir/SOURCES", 0, 0755);
413 0         0 mkpath("$tmp_dir/SPECS", 0, 0755);
414 0         0 mkpath("$tmp_dir/SRPMS", 0, 0755);
415             }
416              
417             # create the rpmrc
418 1 50       114 open (RPMRC, ">$tmp_dir/rpmrc") or
419             die "Error: Cannot open $tmp_dir/rpmrc: $!\n";
420 1         12167 my $macrofiles = `grep macrofiles /usr/lib/rpm/rpmrc`;
421 1         26 $macrofiles =~ s/\n//g;
422 1         19 print RPMRC "$macrofiles:$tmp_dir/rpmmacros\n";
423 1         113 close RPMRC;
424              
425             # create the rpmmacros
426 1 50       186 open (RPMMACROS, ">$tmp_dir/rpmmacros") or
427             die "Error: Cannot open $tmp_dir/rpmmacros: $!\n";
428 1         12 print RPMMACROS "\%_topdir $tmp_dir\n";
429 1         36 close RPMMACROS;
430              
431             # create the spec file
432 1 50         open (SPEC , ">$tmp_dir/SPECS/package.spec") or
433             die "Error: Cannot open $tmp_dir/SPECS/package.spec for writing: $!\n";
434              
435 0           print SPEC "Summary:" . $self->short_description() . "\n";
436 0           print SPEC "Name:" . $self->program_name() . "\n";
437 0           print SPEC "Version:" . $self->version() . "\n";
438 0           print SPEC "Release:" . $self->release() . "\n";
439 0           print SPEC "Copyright:" . $self->copyright() . "\n";
440 0           print SPEC "Group:" . $self->category() . "\n";
441 0           print SPEC "Source:" . $self->source() . "\n";
442 0           print SPEC "URL:" . $self->homepage() . "\n";
443 0           print SPEC "Vendor:" . $self->vendor() . "\n";
444 0           print SPEC "Packager:" . $self->creator() . "\n";
445 0           print SPEC "BuildRoot:$tmp_dir\n";
446 0 0         print SPEC "Prefix:". $self->install_dir() . "\n" if $self->install_dir();
447 0           print SPEC "\n";
448              
449 0           print SPEC "\%description\n" . $self->description() . "\n\n";
450              
451             # now copy everything to the tmp directory
452             #print SPEC "\%prep\n\n";
453             #print SPEC "\%build\n\n";
454             #print SPEC "\%install\n\n";
455 0           foreach my $object ($self->get_directory_objects())
456             {
457 0           my $directory = "$tmp_dir/" . $object->destination();
458 0           mkpath($directory, 0, 0755);
459             }
460 0           foreach my $object ($self->get_file_objects())
461             {
462 0           my $source = $object->source();
463 0           my $destination = "$tmp_dir/" . $object->destination();
464 0           my $dir = dirname($destination);
465 0 0         unless (-d $dir)
466             {
467 0 0         mkpath($dir, 0, 0755) or
468             warn "Error: Problems were encountered creating directory \"$dir\": $!\n";
469             }
470 0           copy($source, $destination);
471             }
472 0           foreach my $object ($self->get_link_objects())
473             {
474 0           my $source = $object->source();
475 0           my $destination = "$tmp_dir/" . $object->destination();
476 0           my $type = $object->type();
477 0 0         if ($type =~ /hard/i)
    0          
478             {
479 0           eval link "$source", "$destination";
480 0 0         warn "Warning: Hard links not supported on this operatiing system: $@\n" if $@;
481             }
482             elsif ($type =~ /soft/i)
483             {
484 0           eval symlink "$source", "$destination";
485 0 0         warn "Warning: Soft links not supported on this operatiing system: $@\n" if $@;
486             }
487             else
488             {
489 0           warn "Error: Not sure what type of link to create soft or hard.";
490             }
491             }
492              
493             # here is where we specify all the installable objects
494 0           print SPEC "\%files\n";
495 0           foreach my $object ($self->get_directory_objects(), $self->get_file_objects(), $self->get_link_objects())
496             {
497 0           my $destination = $object->destination();
498 0           my $user = getpwuid($object->user());
499 0           my $group = getgrgid($object->group());
500 0           my $mode = $object->mode();
501 0           print SPEC "\%attr($mode, $user, $group)";
502 0 0         print SPEC " \%" . $object->kind() if $object->kind();
503 0           print SPEC " /$destination\n"
504             }
505              
506 0           close SPEC;
507              
508 0           return 1;
509             }
510              
511             ################################################################################
512             # Function: _build_package
513             # Description: This method builds the package and moves it to the output
514             # directory.
515             # Arguments: None.
516             # Returns: True on success else undef
517             #
518             sub _build_package
519             {
520 0     0     my $self = shift;
521 0           my $tmp_dir = $self->tmp_dir();
522            
523             # build the package
524 0 0         unless (system("rpm -bb --rcfile $tmp_dir/rpmrc $tmp_dir/SPECS/package.spec") == 0)
525             {
526 0           warn "Error: There were problems creating the package.\n";
527             }
528              
529             # move the pacakge to the output directory
530 0           my $package = "$tmp_dir/RPMS/" . $self->architecture();
531 0           $package .= "/" . $self->package_name();
532 0           my $output_dir = $self->output_dir();
533 0 0         unless (move($package, $output_dir))
534             {
535 0           warn "Error: Couldn't move \"$package\" to \"$output_dir\"\n";
536             }
537              
538 0           return 1;
539             }
540              
541             ################################################################################
542             # Function: _cleanup
543             # Description: This method cleans up the temp directory
544             # Arguments: None.
545             # Returns: True on success else undef
546             #
547             sub _cleanup
548             {
549 0     0     my $self = shift;
550 0           my $tmp_dir = $self->tmp_dir();
551            
552 0 0         unless (system("chmod -R 0777 $tmp_dir") == 0)
553             {
554 0           warn "Warning: Couldn't change the permissions on $tmp_dir: $!\n";
555             }
556 0 0         return undef unless rmtree($tmp_dir, 0, 0);
557              
558 0           return 1;
559             }
560              
561             1;
562             __END__