File Coverage

perllib/Arch/Util.pm
Criterion Covered Total %
statement 101 139 72.6
branch 52 104 50.0
condition 17 42 40.4
subroutine 18 21 85.7
pod 14 14 100.0
total 202 320 63.1


line stmt bran cond sub pod time code
1             # Arch Perl library, Copyright (C) 2004-2005 Mikhael Goikhman
2             #
3             # This program is free software; you can redistribute it and/or modify
4             # it under the terms of the GNU General Public License as published by
5             # the Free Software Foundation; either version 2 of the License, or
6             # (at your option) any later version.
7             #
8             # This program is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11             # GNU General Public License for more details.
12             #
13             # You should have received a copy of the GNU General Public License
14             # along with this program; if not, write to the Free Software
15             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16              
17 40     40   955 use 5.005;
  40         154  
  40         1954  
18 40     40   289 use strict;
  40         90  
  40         2340  
19              
20             package Arch::Util;
21              
22             # import 2 functions for backward compatibility only; remove after summer 2005
23 38     38   23118 use Arch::Backend qw(arch_backend is_baz);
  38         112  
  38         3401  
24              
25 38     38   295 use Exporter;
  38         152  
  38         1576  
26 38     38   191 use vars qw(@ISA @EXPORT_OK);
  38         66  
  38         99468  
27             @ISA = qw(Exporter);
28             @EXPORT_OK = qw(
29             arch_backend is_baz
30             run_pipe_from run_cmd run_tla
31             is_tla_functional
32             load_file save_file
33             copy_dir remove_dir setup_config_dir
34             standardize_date date2daysago date2age
35             parse_creator_email adjacent_revision _parse_revision_descs
36             );
37              
38             sub run_pipe_from (@) {
39 30   50 30 1 255 my $arg0 = shift || die;
40 30         129 my @args = (split(' ', $arg0), @_);
41              
42 30 50       207 @args = ("'" . join("' '", map { s/'/'"'"'/g; $_ } @args) . "'") # "
  1         32  
  1         4  
43             if $] < 5.008;
44 30 50 33     433 print STDERR "executing: '" . join("' '", @args) . "'\n"
45             if $ENV{DEBUG} && ("$ENV{DEBUG}" & "\1") ne "\0";
46              
47             # perl-5.005 does not pass compilation without "eval"...
48 30 50   13   3244 my $pipe_success = $] >= 5.006?
  13         105  
  13         22  
  13         787  
49             eval qq{ no warnings; open(PIPE, '-|', \@args) }: open(PIPE, "$args[0]|");
50 30 100       2132 die "Can't start (@args): $!\n" unless $pipe_success;
51 20         813 return \*PIPE;
52             }
53              
54             # in scalar context return the output string, in list context - list of lines
55             sub run_cmd (@) {
56 29   50 29 1 189 my $arg0 = shift || die;
57 29         153 my @args = (split(' ', $arg0), @_);
58              
59 29         620 my $pipe = run_pipe_from(@args);
60 19 100       330 local $/ = undef unless wantarray;
61 19         40570 my @lines = <$pipe>;
62 19         10301 close($pipe);
63 19 100       176 chomp @lines if wantarray;
64 19 100 100     1240 return wantarray? @lines: $lines[0] || "";
65             }
66              
67             sub run_tla (@) {
68 12   50 12 1 160 my $arg1 = shift || die;
69 12         628 unshift @_, $Arch::Backend::EXE, split(' ', $arg1);
70 12         134 goto \&run_cmd;
71             }
72              
73             sub is_tla_functional () {
74 11 50   11 1 112 eval { run_tla("help --help") } ? 1 : 0;
  10         43  
75             }
76              
77             sub load_file ($;$) {
78 2185     2186 1 3215 my $file_name = shift;
79 2185         2891 my $content_ref = shift;
80 2185 50 33     9629 print STDERR "load_file: $file_name\n"
81             if $ENV{DEBUG} && ("$ENV{DEBUG}" & "\4") ne "\0";
82 2185 50       163503 open(FILE, "<$file_name") or die "Can't load $file_name: $!\n";
83 2185         10245 local $/ = undef;
84 2185         110636 my $content = ;
85 2185 50       55875 close(FILE) or die "Can't close $file_name in load: $!\n";
86 2185 100       5821 if ($content_ref) {
87 9 100       326 $$content_ref = $content if ref($content_ref) eq 'SCALAR';
88 9 100       33 if (ref($content_ref) eq 'ARRAY') {
89 3         9 $content =~ s/\r?\n$//;
90 3         27 @$content_ref = map { chomp; $_ } split(/\r?\n/, $content, -1);
  6         15  
  6         12  
91             }
92             }
93 2185 100       26018 return defined wantarray? $content: undef;
94             }
95              
96             sub save_file ($$) {
97 2131     2132 1 2702 my $file_name = shift;
98 2131 50 33     5872 print STDERR "save_file: $file_name\n"
99             if $ENV{DEBUG} && ("$ENV{DEBUG}" & "\4") ne "\0";
100 2131 50       302356 open(FILE, ">$file_name") or die "Can't save $file_name: $!\n";
101 2127         14221 print FILE
102 0 0       0 ref($_[0]) eq 'SCALAR'? ${$_[0]}:
103 2131 50       7919 ref($_[0]) eq 'ARRAY'? map { m|$/$|? $_: "$_$/" } @{$_[0]}:
  0 100       0  
104             $_[0];
105 2131 50       101264 close(FILE) or die "Can't close $file_name in save: $!\n";
106 2131         6840 return 1;
107             }
108              
109             sub copy_dir ($$) {
110 1     2 1 4 my $dir1 = shift;
111 1         2 my $dir2 = shift;
112 1         5 my $out = run_cmd("/bin/cp -PRp", $dir1, $dir2);
113 1 50       35 warn $out if $out;
114             }
115              
116             sub remove_dir (@) {
117 4     4 1 15 my @dirs = grep { $_ } @_;
  6         25  
118 4 50       41 return unless @dirs;
119 4         32 my $out = run_cmd("/bin/rm -rf", @dirs);
120 4 50       568 warn $out if $out;
121             }
122              
123             sub setup_config_dir (;$@) {
124 3     3 1 14 my $dir = shift;
125 3   66     28 $dir ||= $ENV{ARCH_MAGIC_DIR};
126 3   50     28 $dir ||= ($ENV{HOME} || "/tmp") . "/.arch-magic";
      66        
127              
128 3         11 foreach my $subdir ("", @_) {
129 9 50       23 next unless defined $subdir;
130 9 100       31 $dir .= "/$subdir" unless $subdir eq "";
131 9         266 stat($dir);
132 9 50 33     70 die "$dir exists, but it is not a writable directory\n"
      66        
133             if -e _ && !(-d _ && -w _);
134 9 100       25 unless (-e _) {
135 6 50 33     45 print STDERR "making dir: $dir\n"
136             if $ENV{DEBUG} && ("$ENV{DEBUG}" & "\2") ne "\0";
137 6 50       712 mkdir($dir, 0777) or die "Can't mkdir $dir: $!\n";
138             }
139             }
140 3         55 return $dir;
141             }
142              
143             my %months = (
144             Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6,
145             Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12,
146             );
147             sub standardize_date ($) {
148 0     0 1 0 my $date = shift;
149 0 0       0 if ($date =~ /\w+ (\w+) +(\d+) +(\d+):(\d+):(\d+) (\w+) (\d+)/) {
150 0   0     0 $date = sprintf("%04d-%02d-%02d %02d:%02d:%02d %s",
151             $7, $months{$1} || 88, $2, $3, $4, $5, $6);
152             }
153 0         0 return $date;
154             }
155              
156             # return (creator_name, creator_email, creator_username)
157             sub parse_creator_email ($) {
158 1     1 1 3 my $creator = shift;
159 1         3 my $email = 'no@email.defined';
160 1         2 my $username = "_none_";
161 1 50       7 if ($creator =~ /^(.*?)\s*<((?:(.+?)@)?.*)>$/) {
162 1         7 ($creator, $email, $username) = ($1, $2, $3);
163             }
164 1         4 return ($creator, $email, $username);
165             }
166              
167             sub adjacent_revision ($$) {
168 0     0 1 0 my $full_revision = shift;
169 0   0     0 my $offset = shift || die "adjacent_revision: no offset given\n";
170 0 0       0 die "adjacent_revision: no working revision\n" unless $full_revision;
171              
172 0 0       0 $full_revision =~ /^(.*--.*?)(\w+)-(\d+)$/
173             or die "Invalid revision ($full_revision)\n";
174 0         0 my $prefix = $1;
175 0         0 my $new_num = $3 + $offset;
176 0 0       0 return undef if $new_num < 0;
177 0 0       0 my $new_word = $2 =~ /^patch|base$/?
    0          
    0          
178             $new_num? 'patch': 'base':
179             $new_num? 'versionfix': 'version';
180 0         0 return "$prefix$new_word-$new_num";
181             }
182              
183             sub date2daysago ($) {
184 19     19 1 32 my $date_str = shift;
185              
186 19 50       171 return -10000 unless $date_str =~ /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}) ([^\s]+)/;
187              
188             # timezone is not taken in account...
189 19         3332 require Time::Local;
190 19         3908 my $time = Time::Local::timegm($6, $5, $4, $3, $2 - 1, $1 - 1900);
191 19         677 my $daysago = int((time - $time) / 60 / 60 / 24);
192              
193 19 100       87 return $daysago unless wantarray;
194 1         7 return ($daysago, $time, $7);
195             }
196              
197             sub date2age ($) {
198 12     12 1 38 my $daysago = date2daysago($_[0]);
199 12 50       48 return "bad-date" if $daysago <= -10000;
200              
201 12         68 my ($sign, $days) = $daysago =~ /^(-?)(.*)$/;
202 12 100       77 my $str =
    50          
    100          
    100          
203             $days == 1? "1 day":
204             $days <= 33? "$days days":
205             $days <= 59? int($days / 7 + 0.5) . " weeks":
206             $days <= 550? int($days / 30.42 + 0.5) . " months":
207             int($days / 365.25 + 0.5) . " years";
208 12         174 return "$sign$str";
209             }
210              
211             # gets tla lines with undef meaning the delimiter for revisions;
212             # intended for parsing of "abrowse --desc" and "logs --cDs"
213             sub _parse_revision_descs ($$) {
214 0   0 0   0 my $num_spaces = shift || die;
215 0   0     0 my $revision_lines = shift || die;
216              
217 0         0 my $spaces = " " x $num_spaces;
218 0 0       0 $spaces || die "Invalid number of spaces ($num_spaces)";
219              
220 0         0 my @revision_descs = ();
221 0         0 while (@$revision_lines) {
222 0         0 my ($line1, $line2) = splice @$revision_lines, 0, 2;
223 0         0 my @summary_lines = ();
224 0         0 push @summary_lines, shift @$revision_lines while defined $revision_lines->[0];
225 0         0 shift @$revision_lines; # throw away undef delimiter
226 0         0 my $summary = join("\n", @summary_lines);
227 0         0 $line2 =~ s/^$spaces//; $summary =~ s/^$spaces//mg;
  0         0  
228              
229 0 0       0 my ($name, $kind) = $line1 =~ /^(\S+)(?:\s+\((.*?)\))?/
230             or die "Unexpected output of tla, subline 1:\n\t$line1\n";
231 0 0       0 $kind = !$kind? "unknown": $kind =~ /tag/? "tag": $kind =~ /import/? "import": "cset";
    0          
    0          
232 0 0       0 my ($date, $creator) = $line2 =~ /^(.+?)\s{6}(.*)/
233             or die "Unexpected output of tla, subline 2:\n\t$line2\n";
234 0         0 $date = standardize_date($date);
235 0         0 my $age = date2age($date);
236              
237 0         0 my @version_part;
238 0 0       0 push @version_part, 'version', $1 if $name =~ s/^(.*)--(.*)/$2/;
239              
240 0         0 my ($creator1, $email, $username) = parse_creator_email($creator);
241 0         0 push @revision_descs, {
242             name => $name,
243             summary => $summary,
244             creator => $creator1,
245             email => $email,
246             username => $username,
247             date => $date,
248             age => $age,
249             kind => $kind,
250             @version_part,
251             };
252             }
253 0         0 return \@revision_descs;
254             }
255              
256             1;
257              
258             __END__