File Coverage

blib/lib/Slackware/Slackget/Base.pm
Criterion Covered Total %
statement 7 163 4.2
branch 0 50 0.0
condition 0 24 0.0
subroutine 3 13 23.0
pod 10 10 100.0
total 20 260 7.6


line stmt bran cond sub pod time code
1             package Slackware::Slackget::Base;
2              
3 3     3   46482 use warnings;
  3         4  
  3         82  
4 3     3   9 use strict;
  3         4  
  3         4864  
5              
6             require XML::Simple ;
7             require Slackware::Slackget::PackageList;
8             require Slackware::Slackget::Package;
9             require Slackware::Slackget::File;
10             require Slackware::Slackget::Media;
11             require Slackware::Slackget::MediaList ;
12             require Slackware::Slackget::Date ;
13              
14              
15             =head1 NAME
16              
17             Slackware::Slackget::Base - A module which centralize some base methods usefull to slack-get
18              
19             =head1 VERSION
20              
21             Version 1.0.2
22              
23             =cut
24              
25             our $VERSION = '1.0.3';
26 3     3   491 eval 'use XML::Parser';
  0            
  0            
27             if($@) {
28             warn("XML::Parser is not installed. XML processing operations will be very slow.\n");
29             } else {
30             $XML::Simple::PREFERRED_PARSER='XML::Parser' ;
31             }
32              
33              
34             =head1 SYNOPSIS
35              
36             This module centralize bases tasks like package directory compilation, etc. This class is mainly designed to be a wrapper so it can change a lot before the release.
37              
38             use Slackware::Slackget::Base;
39              
40             my $base = Slackware::Slackget::Base->new();
41             my $packagelist = $base->compil_packages_directory('/var/log/packages/');
42             $packagelist = $base->load_list_from_xml_file('installed.xml');
43              
44             =cut
45              
46             sub new
47             {
48 0     0 1   my ($class,$config) = @_ ;
49 0 0 0       return undef if(!defined($config) or ref($config) ne 'Slackware::Slackget::Config') ;
50 0           my $self = {CONF => $config};
51 0           bless($self,$class);
52 0           return $self;
53             }
54              
55             =head1 CONSTRUCTOR
56              
57             =head2 new
58              
59             Take no arguments.
60              
61             my $base = Slackware::Slackget::Base->new();
62              
63             =head1 FUNCTIONS
64              
65             =cut
66              
67             =head2 ls
68              
69             take a directory as argument and return an array wich contain all things in this directory.
70              
71             my @config_files = $base->ls('/etc/slack-get/') ;
72              
73             =cut
74              
75             sub ls
76             {
77 0     0 1   my $self = shift;
78 0           my $dir = shift;
79 0 0         if (! opendir( DIR, $dir) )
80             {
81 0           warn "unable to open $dir : $!.";
82 0           return undef;
83             }
84 0           my @files = grep !/(?:^\.$)|(?:^\.\$)|(?:^\.\.)/, readdir DIR;
85 0           closedir DIR;
86 0           for(my $k=0; $k<=$#files;$k++)
87             {
88 0 0         if($files[$k] !~ /^(\.\.|\.)$/)
89             {
90 0           $files[$k] = $dir.'/'.$files[$k] ;
91             }
92             }
93 0           return @files;
94             }
95              
96             =head2 dir2files
97              
98             take at leat one directory in argument and recursively follow all subdirectories. Return an array containing all files encounter but WITHOUT symblic links.
99              
100             my @config_files = $base->dir2files('/etc','/usr/local/etc', "/$ENV{HOME}/etc/") ;
101              
102             =cut
103              
104             sub dir2files
105             {
106 0     0 1   my $self = shift;
107 0           my @f_files = ();
108            
109 0           foreach my $a (@_)
110             {
111             # print STDERR "[DEBUG] [dir2files] treating $a\n";
112 0 0 0       unless(-d $a or -l $a)
113             {
114             # print STDERR "\t[DEBUG] [dir2files] file $a is not a directory nor a symlink, pushing on files stack\n";
115 0           push @f_files,$a;
116             }
117             else
118             {
119             # print STDERR "\t[DEBUG] [dir2files] file $a is a directory or a symlink\n";
120 0 0         unless(-l $a)
121             {
122             # print STDERR "\t[DEBUG] [dir2files] file $a is a directory : recurse\n";
123 0           @f_files = (@f_files,$self->dir2files($self->ls($a)));
124             }
125             # else
126             # {
127             # print "\t[dir2files] $a is a symlink\n";
128             # }
129             }
130             }
131 0           return @f_files;
132             }
133              
134             =head2 compil_packages_directory
135              
136             take a directory where are store installed packages files and return a Slackware::Slackget::PackageList object
137              
138             my $packagelist = $base->compil_packages_directory('/var/log/packages/');
139              
140             =cut
141              
142             sub compil_packages_directory
143             {
144 0     0 1   my ($self,$dir,$packagelist) = @_;
145             # print STDERR "[DEBUG] [compil_packages_directory] getting the following packages list : \"$packagelist\"\n";
146             # print STDERR "[DEBUG] [compil_packages_directory] compiling directory \"$dir\"\n";
147 0           my @files = $self->dir2files($dir);
148 0           $|=1;
149             # print STDERR "[DEBUG] number of entry in files array : ",scalar(@files),"\n";
150             # print STDERR "[DEBUG] entry in \@files :\n",join "\n",@files,"\n";
151 0           my $ref;
152 0 0         if($packagelist)
153             {
154 0           my $tmp_packagelist = new Slackware::Slackget::PackageList('encoding'=>$self->{CONF}->{common}->{'file-encoding'});
155 0           while (defined(my $p = $packagelist->Shift()))
156             {
157             # print "treat : $p (",$p->get_id(),")\n";
158             # <STDIN>;
159 0 0 0       if(defined($p) && -e $self->{CONF}->{common}->{'packages-history-dir'}.'/'.$p->get_id())
160             {
161             # print "adding $p\n";
162 0           $tmp_packagelist->add( $p );
163             }
164             }
165 0           $tmp_packagelist->index_list ;
166 0           $packagelist=$tmp_packagelist;
167             }
168             # print join(' :: ', $packagelist->get_indexes());
169 0 0         $packagelist = new Slackware::Slackget::PackageList('encoding'=>$self->{CONF}->{common}->{'file-encoding'}) unless($packagelist);
170 0 0         if(scalar(@files) < 1){
171 0           warn "The directory \"$dir\" is empty or contains no packages.\n" ;
172 0           return $packagelist;
173             }
174             # print STDERR "Slackware::Slackget::PackageList reference : $packagelist\n";
175 0           my $pg_idx=0;
176 0           my $mark = int(scalar(@files)/20);
177 0           my $msg = "[slack-get] compiling $dir (1 mark = $mark packages) : [";
178 0           printf($msg);
179 0           print " "x20 ;
180 0           my $pstr= '0 %';
181 0           print "] $pstr";
182 0           my $mark_idx=0;
183 0           my $percent_idx=0;
184 0           foreach (@files)
185             {
186             # NOTE: The system call is very slow compared to the built-in regular expressions ;)
187             # $_ = `basename $_`;
188             # chomp;
189 0           $_ =~ /^.*\/([^\/]*)$/;
190             #my $file_md5 = `LC_ALL=C md5sum $_ | awk '{print \$1}'`;
191             #chomp($file_md5);
192             # print "searching if $1 is already indexed in the list : ",$packagelist->get_indexed($_),"\n";
193 0 0         if(!defined($packagelist->get_indexed($1)) )#or ($packagelist->get_indexed($_)->getValue('package-file-checksum') ne $file_md5))
194             {
195             # print STDERR "[DEBUG] in Slackware::Slackget::Base, method compil_packages_directory file-encoding=$self->{CONF}->{common}->{'file-encoding'}\n";
196 0           my $sg_file = new Slackware::Slackget::File ($_,'file-encoding' => $self->{CONF}->{common}->{'file-encoding'}) ;
197 0 0         die $! unless $sg_file;
198 0           my @file = $sg_file->Get_file();
199            
200             # print STDERR "[DEBUG] instanciate new package : \"$1\"\n";
201 0           $ref->{$1}= new Slackware::Slackget::Package ($1);
202 0 0         next unless($ref->{$1}) ;
203             # print STDERR "[DEBUG] package reference is $ref->{$1}\n";
204 0           my $pack = $ref->{$1};
205 0           for(my $k=0;$k<=$#file;$k++)
206             {
207             # NOTE: trying to fix a bug reporting by Adi Spivak
208 0 0         next if(!defined($file[$k]));
209 0 0         if($file[$k] =~ /^PACKAGE NAME:\s+(.*)$/)
    0          
    0          
    0          
    0          
210             {
211 0           my $name = $1;
212 0 0 0       unless(defined($pack->getValue('name')) or defined($pack->getValue('version')) or defined($pack->getValue('architecture')) or defined($pack->getValue('package-version')))
      0        
      0        
213             {
214             # print STDERR "[DEBUG] Package forced to be renamed.\n";
215 0           $pack->_setId($name);
216 0           $pack->fill_object_from_package_name();
217             }
218            
219             }
220             elsif($file[$k] =~ /^COMPRESSED PACKAGE SIZE:\s+(.*) K$/)
221             {
222             # print STDERR "[DEBUG] setting param 'compressed-size' to $1\n";
223 0           $pack->setValue('compressed-size',$1);
224             }
225             elsif($file[$k] =~ /^UNCOMPRESSED PACKAGE SIZE:\s+(.*) K$/)
226             {
227             # print STDERR "[DEBUG] setting param 'uncompressed-size' to $1\n";
228 0           $pack->setValue('uncompressed-size',$1);
229             }
230             elsif($file[$k] =~ /^PACKAGE LOCATION:\s+(.*) K$/)
231             {
232             # print STDERR "[DEBUG] setting param 'location' to $1\n";
233 0           $pack->setValue('location',$1);
234             }
235             elsif($file[$k]=~/PACKAGE DESCRIPTION:/)
236             {
237 0           my $tmp = "";
238 0           $k++;
239 0   0       while($file[$k]!~/FILE LIST:/ or $file[$k]!~/\.\//)
240             {
241             # NOTE: this line was originally added to fix the bug reported by Adi Spivak but it doesn't work well
242 0 0 0       last if(!defined($file[$k]) or $file[$k]=~ /^\.\//);
243 0 0         $tmp .= "\t\t\t$file[$k]" if( $file[$k] !~ /FILE\s*LIST\s*:\s*/);
244 0           $k++;
245             }
246             # print STDERR "[DEBUG] setting param 'description' to $tmp\n";
247 0           $pack->setValue('description',"$tmp\n\t\t");
248             ### NOTE: On my system, with 586 packages installed the difference between with or without including the file list is very important
249             ### NOTE: with the file list the installed.xml file size is near 11 MB
250             ### NOTE: without the file list, the size is only 400 KB !!
251             ### NOTE: So I have decided that the file list is not include by default
252 0 0         if(defined($self->{'include-file-list'}))
253             {
254 0           $pack->setValue('file-list',join("\t\t\t",@file[($k+1)..$#file])."\n\t\t");
255             }
256 0           last;
257             }
258             }
259             # print STDERR "[DEBUG] calling Slackware::Slackget::Package->clean_description() on package $pack\n";
260 0           $pack->clean_description();
261             # print STDERR "[DEBUG] calling Slackware::Slackget::Package->grab_info_from_description() on package $pack\n";
262 0           $pack->grab_info_from_description();
263             # $pack->setValue('package-file-checksum',$file_md5);
264             # print STDERR "[DEBUG] calling Slackware::Slackget::PackageList->add() on package $pack\n";
265 0           $packagelist->add($pack);
266 0           $sg_file->Close();
267            
268             }
269             # else
270             # {
271             # print STDERR "[DEBUG] package $_ skipped (already in cache)\n";
272             # }
273 0           $pg_idx++;
274 0           $percent_idx++;
275 0           print "\b" x length($pstr);
276 0           $pstr = $percent_idx/scalar(@files) * 100;
277 0           $pstr =~ /^([^\.]+)/;
278 0           $pstr = $1 ;
279 0           $pstr .= " %";
280 0           print $pstr;
281 0 0         if($pg_idx == $mark)
282             {
283 0           $mark_idx++;
284 0           print "\b"x (40 + length($msg));
285 0           print $msg;
286 0           print '#' x $mark_idx;
287 0           print ' ' x (20 - $mark_idx);
288 0           print "] $pstr";
289 0           $pg_idx=0;
290             }
291             }
292 0           print " (",scalar(@files)," packages examined)\n";
293 0           return $packagelist;
294             }
295              
296              
297             =head2 load_installed_list_from_xml_file
298              
299             Load the data for filling the list from an XML file. Return a Slackware::Slackget::PackageList. This method is design for reading a installed.xml file.
300              
301             $packagelist = $base->load_installed_list_from_xml_file('installed.xml');
302              
303             =cut
304              
305             sub load_installed_list_from_xml_file {
306 0     0 1   my ($self,$file) = @_;
307 0           my $package_list = new Slackware::Slackget::PackageList ;
308 0           my $xml_in = XML::Simple::XMLin($file,KeyAttr => {'package' => 'id'});
309 0           foreach my $pack_name (keys(%{$xml_in->{'package'}})){
  0            
310 0           my $package = new Slackware::Slackget::Package ($pack_name);
311 0           foreach my $key (keys(%{$xml_in->{'package'}->{$pack_name}})){
  0            
312 0           $package->setValue($key,$xml_in->{'package'}->{$pack_name}->{$key}) ;
313             }
314 0           $package_list->add($package);
315             }
316 0           return $package_list;
317             }
318              
319              
320             =head2 load_packages_list_from_xml_file
321              
322             Load the data for filling the list from an XML file. Return a hashref built on this model :
323              
324             my $hashref = {
325             'key' => Slackware::Slackget::PackageList,
326             ...
327             };
328              
329             Ex:
330              
331             my $hashref = {
332             'slackware' => blessed(Slackware::Slackget::PackageList),
333             'slacky' => blessed(Slackware::Slackget::PackageList),
334             'audioslack' => blessed(Slackware::Slackget::PackageList),
335             'linuxpackages' => blessed(Slackware::Slackget::PackageList),
336             };
337              
338             This method is design for reading a packages.xml file.
339              
340             $hashref = $base->load_packages_list_from_xml_file('packages.xml');
341              
342             =cut
343              
344             sub load_packages_list_from_xml_file {
345 0     0 1   my ($self,$file) = @_;
346 0           my $ref = {};
347 0           my $start = time();
348 0           $|=1 ;
349             # print "[DEBUG Slackware::Slackget::Base->load_packages_list_from_xml_file()] Going to parse '$file'\n";
350 0           print "[slack-get] loading packages list...";
351 0           $XML::Simple::PREFERRED_PARSER='XML::Parser' ;
352 0           my $xml_in = XML::Simple::XMLin($file,KeyAttr => {'package' => 'id'}, ForceArray => ['dependencies','dependency','required','suggested']);
353 0           print "ok (loaded in ", time() - $start," sec.)\n";
354             # print "[DEBUG Slackware::Slackget::Base->load_packages_list_from_xml_file()] '$file' correctly parsed in ", time() - $start," sec.\n" ;
355 0           foreach my $group (keys(%{$xml_in})){
  0            
356 0           my $package_list = new Slackware::Slackget::PackageList ;
357 0           foreach my $pack_name (keys(%{$xml_in->{$group}->{'package'}})){
  0            
358 0           my $package = new Slackware::Slackget::Package ($pack_name);
359 0           foreach my $key (keys(%{$xml_in->{$group}->{'package'}->{$pack_name}})){
  0            
360 0 0         if($key eq 'date')
361             {
362 0           $package->setValue($key,Slackware::Slackget::Date->new(%{$xml_in->{$group}->{'package'}->{$pack_name}->{$key}}));
  0            
363             }
364             else
365             {
366 0           $package->setValue($key,$xml_in->{$group}->{'package'}->{$pack_name}->{$key}) ;
367             }
368            
369             }
370 0           $package_list->add($package);
371             }
372 0           $ref->{$group} = $package_list;
373             }
374 0           return $ref;
375             }
376              
377              
378             =head2 load_media_list_from_xml_file
379              
380             Load a server list from a medias.xml file.
381              
382             $serverlist = $base->load_server_list_from_xml_file('servers.xml');
383              
384             =cut
385              
386             sub load_media_list_from_xml_file {
387 0     0 1   my ($self,$file) = @_;
388 0           print "[slack-get] loading media file : $file\n";
389 0           my $server_list = new Slackware::Slackget::MediaList ;
390 0           my $xml_in = XML::Simple::XMLin($file,KeyAttr => {'media' => 'id'});
391             # require Data::Dumper ;
392             # print Data::Dumper::Dumper($xml_in);
393 0           foreach my $server_name (keys(%{$xml_in->{'media'}})){
  0            
394 0           my $server = new Slackware::Slackget::Media ($server_name);
395 0           $server->fill_object_from_xml( $xml_in->{media}->{$server_name} );
396             # $server->print_info ;print "\n\n";
397 0           $server_list->add($server);
398             }
399 0           return $server_list;
400             }
401              
402             =head2 load_server_list_from_xml_file
403              
404             An allias for load_media_list_from_xml_file(). Given for backward compatibility
405              
406             =cut
407              
408             sub load_server_list_from_xml_file{
409 0     0 1   my ($self,$file) = @_;
410 0           $self->load_media_list_from_xml_file($file);
411             }
412              
413              
414             =head2 set_include_file_list
415              
416             By default the file list is not include in the installed.xml for some size consideration (on my system including the file list into installed.xml make him grow 28 times ! It passed from 400 KB to 11 MB),
417              
418             So you can use this method to include the file list into installed.xml. BE carefull, to use it BEFORE compil_packages_directory() !
419              
420             $base->set_include_file_list();
421             $packagelist = $base->compil_packages_directory();
422              
423             =cut
424              
425             sub set_include_file_list{
426 0     0 1   my $self = shift;
427 0           $self->{'include-file-list'} = 1;
428             }
429              
430             =head2 ldd
431              
432             Like the UNIX command ldd. Do a ldd system call on a list of files and return an array of dependencies.
433              
434             my @dependecies = $base->ldd('/usr/bin/gcc', '/usr/bin/perl', '/bin/awk') ;
435              
436             =cut
437              
438             sub ldd
439             {
440 0     0 1   my $self = shift ;
441 0           my @dep = ();
442 0           foreach (@_)
443             {
444 0           foreach my $l (`ldd $_`)
445             {
446 0 0         if($l=~ /^\s*([^\s]*)\s*=>.*/) # linux-gate.so.1 => (0xffffe000) : we only want linux-gate.so.1
447             {
448 0           push @dep,$1 ;
449             }
450             }
451             }
452 0           return @dep;
453             }
454              
455             =head1 AUTHOR
456              
457             DUPUIS Arnaud, C<< <a.dupuis@infinityperl.org> >>
458              
459             =head1 BUGS
460              
461             Please report any bugs or feature requests to
462             C<bug-Slackware-Slackget@rt.cpan.org>, or through the web interface at
463             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Slackware-Slackget>.
464             I will be notified, and then you'll automatically be notified of progress on
465             your bug as I make changes.
466              
467             =head1 SUPPORT
468              
469             You can find documentation for this module with the perldoc command.
470              
471             perldoc Slackware-Slackget
472              
473              
474             You can also look for information at:
475              
476             =over 4
477              
478             =item * Infinity Perl website
479              
480             L<http://www.infinityperl.org/category/slack-get>
481              
482             =item * slack-get specific website
483              
484             L<http://slackget.infinityperl.org>
485              
486             =item * RT: CPAN's request tracker
487              
488             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Slackware-Slackget>
489              
490             =item * AnnoCPAN: Annotated CPAN documentation
491              
492             L<http://annocpan.org/dist/Slackware-Slackget>
493              
494             =item * CPAN Ratings
495              
496             L<http://cpanratings.perl.org/d/Slackware-Slackget>
497              
498             =item * Search CPAN
499              
500             L<http://search.cpan.org/dist/Slackware-Slackget>
501              
502             =back
503              
504             =head1 ACKNOWLEDGEMENTS
505              
506             =head1 COPYRIGHT & LICENSE
507              
508             Copyright 2005 DUPUIS Arnaud, All Rights Reserved.
509              
510             This program is free software; you can redistribute it and/or modify it
511             under the same terms as Perl itself.
512              
513             =cut
514              
515             1; # End of Slackware::Slackget::Base