]> Sergey Matveev's repositories - public-inbox.git/commitdiff
Merge remote-tracking branch 'origin/danga-bundle'
authorEric Wong <e@80x24.org>
Wed, 8 May 2019 19:24:07 +0000 (19:24 +0000)
committerEric Wong <e@80x24.org>
Wed, 8 May 2019 19:24:07 +0000 (19:24 +0000)
* origin/danga-bundle:
  DS: epoll: fix misordered EPOLL_CTL_DEL call
  DS: drop unused "_undef" sub
  syscall: drop readahead wrapper
  build: do not manify DS and Syscall pods
  DS: handle EINTR in IO::Poll path, too
  DS: workaround IO::Kqueue EINTR (mis-)handling
  DS: drop profiling support
  DS: remove unused fields and functions
  listener: use EPOLLEXCLUSIVE for listen sockets
  bundle Danga::Socket and Sys::Syscall

15 files changed:
Documentation/public-inbox-config.pod
INSTALL
MANIFEST
lib/PublicInbox/Config.pm
lib/PublicInbox/Inbox.pm
lib/PublicInbox/NNTP.pm
lib/PublicInbox/SearchIdxPart.pm
lib/PublicInbox/Spawn.pm
lib/PublicInbox/V2Writable.pm
lib/PublicInbox/WWW.pm
lib/PublicInbox/WwwListing.pm [new file with mode: 0644]
lib/PublicInbox/WwwStream.pm
script/public-inbox-index
t/search.t
t/v2writable.t

index 291502205e0618c974d2e04732a92d7b05fe27f0..d44c8f30777adb03c04f63e4fab121938a2da0d6 100644 (file)
@@ -188,6 +188,14 @@ be treated as the default value.
 
 Default: 25
 
+=item publicinbox.<name>.hide
+
+A comma-delimited list of listings to hide the inbox from.
+
+Valid values are currently "www".
+
+Default: none
+
 =item coderepo.<nick>.dir
 
 The path to a git repository for "publicinbox.<name>.coderepo"
@@ -226,6 +234,35 @@ C<publicinbox.cgitbin>, but may be overridden.
 Default: basename of C<publicinbox.cgitbin>, /var/www/htdocs/cgit/
 or /usr/share/cgit/
 
+=item publicinbox.wwwlisting
+
+Enable a HTML listing style when the root path of the URL '/' is accessed.
+Valid values are:
+
+=over 8
+
+=item all
+
+Show all inboxes
+
+=item 404
+
+Return a 404 page.  This is useful to allow customization with
+L<Plack::App::Cascade(3pm)>
+
+=item match=domain
+
+Only show inboxes with URLs which belong to the domain of the HTTP
+request
+
+=for TODO comment
+
+support showing cgit listing
+
+=back
+
+Default: 404
+
 =back
 
 =head2 NAMED LIMITER (PSGI)
diff --git a/INSTALL b/INSTALL
index 3c0b9108e5f0aba8e08fd1dfa21c7203cc6676ec..fafaf577683a811b20359ca894ec3de3dae2b669 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -22,7 +22,7 @@ public-inbox requires a number of other packages to access its full
 functionality.  The core tools are, of course:
 
 * Git (1.8.0+, 2.6+ for writing v2 repositories)
-* Perl 5.8+
+* Perl 5.10.1+
 * SQLite (needed for Xapian use)
 
 To accept incoming mail into a public inbox, you'll likely want:
index afe5ae1cd19f88b975982b2f81caef9932ab4d9c..da9e36457d5c2c4d51d5d7cd00631afb2858a6e4 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -131,6 +131,7 @@ lib/PublicInbox/WatchMaildir.pm
 lib/PublicInbox/WwwAtomStream.pm
 lib/PublicInbox/WwwAttach.pm
 lib/PublicInbox/WwwHighlight.pm
+lib/PublicInbox/WwwListing.pm
 lib/PublicInbox/WwwStream.pm
 lib/PublicInbox/WwwText.pm
 sa_config/Makefile
index 631c7880f331de489ea654e22825fa4e86be5819..09f9179b085a4dd90aed20e0d8b277ede66cc870 100644 (file)
@@ -389,7 +389,7 @@ sub _fill {
        }
        # TODO: more arrays, we should support multi-value for
        # more things to encourage decentralization
-       foreach my $k (qw(address altid nntpmirror coderepo)) {
+       foreach my $k (qw(address altid nntpmirror coderepo hide)) {
                if (defined(my $v = $self->{"$pfx.$k"})) {
                        $ibx->{$k} = _array($v);
                }
index 0d28dd04023e95338e456c8ac2f7403f71bcca12..286555f65cb3b4c8f4a7820b0489e4f6f6005e72 100644 (file)
@@ -95,6 +95,15 @@ sub new {
        if (defined $dir && -f "$dir/inbox.lock") {
                $opts->{version} = 2;
        }
+
+       # allow any combination of multi-line or comma-delimited hide entries
+       my $hide = {};
+       if (defined(my $h = $opts->{hide})) {
+               foreach my $v (@$h) {
+                       $hide->{$_} = 1 foreach (split(/\s*,\s*/, $v));
+               }
+               $opts->{-hide} = $hide;
+       }
        bless $opts, $class;
 }
 
index f756e92c64b39793c682dce067c9af4473d782c3..5c5df7b0dcbe548c0284504c84ec64f782de8d18 100644 (file)
@@ -122,7 +122,7 @@ sub args_ok ($$) {
 sub process_line ($$) {
        my ($self, $l) = @_;
        my ($req, @args) = split(/\s+/, $l);
-       return unless defined($req);
+       return 1 unless defined($req); # skip blank line
        $req = lc($req);
        $req = eval {
                no strict 'refs';
index 7fe2120a425488eb0c076aeb35825dd681101081..51d81a0a21560ef73cac1776f5176f8a29df16e0 100644 (file)
@@ -48,8 +48,15 @@ sub spawn_worker {
 sub partition_worker_loop ($$$$) {
        my ($self, $r, $part, $bnote) = @_;
        $0 = "pi-v2-partition[$part]";
+       my $current_info = '';
+       my $warn_cb = $SIG{__WARN__} || sub { print STDERR @_ };
+       local $SIG{__WARN__} = sub {
+               chomp $current_info;
+               $warn_cb->("[$part] $current_info: ", @_);
+       };
        $self->begin_txn_lazy;
        while (my $line = $r->getline) {
+               $current_info = $line;
                if ($line eq "commit\n") {
                        $self->commit_txn_lazy;
                } elsif ($line eq "close\n") {
index 7b0f3bdde6637f356e14be70790b77914c44a060..66b916dfbc72d60c28c57cdddd63a88d1b8d7966 100644 (file)
@@ -26,22 +26,35 @@ my $vfork_spawn = <<'VFORK_SPAWN';
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <unistd.h>
-#include <alloca.h>
-#include <signal.h>
-#include <assert.h>
+#include <stdlib.h>
 
-#define AV_ALLOCA(av, max) alloca((max = (av_len((av)) + 1)) * sizeof(char *))
+/* some platforms need alloca.h, but some don't */
+#if defined(__GNUC__) && !defined(alloca)
+#  define alloca(sz) __builtin_alloca(sz)
+#endif
 
-static void av2c_copy(char **dst, AV *src, I32 max)
-{
-       I32 i;
+#include <signal.h>
+#include <assert.h>
 
-       for (i = 0; i < max; i++) {
-               SV **sv = av_fetch(src, i, 0);
-               dst[i] = sv ? SvPV_nolen(*sv) : 0;
-       }
-       dst[max] = 0;
-}
+/*
+ * From the av_len apidoc:
+ *   Note that, unlike what the name implies, it returns
+ *   the highest index in the array, so to get the size of
+ *   the array you need to use "av_len(av) + 1".
+ *   This is unlike "sv_len", which returns what you would expect.
+ */
+#define AV2C_COPY(dst, src) do { \
+       I32 i; \
+       I32 top_index = av_len(src); \
+       I32 real_len = top_index + 1; \
+       I32 capa = real_len + 1; \
+       dst = alloca(capa * sizeof(char *)); \
+       for (i = 0; i < real_len; i++) { \
+               SV **sv = av_fetch(src, i, 0); \
+               dst[i] = SvPV_nolen(*sv); \
+       } \
+       dst[real_len] = 0; \
+} while (0)
 
 static void *deconst(const char *s)
 {
@@ -86,15 +99,11 @@ int pi_fork_exec(int in, int out, int err,
        const char *filename = SvPV_nolen(file);
        pid_t pid;
        char **argv, **envp;
-       I32 max;
        sigset_t set, old;
        int ret, errnum;
 
-       argv = AV_ALLOCA(cmd, max);
-       av2c_copy(argv, cmd, max);
-
-       envp = AV_ALLOCA(env, max);
-       av2c_copy(envp, env, max);
+       AV2C_COPY(argv, cmd);
+       AV2C_COPY(envp, env);
 
        ret = sigfillset(&set);
        assert(ret == 0 && "BUG calling sigfillset");
index 6829a34376105fcd00c1402d0e2a3dbfad7e0b6b..87e8f3eb581a97076b5fd22ea5af917bb623306e 100644 (file)
@@ -72,6 +72,7 @@ sub new {
                im => undef, #  PublicInbox::Import
                parallel => 1,
                transact_bytes => 0,
+               current_info => '',
                xpfx => $xpfx,
                over => PublicInbox::OverIdx->new("$xpfx/over.sqlite3", 1),
                lock_path => "$dir/inbox.lock",
@@ -949,8 +950,10 @@ sub index_sync {
                my $fh = $self->{reindex_pipe} = $git->popen(@cmd, $range);
                my $cmt;
                while (<$fh>) {
+                       chomp;
+                       $self->{current_info} = "$i.git $_";
                        if (/\A$x40$/o && !defined($cmt)) {
-                               chomp($cmt = $_);
+                               $cmt = $_;
                        } elsif (/\A:\d{6} 100644 $x40 ($x40) [AM]\tm$/o) {
                                $self->reindex_oid($mm_tmp, $D, $git, $1,
                                                $regen, $reindex);
index 6e69001c4c4d78fa2e52fc851525c30bfd8f7a59..1f3ca1574aa0c5c84c43dcc31d8797f08b6de5e6 100644 (file)
@@ -11,7 +11,7 @@
 # - Must not rely on static content
 # - UTF-8 is only for user-content, 7-bit US-ASCII for us
 package PublicInbox::WWW;
-use 5.008;
+use 5.010_001;
 use strict;
 use warnings;
 use bytes (); # only for bytes::length
@@ -68,8 +68,9 @@ sub call {
        } split(/[&;]+/, $env->{QUERY_STRING});
        $ctx->{qp} = \%qp;
 
-       # not using $env->{PATH_INFO} here since that's already decoded
+       # avoiding $env->{PATH_INFO} here since that's already decoded
        my ($path_info) = ($env->{REQUEST_URI} =~ path_re($env));
+       $path_info //= $env->{PATH_INFO};
        my $method = $env->{REQUEST_METHOD};
 
        if ($method eq 'POST') {
@@ -87,7 +88,7 @@ sub call {
 
        # top-level indices and feeds
        if ($path_info eq '/') {
-               r404();
+               www_listing($self)->call($env);
        } elsif ($path_info =~ m!$INBOX_RE\z!o) {
                invalid_inbox($ctx, $1) || r301($ctx, $1);
        } elsif ($path_info =~ m!$INBOX_RE(?:/|/index\.html)?\z!o) {
@@ -157,6 +158,7 @@ sub preload {
        if (ref($self)) {
                $self->cgit;
                $self->stylesheets_prepare($_) for ('', '../', '../../');
+               $self->www_listing;
        }
 }
 
@@ -489,6 +491,14 @@ sub cgit {
        }
 }
 
+sub www_listing {
+       my ($self) = @_;
+       $self->{www_listing} ||= do {
+               require PublicInbox::WwwListing;
+               PublicInbox::WwwListing->new($self);
+       }
+}
+
 sub get_attach {
        my ($ctx, $idx, $fn) = @_;
        require PublicInbox::WwwAttach;
diff --git a/lib/PublicInbox/WwwListing.pm b/lib/PublicInbox/WwwListing.pm
new file mode 100644 (file)
index 0000000..e8dad4b
--- /dev/null
@@ -0,0 +1,104 @@
+# Copyright (C) 2019 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+# Provide an HTTP-accessible listing of inboxes.
+# Used by PublicInbox::WWW
+package PublicInbox::WwwListing;
+use strict;
+use warnings;
+use PublicInbox::Hval qw(ascii_html);
+use PublicInbox::Linkify;
+use PublicInbox::View;
+
+sub list_all ($$) {
+       my ($self, undef) = @_;
+       my @list;
+       $self->{pi_config}->each_inbox(sub {
+               my ($ibx) = @_;
+               push @list, $ibx unless $ibx->{-hide}->{www};
+       });
+       \@list;
+}
+
+sub list_match_domain ($$) {
+       my ($self, $env) = @_;
+       my @list;
+       my $host = $env->{HTTP_HOST} // $env->{SERVER_NAME};
+       $host =~ s/:\d+\z//;
+       my $re = qr!\A(?:https?:)?//\Q$host\E(?::\d+)?/!i;
+       $self->{pi_config}->each_inbox(sub {
+               my ($ibx) = @_;
+               push @list, $ibx if !$ibx->{-hide}->{www} && $ibx->{url} =~ $re;
+       });
+       \@list;
+}
+
+sub list_404 ($$) { [] }
+
+# TODO: +cgit
+my %VALID = (
+       all => *list_all,
+       'match=domain' => *list_match_domain,
+       404 => *list_404,
+);
+
+sub new {
+       my ($class, $www) = @_;
+       my $k = 'publicinbox.wwwListing';
+       my $pi_config = $www->{pi_config};
+       my $v = $pi_config->{lc($k)} // 404;
+       bless {
+               pi_config => $pi_config,
+               style => $www->style("\0"),
+               list_cb => $VALID{$v} || do {
+                       warn <<"";
+`$v' is not a valid value for `$k'
+$k be one of `all', `match=domain', or `404'
+
+                       *list_404;
+               },
+       }, $class;
+}
+
+sub ibx_entry {
+       my ($mtime, $ibx, $env) = @_;
+       my $ts = PublicInbox::View::fmt_ts($mtime);
+       my $url = PublicInbox::Hval::prurl($env, $ibx->{url});
+       my $tmp = <<"";
+* $ts - $url
+  ${\$ibx->description}
+
+       if (defined(my $info_url = $ibx->{info_url})) {
+               $tmp .= "\n$info_url";
+       }
+       $tmp;
+}
+
+# not really a stand-alone PSGI app, but maybe it could be...
+sub call {
+       my ($self, $env) = @_;
+       my $h = [ 'Content-Type', 'text/html; charset=UTF-8' ];
+       my $list = $self->{list_cb}->($self, $env);
+       my $code = 404;
+       my $title = 'public-inbox';
+       my $out = '';
+       if (@$list) {
+               # Swartzian transform since ->modified is expensive
+               @$list = sort {
+                       $b->[0] <=> $a->[0]
+               } map { [ $_->modified, $_ ] } @$list;
+
+               $code = 200;
+               $title .= ' - listing';
+               my $tmp = join("\n", map { ibx_entry(@$_, $env) } @$list);
+               my $l = PublicInbox::Linkify->new;
+               $l->linkify_1($tmp);
+               $out = '<pre>'.$l->linkify_2(ascii_html($tmp)).'</pre><hr>';
+       }
+       $out = "<html><head><title>$title</title></head><body>" . $out;
+       $out .= '<pre>'. PublicInbox::WwwStream::code_footer($env) .
+               '</pre></body></html>';
+       [ $code, $h, [ $out ] ]
+}
+
+1;
index ea7aaad0a76024ec7a04adb75a84c9b913d15810..f6c504966e5b037413faf053a8777f84353d0250 100644 (file)
@@ -10,7 +10,6 @@ package PublicInbox::WwwStream;
 use strict;
 use warnings;
 use PublicInbox::Hval qw(ascii_html);
-use URI;
 our $TOR_URL = 'https://www.torproject.org/';
 our $CODE_URL = 'https://public-inbox.org/';
 our $PROJECT = 'public-inbox';
@@ -70,6 +69,12 @@ sub _html_top ($) {
                "</head><body>". $top . $tip;
 }
 
+sub code_footer ($) {
+       my ($env) = @_;
+       my $u = PublicInbox::Hval::prurl($env, $CODE_URL);
+       qq(AGPL code for this site: git clone <a\nhref="$u">$u</a> $PROJECT)
+}
+
 sub _html_end {
        my ($self) = @_;
        my $urls = 'Archives are clonable:';
@@ -134,12 +139,10 @@ EOF
                $urls .= "\n note: .onion URLs require Tor: ";
                $urls .= qq[<a\nhref="$TOR_URL">$TOR_URL</a>];
        }
-       my $url = PublicInbox::Hval::prurl($ctx->{env}, $CODE_URL);
        '<hr><pre>'.join("\n\n",
                $desc,
                $urls,
-               'AGPL code for this site: '.
-               qq(git clone <a\nhref="$url">$url</a> $PROJECT)
+               code_footer($ctx->{env})
        ).'</pre></body></html>';
 }
 
index 5adb6e741eff8f2578a780bd40738cd7c42ee7a6..2f810a564f01367a592c0862705074e077a193c9 100755 (executable)
@@ -85,6 +85,9 @@ sub index_dir {
                                }
                        }
                }
+               local $SIG{__WARN__} = sub {
+                       print STDERR $v2w->{current_info}, ': ', @_;
+               };
                $v2w->index_sync({ reindex => $reindex, prune => $prune });
        } else {
                my $s = PublicInbox::SearchIdx->new($repo, 1);
index 6415a644b5808f1ba693c9ff67f4b03e1841229b..35d71473e29a8bf9e71178ed5d774982775dc0ad 100644 (file)
@@ -430,13 +430,23 @@ $ibx->with_umask(sub {
        is($ro->lookup_article($art->{num}), undef, 'gone from OVER DB') if defined($art);
 });
 
+my $all_mask = 07777;
+my $dir_mask = 02770;
+
+# FreeBSD does not allow non-root users to set S_ISGID, so
+# git doesn't set it, either (see DIR_HAS_BSD_GROUP_SEMANTICS in git.git)
+if ($^O =~ /freebsd/i) {
+       $all_mask = 0777;
+       $dir_mask = 0770;
+}
+
 foreach my $f ("$git_dir/public-inbox/msgmap.sqlite3",
                "$git_dir/public-inbox",
                glob("$git_dir/public-inbox/xapian*/"),
                glob("$git_dir/public-inbox/xapian*/*")) {
        my @st = stat($f);
        my ($bn) = (split(m!/!, $f))[-1];
-       is($st[2] & 07777, -f _ ? 0660 : 02770,
+       is($st[2] & $all_mask, -f _ ? 0660 : $dir_mask,
                "sharedRepository respected for $bn");
 }
 
index 06b2251999f08ba0abf7d35035f1bdacac82d28f..f8ef415acc51061b30fbd006ee491edb74c7c536 100644 (file)
@@ -253,10 +253,9 @@ EOF
 }
 
 {
-       my @warn;
        my $x = 'x'x250;
        my $y = 'y'x250;
-       local $SIG{__WARN__} = sub { push @warn, @_ };
+       local $SIG{__WARN__} = sub {};
        $mime->header_set('Subject', 'long mid');
        $mime->header_set('Message-ID', "<$x>");
        ok($im->add($mime), 'add excessively long Message-ID');