]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/Import.pm
treewide: "require" + "use" cleanup and docs
[public-inbox.git] / lib / PublicInbox / Import.pm
index 6ee1935e6f8bbd1900500698674ee9b8fdcf37be..572e9bb9899fc464671510dc26275d51d6b7ce8c 100644 (file)
@@ -10,7 +10,7 @@ use strict;
 use warnings;
 use base qw(PublicInbox::Lock);
 use PublicInbox::Spawn qw(spawn);
-use PublicInbox::MID qw(mids mid_mime mid2path);
+use PublicInbox::MID qw(mids mid2path);
 use PublicInbox::Address;
 use PublicInbox::MsgTime qw(msg_timestamp msg_datestamp);
 use PublicInbox::ContentId qw(content_digest);
@@ -66,7 +66,7 @@ sub gfi_start {
        my $git_dir = $git->{git_dir};
        my @cmd = ('git', "--git-dir=$git_dir", qw(fast-import
                        --quiet --done --date-format=raw));
-       my $rdr = { 0 => fileno($out_r), 1 => fileno($in_w) };
+       my $rdr = { 0 => $out_r, 1 => $in_w };
        my $pid = spawn(\@cmd, undef, $rdr);
        die "spawn fast-import failed: $!" unless defined $pid;
        $out_w->autoflush(1);
@@ -178,14 +178,14 @@ sub _update_git_info ($$) {
                my $env = { GIT_INDEX_FILE => $index };
                run_die([@cmd, qw(read-tree -m -v -i), $self->{ref}], $env);
        }
-       run_die([@cmd, 'update-server-info'], undef);
-       ($self->{path_type} eq '2/38') and eval {
+       run_die([@cmd, 'update-server-info']);
+       my $ibx = $self->{-inbox};
+       ($ibx && $self->{path_type} eq '2/38') and eval {
                require PublicInbox::SearchIdx;
-               my $ibx = $self->{-inbox} || $git_dir;
                my $s = PublicInbox::SearchIdx->new($ibx);
                $s->index_sync({ ref => $self->{ref} });
        };
-       eval { run_die([@cmd, qw(gc --auto)], undef) } if $do_gc;
+       eval { run_die([@cmd, qw(gc --auto)]) } if $do_gc;
 }
 
 sub barrier {
@@ -394,16 +394,16 @@ sub add {
        }
 
        my $blob = $self->{mark}++;
-       my $str = $mime->as_string;
-       my $n = length($str);
+       my $raw_email = $mime->{-public_inbox_raw} // $mime->as_string;
+       my $n = length($raw_email);
        $self->{bytes_added} += $n;
        print $w "blob\nmark :$blob\ndata ", $n, "\n" or wfail;
-       print $w $str, "\n" or wfail;
+       print $w $raw_email, "\n" or wfail;
 
        # v2: we need this for Xapian
        if ($self->{want_object_info}) {
                my $oid = $self->get_mark(":$blob");
-               $self->{last_object} = [ $oid, $n, \$str ];
+               $self->{last_object} = [ $oid, $n, \$raw_email ];
        }
        my $ref = $self->{ref};
        my $commit = $self->{mark}++;
@@ -484,33 +484,45 @@ sub digest2mid ($$) {
        "$dt.$b64" . '@z';
 }
 
-sub clean_purge_buffer {
-       my ($oids, $buf) = @_;
-       my $cmt_msg = 'purged '.join(' ',@$oids)."\n";
+sub rewrite_commit ($$$$) {
+       my ($self, $oids, $buf, $mime) = @_;
+       my ($name, $email, $at, $ct, $subject);
+       if ($mime) {
+               ($name, $email, $at, $ct, $subject) = extract_cmt_info($mime);
+       } else {
+               $name = $email = '';
+               $subject = 'purged '.join(' ', @$oids);
+       }
        @$oids = ();
-
+       $subject .= "\n";
        foreach my $i (0..$#$buf) {
                my $l = $buf->[$i];
                if ($l =~ /^author .* ([0-9]+ [\+-]?[0-9]+)$/) {
-                       $buf->[$i] = "author <> $1\n";
+                       $at //= $1;
+                       $buf->[$i] = "author $name <$email> $at\n";
+               } elsif ($l =~ /^committer .* ([0-9]+ [\+-]?[0-9]+)$/) {
+                       $ct //= $1;
+                       $buf->[$i] = "committer $self->{ident} $ct\n";
                } elsif ($l =~ /^data ([0-9]+)/) {
-                       $buf->[$i++] = "data " . length($cmt_msg) . "\n";
-                       $buf->[$i] = $cmt_msg;
+                       $buf->[$i++] = "data " . length($subject) . "\n";
+                       $buf->[$i] = $subject;
                        last;
                }
        }
 }
 
-sub purge_oids {
-       my ($self, $purge) = @_;
-       my $tmp = "refs/heads/purge-".((keys %$purge)[0]);
+# returns the new commit OID if a replacement was done
+# returns undef if nothing was done
+sub replace_oids {
+       my ($self, $mime, $replace_map) = @_; # oid => raw string
+       my $tmp = "refs/heads/replace-".((keys %$replace_map)[0]);
        my $old = $self->{'ref'};
        my $git = $self->{git};
        my @export = (qw(fast-export --no-data --use-done-feature), $old);
        my $rd = $git->popen(@export);
        my ($r, $w) = $self->gfi_start;
        my @buf;
-       my $npurge = 0;
+       my $nreplace = 0;
        my @oids;
        my ($done, $mark);
        my $tree = $self->{-tree};
@@ -533,10 +545,13 @@ sub purge_oids {
                } elsif (/^M 100644 ([a-f0-9]+) (\w+)/) {
                        my ($oid, $path) = ($1, $2);
                        $tree->{$path} = 1;
-                       if ($purge->{$oid}) {
+                       my $sref = $replace_map->{$oid};
+                       if (defined $sref) {
                                push @oids, $oid;
-                               my $cmd = "M 100644 inline $path\ndata 0\n\n";
-                               push @buf, $cmd;
+                               my $n = length($$sref);
+                               push @buf, "M 100644 inline $path\ndata $n\n";
+                               push @buf, $$sref; # hope CoW works...
+                               push @buf, "\n";
                        } else {
                                push @buf, $_;
                        }
@@ -545,11 +560,13 @@ sub purge_oids {
                        push @buf, $_ if $tree->{$path};
                } elsif ($_ eq "\n") {
                        if (@oids) {
-                               my $out = join('', @buf);
-                               $out =~ s/^/# /sgm;
-                               warn "purge rewriting\n", $out, "\n";
-                               clean_purge_buffer(\@oids, \@buf);
-                               $npurge++;
+                               if (!$mime) {
+                                       my $out = join('', @buf);
+                                       $out =~ s/^/# /sgm;
+                                       warn "purge rewriting\n", $out, "\n";
+                               }
+                               rewrite_commit($self, \@oids, \@buf, $mime);
+                               $nreplace++;
                        }
                        $w->print(@buf, "\n") or wfail;
                        @buf = ();
@@ -567,28 +584,30 @@ sub purge_oids {
                $w->print(@buf) or wfail;
        }
        die 'done\n not seen from fast-export' unless $done;
-       chomp(my $cmt = $self->get_mark(":$mark")) if $npurge;
+       chomp(my $cmt = $self->get_mark(":$mark")) if $nreplace;
        $self->{nchg} = 0; # prevent _update_git_info until update-ref:
        $self->done;
        my @git = ('git', "--git-dir=$git->{git_dir}");
 
-       run_die([@git, qw(update-ref), $old, $tmp]) if $npurge;
+       run_die([@git, qw(update-ref), $old, $tmp]) if $nreplace;
 
        run_die([@git, qw(update-ref -d), $tmp]);
 
-       return if $npurge == 0;
+       return if $nreplace == 0;
+
+       run_die([@git, qw(-c gc.reflogExpire=now gc --prune=all --quiet)]);
 
-       run_die([@git, qw(-c gc.reflogExpire=now gc --prune=all)]);
+       # check that old OIDs are gone
        my $err = 0;
-       foreach my $oid (keys %$purge) {
+       foreach my $oid (keys %$replace_map) {
                my @info = $git->check($oid);
                if (@info) {
-                       warn "$oid not purged\n";
+                       warn "$oid not replaced\n";
                        $err++;
                }
        }
        _update_git_info($self, 0);
-       die "Failed to purge $err object(s)\n" if $err;
+       die "Failed to replace $err object(s)\n" if $err;
        $cmt;
 }
 
@@ -604,7 +623,7 @@ PublicInbox::Import - message importer for public-inbox v1 inboxes
 
 version 1.0
 
-=head1 SYNOPSYS
+=head1 SYNOPSIS
 
        use Email::MIME;
        use PublicInbox::Git;