X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FLeiRediff.pm;h=f0521bcc6b623ae54963809754a9e0ae9f67aeca;hb=0054246c2d03fcc91bc899da5ef41a68f505e542;hp=d73e3e286f4f0c325d0dcb20c67a8d7f5fd8c38a;hpb=274d3476320aebc93ead7c5da4f716a12d43167f;p=public-inbox.git diff --git a/lib/PublicInbox/LeiRediff.pm b/lib/PublicInbox/LeiRediff.pm index d73e3e28..f0521bcc 100644 --- a/lib/PublicInbox/LeiRediff.pm +++ b/lib/PublicInbox/LeiRediff.pm @@ -23,14 +23,14 @@ sub rediff_user_cb { # called by solver when done my $lei = $self->{lei}; my $log_buf = delete $lei->{log_buf}; $$log_buf =~ s/^/# /sgm; - ref($res) eq 'ARRAY' or return $lei->child_error(1 << 8, $$log_buf); + ref($res) eq 'ARRAY' or return $lei->child_error(0, $$log_buf); $lei->qerr($$log_buf); my ($git, $oid, $type, $size, $di) = @$res; my $oid_want = delete $self->{cur_oid_want}; # 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(<{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; @@ -70,7 +98,6 @@ EOM my $tb = $ta; $tb =~ tr!A!B!; my $lei = $self->{lei}; - my $wait = delete($self->{-do_done}) ? $lei->{sto}->ipc_do('done') : 0; while (my ($oid_a, $oid_b, $pa, $pb, $ma, $mb) = splice(@$ctxq, 0, 6)) { my $xa = $blob->{$oid_a} //= solve_1($self, $oid_a, { path_b => $pa }); @@ -104,36 +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) { - $o =~ s/\|([a-z0-9])\b//i; # remove single char short option - my $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,17 +221,41 @@ 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->{lei}->{sto}->ipc_do('add_eml', $eml); - $self->{-do_done} = 1; + { + 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}->{stdin} = 1 if !@inputs; $lei->{opt}->{'in-format'} //= 'eml'; # maybe it's a non-email (code) blob from a coderepo my $git_dirs = $lei->{opt}->{'git-dir'} //= []; @@ -216,7 +270,7 @@ sub lei_rediff { $lei->{curl} //= which('curl') or return $lei->fail('curl needed for', $lxs->remotes); } - $lei->ale->refresh_externals($lxs); + $lei->ale->refresh_externals($lxs, $lei); my $self = bless { -force_eml => 1, # for LeiInput->input_fh lxs => $lxs, @@ -225,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}; - $op_c->op_wait_event($ops); + $lei->wq1_start($self); } sub ipc_atfork_child { @@ -239,18 +290,24 @@ sub ipc_atfork_child { binmode $lei->{1}, ':utf8'; $self->{blobs} = {}; # oidhex => filename $self->{rdtmp} = File::Temp->newdir('lei-rediff-XXXX', TMPDIR => 1); - $self->{rmt} = [ map { + $self->{tmp_sto} = PublicInbox::LeiStore->new( + "$self->{rdtmp}/tmp.store", + { creat => { nproc => 1 }, indexlevel => 'medium' }); + $self->{tmp_sto}->{priv_eidx}->{parallel} = 0; + $self->{rmt} = [ $self->{tmp_sto}->search, map { PublicInbox::LeiRemote->new($lei, $_) } $self->{lxs}->remotes ]; $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;