]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/LeiRediff.pm
lei: simplify common LeiInput users with ->wq1_start
[public-inbox.git] / lib / PublicInbox / LeiRediff.pm
index 60286b065359430a1d6809ac073bea0482433428..f0521bcc6b623ae54963809754a9e0ae9f67aeca 100644 (file)
@@ -30,7 +30,7 @@ sub rediff_user_cb { # called by solver when done
 
        # don't try to support all the git-show(1) options for non-blob,
        # this is just a convenience:
-       $type ne 'blob' and return $lei->err(<<EOF);
+       $type ne 'blob' and return warn(<<EOF);
 # $oid is a $type of $size bytes in:
 # $git->{git_dir} (wanted: $oid_want)
 EOF
@@ -56,6 +56,34 @@ sub solve_1 ($$$) {
        $self->{blob}->{$oid_want}; # full OID
 }
 
+sub _lei_diff_prepare ($$) {
+       my ($lei, $cmd) = @_;
+       my $opt = $lei->{opt};
+       push @$cmd, '--'.($opt->{color} && !$opt->{'no-color'} ? '' : 'no-').
+                       'color';
+       for my $o (@PublicInbox::LEI::diff_opt) {
+               my $c = '';
+               # remove single char short option
+               $o =~ s/\|([a-z0-9])\b//i and $c = $1;
+               if ($o =~ s/=[is]@\z//) {
+                       my $v = $opt->{$o} or next;
+                       push @$cmd, map { $c ? "-$c$_" : "--$o=$_" } @$v;
+               } elsif ($o =~ s/=[is]\z//) {
+                       my $v = $opt->{$o} // next;
+                       push @$cmd, $c ? "-$c$v" : "--$o=$v";
+               } elsif ($o =~ s/:[is]\z//) {
+                       my $v = $opt->{$o} // next;
+                       push @$cmd, $c ? "-$c$v" :
+                                       ($v eq '' ? "--$o" : "--$o=$v");
+               } elsif ($o =~ s/!\z//) {
+                       my $v = $opt->{$o} // next;
+                       push @$cmd, $v ? "--$o" : "--no-$o";
+               } elsif ($opt->{$o}) {
+                       push @$cmd, $c ? "-$c" : "--$o";
+               }
+       }
+}
+
 sub diff_ctxq ($$) {
        my ($self, $ctxq) = @_;
        return unless $ctxq;
@@ -103,37 +131,35 @@ EOM
        waitpid($pid, 0);
        die "fast-import failed: \$?=$?" if $?;
 
-       my @cmd = qw(diff);
-       my $opt = $lei->{opt};
-       push @cmd, '--'.($opt->{color} && !$opt->{'no-color'} ? '' : 'no-').
-                       'color';
-       for my $o (@PublicInbox::LEI::diff_opt) {
-               my $c = '';
-               # remove single char short option
-               $o =~ s/\|([a-z0-9])\b//i and $c = $1;
-               if ($o =~ s/=[is]@\z//) {
-                       my $v = $opt->{$o} or next;
-                       push @cmd, map { $c ? "-$c$_" : "--$o=$_" } @$v;
-               } elsif ($o =~ s/=[is]\z//) {
-                       my $v = $opt->{$o} // next;
-                       push @cmd, $c ? "-$c$v" : "--$o=$v";
-               } elsif ($o =~ s/:[is]\z//) {
-                       my $v = $opt->{$o} // next;
-                       push @cmd, $c ? "-$c$v" :
-                                       ($v eq '' ? "--$o" : "--$o=$v");
-               } elsif ($o =~ s/!\z//) {
-                       my $v = $opt->{$o} // next;
-                       push @cmd, $v ? "--$o" : "--no-$o";
-               } elsif ($opt->{$o}) {
-                       push @cmd, $c ? "-$c" : "--$o";
-               }
-       }
-       $lei->qerr("# git @cmd");
-       push @cmd, qw(A B);
-       unshift @cmd, 'git', "--git-dir=$rw->{git_dir}";
-       $pid = spawn(\@cmd, $lei->{env}, { 2 => $lei->{2}, 1 => $lei->{1} });
+       my $cmd = [ 'diff' ];
+       _lei_diff_prepare($lei, $cmd);
+       $lei->qerr("# git @$cmd");
+       push @$cmd, qw(A B);
+       unshift @$cmd, 'git', "--git-dir=$rw->{git_dir}";
+       $pid = spawn($cmd, $lei->{env}, { 2 => $lei->{2}, 1 => $lei->{1} });
        waitpid($pid, 0);
        $lei->child_error($?) if $?; # for git diff --exit-code
+       undef;
+}
+
+sub wait_requote ($$$) { # OnDestroy callback
+       my ($lei, $pid, $old_1) = @_;
+       $lei->{1} = $old_1; # closes stdin of `perl -pE 's/^/> /'`
+       waitpid($pid, 0) == $pid or die "BUG(?) waitpid: \$!=$! \$?=$?";
+       $lei->child_error($?) if $?;
+}
+
+sub requote ($$) {
+       my ($lei, $pfx) = @_;
+       pipe(my($r, $w)) or die "pipe: $!";
+       my $rdr = { 0 => $r, 1 => $lei->{1}, 2 => $lei->{2} };
+       # $^X (perl) is overkill, but maybe there's a weird system w/o sed
+       my $pid = spawn([$^X, '-pE', "s/^/$pfx/"], $lei->{env}, $rdr);
+       my $old_1 = $lei->{1};
+       $w->autoflush(1);
+       binmode $w, ':utf8';
+       $lei->{1} = $w;
+       PublicInbox::OnDestroy->new(\&wait_requote, $lei, $pid, $old_1);
 }
 
 sub extract_oids { # Eml each_part callback
@@ -142,6 +168,10 @@ sub extract_oids { # Eml each_part callback
        $self->{lei}->out($p->header_obj->as_string, "\n");
        my ($s, undef) = msg_part_text($p, $p->content_type || 'text/plain');
        defined $s or return;
+       my $rq;
+       if ($self->{dqre} && $s =~ s/$self->{dqre}//g) { # '> ' prefix(es)
+               $rq = requote($self->{lei}, $1) if $self->{lei}->{opt}->{drq};
+       }
        my @top = split($PublicInbox::ViewDiff::EXTRACT_DIFFS, $s);
        undef $s;
        my $blobs = $self->{blobs}; # blobs to resolve
@@ -191,15 +221,40 @@ sub extract_oids { # Eml each_part callback
        $ctxq = diff_ctxq($self, $ctxq);
 }
 
+# ensure dequoted parts are available for rebuilding patches:
+sub dequote_add { # Eml each_part callback
+       my ($ary, $self) = @_;
+       my ($p, undef, $idx) = @$ary;
+       my ($s, undef) = msg_part_text($p, $p->content_type || 'text/plain');
+       defined $s or return;
+       if ($s =~ s/$self->{dqre}//g) { # remove '> ' prefix(es)
+               substr($s, 0, 0, "part-dequoted: $idx\n\n");
+               utf8::encode($s);
+               $self->{tmp_sto}->add_eml(PublicInbox::Eml->new(\$s));
+       }
+}
+
 sub input_eml_cb { # callback for all emails
        my ($self, $eml) = @_;
-       $self->{tmp_sto}->add_eml($eml);
-       $self->{tmp_sto}->done;
+       {
+               local $SIG{__WARN__} = sub {
+                       return if "@_" =~ /^no email in From: .*? or Sender:/;
+                       return if PublicInbox::Eml::warn_ignore(@_);
+                       warn @_;
+               };
+               $self->{tmp_sto}->add_eml($eml);
+               $eml->each_part(\&dequote_add, $self) if $self->{dqre};
+               $self->{tmp_sto}->done;
+       }
        $eml->each_part(\&extract_oids, $self, 1);
 }
 
 sub lei_rediff {
        my ($lei, @inputs) = @_;
+       ($lei->{opt}->{drq} && $lei->{opt}->{'dequote-only'}) and return
+               $lei->fail('--drq and --dequote-only are mutually exclusive');
+       ($lei->{opt}->{drq} && !$lei->{opt}->{verbose}) and
+               $lei->{opt}->{quiet} //= 1;
        $lei->_lei_store(1)->write_prepare($lei);
        $lei->{opt}->{'in-format'} //= 'eml';
        # maybe it's a non-email (code) blob from a coderepo
@@ -224,10 +279,7 @@ sub lei_rediff {
        my $isatty = -t $lei->{1};
        $lei->{opt}->{color} //= $isatty;
        $lei->start_pager if $isatty;
-       my ($op_c, $ops) = $lei->workers_start($self, 1);
-       $lei->{wq1} = $self;
-       net_merge_all_done($self) unless $lei->{auth};
-       $lei->wait_wq_events($op_c, $ops);
+       $lei->wq1_start($self);
 }
 
 sub ipc_atfork_child {
@@ -248,12 +300,14 @@ sub ipc_atfork_child {
        $self->{gits} = [ map {
                        PublicInbox::Git->new($lei->rel2abs($_))
                } @{$self->{lei}->{opt}->{'git-dir'}} ];
-       $lei->{env}->{'psgi.errors'} = $lei->{2}; # ugh...
        $lei->{env}->{TMPDIR} = $self->{rdtmp}->dirname;
+       if (my $nr = ($lei->{opt}->{drq} || $lei->{opt}->{'dequote-only'})) {
+               my $re = '\s*> ' x $nr;
+               $self->{dqre} = qr/^($re)/ms;
+       }
        undef;
 }
 
 no warnings 'once';
 *net_merge_all_done = \&PublicInbox::LeiInput::input_only_net_merge_all_done;
-*net_merge_all = \&PublicInbox::LeiAuth::net_merge_all;
 1;