]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/LeiInput.pm
lei_input: support compressed mboxes
[public-inbox.git] / lib / PublicInbox / LeiInput.pm
index 859fdb110636f9847136e9724161180e3e5a3765..505b73ff6df0a8c27ef8c12ed581252e90f93b6d 100644 (file)
@@ -14,9 +14,9 @@ sub check_input_format ($;$) {
                my $err = $files ? "regular file(s):\n@$files" : '--stdin';
                return $lei->fail("--$opt_key unset for $err");
        }
+       return 1 if $fmt eq 'eml';
        require PublicInbox::MboxLock if $files;
        require PublicInbox::MboxReader;
-       return 1 if $fmt eq 'eml';
        # XXX: should this handle {gz,bz2,xz}? that's currently in LeiToMail
        PublicInbox::MboxReader->reads($fmt) or
                return $lei->fail("--$opt_key=$fmt unrecognized");
@@ -24,7 +24,7 @@ sub check_input_format ($;$) {
 }
 
 # import a single file handle of $name
-# Subclass must define ->eml_cb and ->mbox_cb
+# Subclass must define ->input_eml_cb and ->input_mbox_cb
 sub input_fh {
        my ($self, $ifmt, $fh, $name, @args) = @_;
        if ($ifmt eq 'eml') {
@@ -36,26 +36,75 @@ error reading $name: $!
                # but no Content-Length or "From " escaping.
                # "git format-patch" also generates such files by default.
                $buf =~ s/\A[\r\n]*From [^\r\n]*\r?\n//s;
-               $self->eml_cb(PublicInbox::Eml->new(\$buf), @args);
+               $self->input_eml_cb(PublicInbox::Eml->new(\$buf), @args);
        } else {
                # prepare_inputs already validated $ifmt
                my $cb = PublicInbox::MboxReader->reads($ifmt) //
                                die "BUG: bad fmt=$ifmt";
-               $cb->(undef, $fh, $self->can('mbox_cb'), $self, @args);
+               $cb->(undef, $fh, $self->can('input_mbox_cb'), $self, @args);
        }
 }
 
-sub prepare_inputs {
+sub input_path_url {
+       my ($self, $input, @args) = @_;
+       my $lei = $self->{lei};
+       my $ifmt = lc($lei->{opt}->{'in-format'} // '');
+       # TODO auto-detect?
+       if ($input =~ m!\Aimaps?://!i) {
+               $lei->{net}->imap_each($input, $self->can('input_net_cb'),
+                                       $self, @args);
+               return;
+       } elsif ($input =~ m!\A(?:nntps?|s?news)://!i) {
+               $lei->{net}->nntp_each($input, $self->can('input_net_cb'),
+                                       $self, @args);
+               return;
+       }
+       if ($input =~ s!\A([a-z0-9]+):!!i) {
+               $ifmt = lc($1);
+       } elsif ($input =~ /\.(?:patch|eml)\z/i) {
+               $ifmt = 'eml';
+       }
+       my $devfd = $lei->path_to_fd($input) // return;
+       if ($devfd >= 0) {
+               $self->input_fh($ifmt, $lei->{$devfd}, $input, @args);
+       } elsif (-f $input && $ifmt eq 'eml') {
+               open my $fh, '<', $input or
+                                       return $lei->fail("open($input): $!");
+               $self->input_fh($ifmt, $fh, $input, @args);
+       } elsif (-f _) {
+               my $m = $lei->{opt}->{'lock'} //
+                       PublicInbox::MboxLock->defaults;
+               my $mbl = PublicInbox::MboxLock->acq($input, 0, $m);
+               my $zsfx = PublicInbox::MboxReader::zsfx($input);
+               if ($zsfx) {
+                       my $in = delete $mbl->{fh};
+                       $mbl->{fh} =
+                            PublicInbox::MboxReader::zsfxcat($in, $zsfx, $lei);
+               }
+               local $PublicInbox::DS::in_loop = 0 if $zsfx; # dwaitpid
+               $self->input_fh($ifmt, $mbl->{fh}, $input, @args);
+       } elsif (-d _ && (-d "$input/cur" || -d "$input/new")) {
+               return $lei->fail(<<EOM) if $ifmt && $ifmt ne 'maildir';
+$input appears to a be a maildir, not $ifmt
+EOM
+               PublicInbox::MdirReader::maildir_each_eml($input,
+                                       $self->can('input_maildir_cb'),
+                                       $self, @args);
+       } else {
+               $lei->fail("$input unsupported (TODO)");
+       }
+}
+
+sub prepare_inputs { # returns undef on error
        my ($self, $lei, $inputs) = @_;
        my $in_fmt = $lei->{opt}->{'in-format'};
        if ($lei->{opt}->{stdin}) {
                @$inputs and return
                        $lei->fail("--stdin and @$inputs do not mix");
                check_input_format($lei) or return;
-               $self->{0} = $lei->{0};
+               push @$inputs, '/dev/stdin';
        }
        my $net = $lei->{net}; # NetWriter may be created by l2m
-       my $fmt = $lei->{opt}->{'in-format'};
        my (@f, @d);
        # e.g. Maildir:/home/user/Mail/ or imaps://example.com/INBOX
        for my $input (@$inputs) {
@@ -71,21 +120,34 @@ sub prepare_inputs {
 --in-format=$in_fmt and `$ifmt:' conflict
 
                        }
-                       if (-f $input_path) {
+                       my $devfd = $lei->path_to_fd($input_path) // return;
+                       if ($devfd >= 0 || (-f $input_path || -p _)) {
                                require PublicInbox::MboxLock;
                                require PublicInbox::MboxReader;
                                PublicInbox::MboxReader->reads($ifmt) or return
                                        $lei->fail("$ifmt not supported");
-                       } elsif (-d _) {
+                       } elsif (-d $input_path) {
                                require PublicInbox::MdirReader;
                                $ifmt eq 'maildir' or return
                                        $lei->fail("$ifmt not supported");
                        } else {
                                return $lei->fail("Unable to handle $input");
                        }
-               } elsif (-f $input) { push @f, $input }
-               elsif (-d _) { push @d, $input }
-               else { return $lei->fail("Unable to handle $input") }
+               } elsif ($input =~ /\.(eml|patch)\z/i && -f $input) {
+                       lc($in_fmt//'eml') eq 'eml' or return $lei->fail(<<"");
+$input is `eml', not --in-format=$in_fmt
+
+                       require PublicInbox::Eml;
+               } else {
+                       my $devfd = $lei->path_to_fd($input) // return;
+                       if ($devfd >= 0 || -f $input || -p _) {
+                               push @f, $input
+                       } elsif (-d $input) {
+                               push @d, $input
+                       } else {
+                               return $lei->fail("Unable to handle $input")
+                       }
+               }
        }
        if (@f) { check_input_format($lei, \@f) or return }
        if (@d) { # TODO: check for MH vs Maildir, here
@@ -103,4 +165,13 @@ sub prepare_inputs {
        $self->{inputs} = $inputs;
 }
 
+sub input_only_atfork_child {
+       my ($self) = @_;
+       my $lei = $self->{lei};
+       $lei->_lei_atfork_child;
+       PublicInbox::IPC::ipc_atfork_child($self);
+       $lei->{auth}->do_auth_atfork($self) if $lei->{auth};
+       undef;
+}
+
 1;