Tweaked version. The previous version was working just fine, but this
one also marks hardlinks and symlinks as skippable, as should be.
It also adjusts the pace of progress slightly (making the meter jump AFTER
skipping the entry), and also it does prepare_to_extract systematically
(which will recheck links vs their packing-list entry for consistency)

I haven't seen any negative report from the previous version.

If this one does work too, I intend to commit it sometimes during the week.

Index: OpenBSD/Add.pm
===================================================================
RCS file: /build/data/openbsd/cvs/src/usr.sbin/pkg_add/OpenBSD/Add.pm,v
retrieving revision 1.153
diff -u -p -r1.153 Add.pm
--- OpenBSD/Add.pm      20 May 2014 05:55:43 -0000      1.153
+++ OpenBSD/Add.pm      13 Jun 2014 17:14:05 -0000
@@ -113,7 +113,34 @@ sub perform_extraction
        $state->{partial} = $handle->{partial};
        $state->{archive} = $handle->{location};
        $state->{check_digest} = $handle->{plist}{check_digest};
-       $state->progress->visit_with_size($handle->{plist}, 'extract', $state);
+       my ($wanted, $tied) = {};
+       $handle->{plist}->find_extractible($state, $wanted, $tied);
+       my $p = $state->progress->new_sizer($handle->{plist}, $state);
+       while (my $file = $state->{archive}->next) {
+               my $e = $tied->{$file->name};
+               if (defined $e) {
+                       delete $tied->{$file->name};
+                       $e->prepare_to_extract($state, $file);
+                       $state->{archive}->skip;
+                       $p->advance($e);
+                       # skip to next;
+               }
+               $e = $wanted->{$file->name};
+               if (!defined $e) {
+                       $state->Fatal("archive member not found #1",
+                           $file->name);
+               }
+               delete $wanted->{$file->name};
+               $e->prepare_to_extract($state, $file);
+               $e->extract($state, $file);
+               $p->advance($e);
+               if (keys %$wanted == 0) {
+                       return;
+               }
+       }
+       if (keys %$wanted > 0) {
+               $state->fatal("Truncated archive");
+       }
 }
 
 my $user_tagged = {};
@@ -181,6 +208,10 @@ sub prepare_for_addition
 {
 }
 
+sub find_extractible
+{
+}
+
 sub extract
 {
        my ($self, $state) = @_;
@@ -236,6 +267,16 @@ sub set_modes
        }
 }
 
+package OpenBSD::PackingElement::Meta;
+
+# XXX stuff that's invisible to find_extractible should be considered extracted
+# for the most part, otherwise we create broken partial packages
+sub find_extractible
+{
+       my ($self, $state, $wanted, $tied) = @_;
+       $state->{partial}{$self} = 1;
+}
+
 package OpenBSD::PackingElement::ExtraInfo;
 use OpenBSD::Error;
 
@@ -360,6 +401,18 @@ use File::Basename;
 use File::Path;
 use OpenBSD::Temp;
 
+sub find_extractible
+{
+       my ($self, $state, $wanted, $tied) = @_;
+       $wanted->{$self->name} = $self;
+       return;
+       if ($self->{tied} || $self->{link} || $self->{symlink}) {
+               $tied->{$self->name} = $self;
+       } else {
+               $wanted->{$self->name} = $self;
+       }
+}
+
 sub prepare_for_addition
 {
        my ($self, $state, $pkgname) = @_;
@@ -384,19 +437,11 @@ sub prepare_for_addition
 
 sub prepare_to_extract
 {
-       my ($self, $state) = @_;
+       my ($self, $state, $file) = @_;
        my $fullname = $self->fullname;
        my $destdir = $state->{destdir};
 
-       my $file=$state->{archive}->next;
-       if (!defined $file) {
-               $state->fatal("truncated archive");
-       }
        $file->{cwd} = $self->cwd;
-       if (!$file->check_name($self)) {
-               $state->fatal("archive does not match #1 != #2",
-                   $file->name, $self->name);
-       }
        if (defined $self->{symlink} || $file->isSymLink) {
                unless (defined $self->{symlink} && $file->isSymLink) {
                        $state->fatal("bogus symlink #1", $self->name);
@@ -427,14 +472,11 @@ sub prepare_to_extract
        if (defined $self->{symlink} && $state->{do_faked}) {
                $file->{linkname} = $destdir.$file->{linkname};
        }
-       return $file;
 }
 
 sub extract
 {
-       my ($self, $state) = @_;
-
-       my $file = $self->prepare_to_extract($state);
+       my ($self, $state, $file) = @_;
 
        if (defined $self->{link} || defined $self->{symlink}) {
                $state->{archive}->skip;
@@ -483,6 +525,7 @@ sub extract
 
                $state->say("extracting #1", $tempname) if $state->verbose >= 3;
 
+
                if (!$file->isFile) {
                        $state->fatal("can't extract #1, it's not a file", 
                            $self->stringize);
@@ -558,6 +601,10 @@ sub prepare_for_addition
        if ($s->avail < 0) {
                $s->report_overflow($state, $fname);
        }
+}
+
+sub find_extractible
+{
 }
 
 sub extract
Index: OpenBSD/ProgressMeter.pm
===================================================================
RCS file: 
/build/data/openbsd/cvs/src/usr.sbin/pkg_add/OpenBSD/ProgressMeter.pm,v
retrieving revision 1.40
diff -u -p -r1.40 ProgressMeter.pm
--- OpenBSD/ProgressMeter.pm    23 Dec 2013 15:04:37 -0000      1.40
+++ OpenBSD/ProgressMeter.pm    13 Jun 2014 17:13:21 -0000
@@ -47,6 +47,15 @@ sub errprint
        print STDERR @_;
 }
 
+sub new_sizer
+{
+       return shift;
+}
+
+sub advance
+{
+}
+
 sub for_list
 {
        my ($self, $msg, $l, $code) = @_;
Index: OpenBSD/ProgressMeter/Term.pm
===================================================================
RCS file: 
/build/data/openbsd/cvs/src/usr.sbin/pkg_add/OpenBSD/ProgressMeter/Term.pm,v
retrieving revision 1.23
diff -u -p -r1.23 Term.pm
--- OpenBSD/ProgressMeter/Term.pm       18 Mar 2014 18:53:29 -0000      1.23
+++ OpenBSD/ProgressMeter/Term.pm       13 Jun 2014 17:13:21 -0000
@@ -20,11 +20,8 @@ use warnings;
 package OpenBSD::PackingElement;
 sub size_and
 {
-       my ($self, $progress, $donesize, $totsize, $method, @r) = @_;
-       if (defined $self->{size}) {
-               $$donesize += $self->{size};
-               $progress->show($$donesize, $totsize);
-       }
+       my ($self, $p, $method, @r) = @_;
+       $p->advance($self);
        $self->$method(@r);
 }
 
@@ -80,18 +77,28 @@ sub compute_count
 sub visit_with_size
 {
        my ($progress, $plist, $method, $state, @r) = @_;
+       my $p = $progress->new_sizer($plist, $state);
+       $plist->size_and($p, $method, $state, @r);
+}
+
+sub new_sizer
+{
+       my ($progress, $plist, $state) = @_;
        $plist->{totsize} //= compute_size($plist);
-       my $donesize = 0;
-       my $totsize = $plist->{totsize};
-       $progress->show($donesize, $totsize);
+       my $p = bless {
+           progress => $progress, 
+           totsize => $plist->{totsize},
+           donesize => 0,
+           state => $state
+           }, "_SizeCounter";
+       $progress->show(0, $p->{totsize});
        if (defined $state->{archive}) {
                $state->{archive}{callback} = sub {
                    my $done = shift;
-                   $progress->show($donesize + $done, $totsize);
+                   $progress->show($p->{donesize} + $done, $p->{totsize});
                };
        }
-       $plist->size_and($progress, \$donesize, $totsize,
-           $method, $state, @r);
+       return $p;
 }
 
 sub visit_with_count
@@ -304,6 +311,20 @@ sub next
 
        $todo //= 'ok';
        print "\r$self->{header}: $todo\n";
+}
+
+package _SizeCounter;
+sub new
+{
+}
+
+sub advance
+{
+       my ($self, $e) = @_;
+       if (defined $e->{size}) {
+               $self->{donesize} += $e->{size};
+               $self->{progress}->show($self->{donesize}, $self->{totsize});
+       }
 }
 
 1;

Reply via email to