File Coverage

perllib/Arch/Session.pm
Criterion Covered Total %
statement 33 269 12.2
branch 0 140 0.0
condition 0 42 0.0
subroutine 11 30 36.6
pod 17 18 94.4
total 61 499 12.2


line stmt bran cond sub pod time code
1             # Arch Perl library, Copyright (C) 2004 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 3     3   65 use 5.005;
  3         12  
  3         121  
18 3     3   18 use strict;
  3         5  
  3         133  
19              
20             package Arch::Session;
21              
22 3     3   16 use base 'Arch::Storage';
  3         12  
  3         1456  
23              
24 3     3   17 use Arch::Util qw(run_tla _parse_revision_descs load_file save_file);
  3         5  
  3         229  
25 3     3   18 use Arch::Backend qw(get_cache_config);
  3         7  
  3         137  
26 3     3   735 use Arch::TempFiles qw(temp_dir_name temp_dir);
  3         8  
  3         178  
27 3     3   1365 use Arch::Changeset;
  3         7  
  3         103  
28 3     3   1492 use Arch::Library;
  3         8  
  3         120  
29 3     3   19 use Arch::Log;
  3         7  
  3         56  
30 3     3   2180 use Arch::Tree;
  3         8  
  3         46  
31 3     3   2167 use Arch::Tarball;
  3         9  
  3         10267  
32              
33             sub _default_fields ($) {
34 0     0     my $this = shift;
35             return (
36 0           $this->SUPER::_default_fields,
37             use_library => 1,
38             );
39             }
40              
41             sub new ($%) {
42 0     0 1   my $class = shift;
43 0           my %init = @_;
44 0           my $self = $class->SUPER::new(%init);
45 0           $self->clear_cache;
46 0           return $self;
47             }
48              
49             sub archives ($) {
50 0     0 1   my $self = shift;
51 0   0       $self->{archives} ||= [ run_tla("archives -n") ];
52 0           return $self->{archives};
53             }
54            
55             *is_archive_registered = *Arch::Storage::is_archive_managed;
56             *is_archive_registered = *is_archive_registered;
57              
58             sub categories ($;$) {
59 0     0 1   my $self = shift;
60 0           my $archive = $self->_name_operand(shift, 'archive');
61              
62 0 0         unless ($self->{categories}->{$archive}) {
63 0           $self->{categories}->{$archive} = [ run_tla("categories", $archive) ];
64             }
65 0           return $self->{categories}->{$archive};
66             }
67              
68             sub branches ($;$) {
69 0     0 1   my $self = shift;
70 0           my $category = $self->_name_operand(shift, 'category');
71              
72 0 0         unless ($self->{branches}->{$category}) {
73 0           $self->{branches}->{$category} = [ run_tla("branches", $category) ];
74             }
75 0           return $self->{branches}->{$category};
76             }
77              
78             sub versions ($;$) {
79 0     0 1   my $self = shift;
80 0           my $branch = $self->_name_operand(shift, 'branch');
81              
82 0 0         unless ($self->{versions}->{$branch}) {
83 0           $self->{versions}->{$branch} = [ run_tla("versions", $branch) ];
84             # temporarily do this for backward compatibility
85 0 0         $self->{versions}->{$branch} = [ map { s/--/----/; $_ } grep !/--.*--/, @{$self->{versions}->{$branch}} ]
  0            
  0            
  0            
86             if $branch->branch eq '';
87             }
88 0           return $self->{versions}->{$branch};
89             }
90              
91             sub revisions ($;$) {
92 0     0 1   my $self = shift;
93 0           my $version = $self->_name_operand(shift, 'version');
94              
95 0 0         unless ($self->{revisions}->{$version}) {
96 0           $self->{revisions}->{$version} = [ run_tla("revisions", $version) ];
97             }
98 0           return $self->{revisions}->{$version};
99             }
100              
101             sub get_revision_descs ($;$$) {
102 0     0 1   my $self = shift;
103 0           my $version = $self->_name_operand(shift, 'version');
104 0   0       my $extra_args = shift || [];
105 0 0         die "get_revision_descs: no a|c|b|v ($version)\n" unless $version->is_valid('archive+');
106              
107 0 0         unless ($self->{revision_descs}->{$version}) {
108 0           my $nonarch_version = $version->nan;
109              
110             # $ok is used to work around the tla bug with branchless version
111             # $prev_line is used to track revisions with no (empty) summary
112 0           my $ok = 0;
113 0           my $prev_line = "";
114              
115 0 0         my @revision_lines = map { s/^ //? $_: undef }
  0 0          
116             grep {
117 0           $ok = /^ \Q$nonarch_version\E$/ if /^ [^ ]/;
118 0   0       my $end = ($prev_line =~ /^ /) && ($_ eq "");
119 0           $prev_line = $_;
120 0 0 0       ($end || /^ /) && $ok
121             }
122             run_tla("abrowse --desc", @$extra_args, $version);
123              
124 0           my $revision_descs = _parse_revision_descs(2, \@revision_lines);
125 0           $self->{revision_descs}->{$version} = $revision_descs;
126 0           $self->{revisions}->{$version} = [ map { $_->{name} } @$revision_descs ];
  0            
127             }
128 0           return $self->{revision_descs}->{$version};
129             }
130              
131             *revision_details = *get_revision_descs; *revision_details = *revision_details;
132              
133             sub clear_cache ($;@) {
134 0     0 1   my $self = shift;
135 0           my @keys = @_;
136              
137 0 0         @keys = qw(archives categories branches versions revisions revision_descs)
138             unless @keys;
139              
140 0           foreach (@keys) {
141 0 0 0       if (@_ && !exist $self->{$_}) {
142 0           warn __PACKAGE__ . "::clear_cache: unknown key ($_), ignoring\n";
143 0           next;
144             }
145 0 0         $self->{$_} = $_ eq 'archives'? undef: {};
146             }
147              
148 0           return $self;
149             }
150              
151             sub expanded_versions ($;$$) {
152 0     0 0   my $self = shift;
153 0           my $archive = $self->_name_operand(shift);
154 0   0       my $extra_args = shift || [];
155 0 0         die "get_all_versions: no archive+ ($archive)\n" unless $archive->is_valid('archive+');
156 0           my $archive0 = $archive->cast('archive');
157              
158 0 0         unless ($self->{all_versions}->{$archive}) {
159 0           my @versions =
160 0           map { s/^ //; "$archive0/$_" }
  0            
161 0           grep { /^ [^ ]/ }
162             run_tla("abrowse --desc", @$extra_args, $archive);
163              
164 0           $self->{all_versions}->{$archive} = \@versions;
165             }
166 0           return $self->{all_versions}->{$archive};
167             }
168              
169             # [
170             # [ category1, [
171             # [ branch1, [
172             # [ version1, start_revision1, end_revision1 ],
173             # [ version2, start_revision2, end_revision2 ],
174             # ] ],
175             # [ branch2, [
176             # [ version3, start_revision3, end_revision3 ],
177             # [ version4, start_revision4, end_revision4 ],
178             # ] ],
179             # ...,
180             # ] ],
181             # ]
182              
183             sub expanded_archive_info ($;$$) {
184 0     0 1   my $self = shift;
185 0           my $archive_plus = $self->_name_operand(shift);
186 0   0       my $full_listing = shift || 0; # currently ignored
187              
188 0           my $infos = [];
189 0           my @category_infos = split(/^\b/m, join('',
190 0           map { s/^ //; "$_\n" } grep { /^ / }
  0            
  0            
191             run_tla("abrowse $archive_plus")
192             ));
193              
194 0           my $error = 0;
195             CATEGORY_ITEM:
196 0           foreach (@category_infos) {
197 0           my ($category, $branch_infos) = /^([^\s]+)\n( .*)$/s;
198 0           push @$infos, [ $category, [] ];
199 0 0         unless (defined $category) {
200 0           $error = 1; next CATEGORY_ITEM;
  0            
201             }
202              
203 0 0         my @branch_infos = split(/^\b/m, join('',
204 0           map { s/^ // or $error = 1; "$_\n" }
  0            
205             split("\n", $branch_infos)
206             ));
207 0 0         $error = 1 unless @branch_infos;
208 0           foreach (@branch_infos) {
209 0           my ($branch, $version_infos) = /^\Q$category\E(?:--([^\s]+))?\n( .*)$/s;
210 0 0 0       $branch = "" if defined $version_infos && !defined $branch;
211 0 0         unless (defined $branch) {
212 0           $error = 1; next CATEGORY_ITEM;
  0            
213             }
214 0           push @{$infos->[-1]->[1]}, [ $branch, [] ];
  0            
215              
216 0 0         my @version_infos = split(/^\b/m, join('',
217 0           map { s/^ // or $error = 1; "$_\n" }
  0            
218             split("\n", $version_infos)
219             ));
220 0 0         $error = 1 unless @version_infos;
221 0           foreach (@version_infos) {
222 0           my ($version, $revision0, $revisionl) = /^\Q$category\E(?:--)?\Q$branch\E--([^\s]+)(?:\n ([^\s]+)(?: \.\. ([^\s]+))?\n)?$/s;
223 0 0         unless (defined $version) {
224 0           $error = 1; next CATEGORY_ITEM;
  0            
225             }
226 0           my $revisions2 = [];
227 0 0         if ($full_listing) {
228 0 0         push @$revisions2, $revision0 if defined $revision0;
229 0 0         push @$revisions2, $revisionl if defined $revisionl;
230             } else {
231 0 0         $revision0 = '' unless defined $revision0;
232 0 0         $revisionl = '' unless defined $revisionl;
233 0           push @$revisions2, $revision0, $revisionl;
234             }
235 0           push @{$infos->[-1]->[1]->[-1]->[1]}, [ $version, @$revisions2 ];
  0            
236             }
237             }
238             } continue {
239 0 0         if ($error) {
240 0           warn "Unexpected abrowse output, skipping:\n$_\n";
241 0           pop @$infos;
242 0           $error = 0;
243             }
244             }
245 0           return $infos;
246             }
247              
248             sub get_revision_changeset ($$;$) {
249 0     0 1   my $self = shift;
250 0           my $revision = shift;
251 0           my $dir = shift;
252              
253             # use revlib unless specific result dir requested (and unless disabled)
254 0 0 0       if (!$dir && $self->{use_library}) {
255 0           $dir = Arch::Library->instance->find_revision_tree($revision);
256 0 0         if ($dir) {
257 0           $dir .= "/,,patch-set";
258 0           goto RETURN_CHANGESET;
259             }
260             }
261              
262             # use arch cache if available
263 0           my $cache_dir = get_cache_config()->{dir};
264 0 0 0       if (!$dir && $cache_dir) {
265 0           my $delta_file = "$cache_dir/archives/$revision/delta.tar.gz";
266 0 0         if (-r $delta_file) {
267 0           my $tarball = Arch::Tarball->new(file => $delta_file);
268 0           my $subdir = $revision; $subdir =~ s!.*/!!;
  0            
269 0           $dir = $tarball->extract . "/$subdir.patches";
270 0 0         $dir = "" unless -d $dir;
271 0 0         goto RETURN_CHANGESET if $dir;
272             }
273             }
274              
275 0   0       $dir ||= temp_dir_name("arch-changeset");
276 0 0 0       die "get_changeset: incorrect dir ($dir)\n" unless $dir && !-d $dir;
277              
278 0           run_tla("get-changeset", $revision, $dir);
279              
280 0           RETURN_CHANGESET:
281             return Arch::Changeset->new($revision, $dir);
282             }
283              
284             sub get_changeset ($;$) {
285 0     0 1   my $self = shift;
286 0           my $dir = shift;
287 0           my $revision = $self->working_name;
288 0 0         die "get_changeset: no working revision\n" unless $revision->is_valid('revision');
289 0           return $self->get_revision_changeset($revision, $dir);
290             }
291              
292             sub get_specified_changeset ($$) {
293 0     0 1   my $self = shift;
294 0           my $arg = shift;
295              
296 0 0         die "No changeset specifier (revision name or directory)\n"
297             unless $arg;
298              
299 0           my $downloaded_file = undef;
300 0           my $temp_dir = undef;
301              
302 0 0         if ($arg =~ m!^http://!) {
303 0 0         die "Invalid http:// tarball url ($arg)\n"
304             unless $arg =~ m!/([^/]+\.tar\.gz)$!;
305 0           my $filename = $1;
306              
307 0           require Arch::LiteWeb;
308 0           my $web = Arch::LiteWeb->new;
309 0           my $content = $web->get($arg);
310 0 0         die $web->error_with_url unless defined $content;
311 0 0         die "Zero content in $arg\n" unless $content;
312              
313 0           $temp_dir = temp_dir("arch-download");
314 0           $arg = "$temp_dir/$filename";
315 0           save_file($arg, \$content);
316 0           $downloaded_file = $arg;
317             }
318              
319 0 0         if ($arg =~ m!([^/]+)\.tar\.gz$!) {
320 0 0         die "No tarball file $arg found\n"
321             unless -f $arg;
322 0           my $basename = $1;
323              
324 0           require Arch::Tarball;
325 0           my $tarball = Arch::Tarball->new(file => $arg);
326 0           my $final_dir = $tarball->extract(dir => $temp_dir) . "/$basename";
327              
328             # base-0.src.tar.gz tarball extracts to dir without .src part,
329             # but this tree has no tree-version set anyway (and zero changes)
330 0 0 0       die "No way to get tree changes from what seems to be an arch import tarball\n File: $arg\n"
331             if $final_dir =~ /.*--.*--.*\d+\.src$/ && !-d $final_dir;
332 0 0         die "No expected $final_dir after extracting $arg\n"
333             unless -d $final_dir;
334              
335 0           $arg = $final_dir;
336 0 0         unlink $downloaded_file if $downloaded_file;
337             }
338              
339 0 0         if (-d "$arg/{arch}") {
    0          
    0          
340 0           my $tree = Arch::Tree->new($arg);
341 0           my $cset = $tree->get_changeset(temp_dir_name("arch-changeset"));
342              
343 0 0         die qq(Could not get local tree changes\n)
344             . qq( You may be using "untagged-source unrecognized" and have untagged source\n)
345             . qq( files in your tree. Please add file ids or remove the offending files.\n)
346             unless defined $cset;
347 0           return $cset;
348              
349             } elsif (-f "$arg/mod-dirs-index") {
350 0           return Arch::Changeset->new('none', $arg);
351              
352             } elsif (-d $arg) {
353 0           die qq(Invalid directory\n)
354             . qq( "$arg" is neither a changeset directory nor a project tree.\n);
355              
356             } else {
357             # die "No fully qualified revision name ($arg)\n"
358             # unless Arch::Name->is_valid($arg, "revision");
359 0           my $cset = eval {
360 0           $self->get_revision_changeset(
361             $arg, temp_dir_name("arch-changeset")
362             );
363             };
364 0 0         die qq(get-changeset failed\n)
365             . qq( Could not fetch changeset for revision "$arg".\n)
366             if $@;
367 0           return $cset;
368             }
369             }
370              
371             sub get_revision_log ($$) {
372 0     0 1   my $self = shift;
373 0   0       my $revision = shift || die "get_revision_log: No revision given\n";
374              
375 0           my $message;
376              
377             # use arch cache if available
378 0           my $cache_dir = get_cache_config()->{dir};
379 0 0         if ($cache_dir) {
380 0           my $log_file = "$cache_dir/archives/$revision/log";
381 0 0         if (-r $log_file) {
382 0           load_file($log_file, \$message);
383 0           goto RETURN_LOG;
384             }
385             }
386              
387 0           $message = run_tla("cat-archive-log", $revision);
388 0 0         die "Can't get log of $revision from archive.\n"
389             . "Unexisting revision or system problems.\n"
390             unless $message;
391              
392 0           RETURN_LOG:
393             return Arch::Log->new($message);
394             }
395              
396             sub get_log ($) {
397 0     0 1   my $self = shift;
398 0           my $revision = $self->working_name;
399 0 0         die "get_log: no working revision\n" unless $revision->is_valid('revision');
400 0           return $self->get_revision_log($revision);
401             }
402              
403             sub get_tree ($;$$%) {
404 0     0 1   my $self = shift;
405 0 0         my $opts = shift if ref($_[0]) eq 'HASH';
406 0           my $revision = $self->_name_operand(shift);
407 0 0         die "get_tree: no r|v|b ($revision)\n" unless $revision->is_valid('branch+');
408              
409 0   0       my $dir = shift || temp_dir_name("arch-tree");
410 0 0         die "get_tree: no directory name (internal error?)\n" unless $dir;
411 0 0         die "get_tree: directory already exists ($dir)\n" if -d $dir;
412              
413 0           my @args = ();
414 0 0         push @args, "--no-pristine" unless $opts->{pristine};
415 0 0         push @args, "--link" if $opts->{link};
416 0 0         push @args, "--library" if $opts->{library};
417 0 0         push @args, "--sparse" if $opts->{sparse};
418 0 0         push @args, "--non-sparse" if $opts->{non_sparse};
419 0 0         push @args, "--no-greedy-add" if $opts->{no_greedy_add};
420              
421 0           run_tla("get --silent", @args, $revision, $dir);
422 0 0         die "Can't get revision $revision from archive.\n"
423             . "Unexisting revision or system problems.\n"
424             unless -d $dir;
425 0           return Arch::Tree->new($dir);
426             }
427              
428             sub init_tree ($$;$) {
429 0     0 1   my $self = shift;
430 0           my $version = $self->_name_operand(shift, "version");
431 0   0       my $dir = shift || ".";
432              
433 0           run_tla("init-tree", "-d", $dir, $version);
434 0 0         return undef unless $? == 0;
435 0           return Arch::Tree->new($dir);
436             }
437              
438             sub my_id ($;$) {
439 0     0 1   my $self = shift;
440 0           my $userid = shift;
441              
442 0 0         if (defined $userid) {
443 0 0         return 0 unless $userid =~ /<.+\@.*>/;
444 0           run_tla("my-id", $userid);
445 0           return !$?;
446             } else {
447 0           ($userid) = run_tla("my-id");
448 0           return $userid;
449             }
450             }
451              
452             1;
453              
454             __END__