--help / -h is now supported for all user-run scripts (though not public-inbox.cgi). I'm dropping -? support since it never made it into a release; -h is more consistent with other CLI tools out there (notably git). init + convert now creates deep directories like "git init". Some minor cleanups and future proofing along the way, too. Eric Wong (10): script/*: set executable bit on -learn and -imapd admin: improve minimum version text edit+purge: support `--help' and `-h' like other commands script/*: fold $usage into $help, support `-h' instead of -? daemon: support --help/-h in -httpd/imapd/nntpd mda+learn: add --help / -h support config: use defined-or (//) in a few places watch: add --help/-h support doc: remove B<> (bold) markup from the remaining POD init+convert: create non-existing directory hierarchies Documentation/public-inbox-edit.pod | 2 +- Documentation/public-inbox-httpd.pod | 2 +- Documentation/public-inbox-imapd.pod | 2 +- Documentation/public-inbox-learn.pod | 2 +- Documentation/public-inbox-mda.pod | 2 +- Documentation/public-inbox-nntpd.pod | 2 +- Documentation/public-inbox-watch.pod | 2 +- lib/PublicInbox/Admin.pm | 2 +- lib/PublicInbox/AdminEdit.pm | 2 +- lib/PublicInbox/Config.pm | 6 ++---- lib/PublicInbox/Daemon.pm | 19 +++++++++++++++++-- script/public-inbox-compact | 9 ++++----- script/public-inbox-convert | 21 ++++++++++----------- script/public-inbox-edit | 21 ++++++++++++++++++--- script/public-inbox-imapd | 0 script/public-inbox-index | 10 ++++------ script/public-inbox-init | 17 +++++++++++------ script/public-inbox-learn | 23 ++++++++++++++++++----- script/public-inbox-mda | 18 ++++++++++++++---- script/public-inbox-purge | 17 ++++++++++++++--- script/public-inbox-watch | 18 ++++++++++++++---- script/public-inbox-xcpdb | 8 +++----- t/convert-compact.t | 20 ++++++++++---------- t/init.t | 12 ++++++++++++ 24 files changed, 160 insertions(+), 77 deletions(-) mode change 100644 => 100755 script/public-inbox-imapd mode change 100644 => 100755 script/public-inbox-learn
It's useful to mark they're meant to be executable, even if the shebang is useless. --- script/public-inbox-imapd | 0 script/public-inbox-learn | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 script/public-inbox-imapd mode change 100644 => 100755 script/public-inbox-learn diff --git a/script/public-inbox-imapd b/script/public-inbox-imapd old mode 100644 new mode 100755 diff --git a/script/public-inbox-learn b/script/public-inbox-learn old mode 100644 new mode 100755
"inboxes 1 inboxes not supported by ..." was non-sensical. Now it'll show "-V1 inbox not supported by ...", instead. --- lib/PublicInbox/Admin.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/PublicInbox/Admin.pm b/lib/PublicInbox/Admin.pm index b8ead6f7..fb88e621 100644 --- a/lib/PublicInbox/Admin.pm +++ b/lib/PublicInbox/Admin.pm @@ -131,7 +131,7 @@ EOF } } if (@old) { - die "inboxes $min_ver inboxes not supported by $0\n\t", + die "-V$min_ver inboxes not supported by $0\n\t", join("\n\t", @old), "\n"; } @ibxs;
And while we're at it, note edit is *destructive* to encourage reading the fine manual. --- Documentation/public-inbox-edit.pod | 2 +- lib/PublicInbox/AdminEdit.pm | 2 +- script/public-inbox-edit | 21 ++++++++++++++++++--- script/public-inbox-purge | 17 ++++++++++++++--- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Documentation/public-inbox-edit.pod b/Documentation/public-inbox-edit.pod index 68180872..55d1c163 100644 --- a/Documentation/public-inbox-edit.pod +++ b/Documentation/public-inbox-edit.pod @@ -1,6 +1,6 @@ =head1 NAME -public-inbox-edit - edit messages in a public inbox +public-inbox-edit - destructively edit messages in a public inbox =head1 SYNOPSIS diff --git a/lib/PublicInbox/AdminEdit.pm b/lib/PublicInbox/AdminEdit.pm index 25abfd8e..4448dcc2 100644 --- a/lib/PublicInbox/AdminEdit.pm +++ b/lib/PublicInbox/AdminEdit.pm @@ -6,7 +6,7 @@ package PublicInbox::AdminEdit; use strict; use warnings; use PublicInbox::Admin; -our @OPT = qw(all force|f verbose|v!); +our @OPT = qw(all force|f verbose|v! help|h); sub check_editable ($) { my ($ibxs) = @_; diff --git a/script/public-inbox-edit b/script/public-inbox-edit index 240beb3a..a70614fc 100755 --- a/script/public-inbox-edit +++ b/script/public-inbox-edit @@ -16,11 +16,26 @@ use PublicInbox::Eml; use PublicInbox::InboxWritable qw(eml_from_path); use PublicInbox::Import; -my $usage = "$0 -m MESSAGE_ID [--all] [INBOX_DIRS]"; +my $help = <<'EOF'; +usage: public-inbox-edit -m MESSAGE-ID [--all] [INBOX_DIRS] + + destructively edit messages in a public inbox + +options: + + --all edit all configured inboxes + -m MESSAGE-ID edit the message with a given Message-ID + -F FILE edit the message matching the contents of FILE + --force forcibly edit even if Message-ID is ambiguous + --raw do not perform "From " line escaping + +See public-inbox-edit(1) man page for full documentation. +EOF + my $opt = { verbose => 1, all => 0, -min_inbox_version => 2, raw => 0 }; my @opt = qw(mid|m=s file|F=s raw); -GetOptions($opt, @PublicInbox::AdminEdit::OPT, @opt) or - die "bad command-line args\n$usage\n"; +GetOptions($opt, @PublicInbox::AdminEdit::OPT, @opt) or die $help; +if ($opt->{help}) { print $help; exit 0 }; my $cfg = PublicInbox::Config->new; my $editor = $ENV{MAIL_EDITOR}; # e.g. "mutt -f" diff --git a/script/public-inbox-purge b/script/public-inbox-purge index 82a63b80..7bca11ea 100755 --- a/script/public-inbox-purge +++ b/script/public-inbox-purge @@ -13,10 +13,21 @@ use PublicInbox::Filter::Base qw(REJECT); use PublicInbox::Eml; require PublicInbox::V2Writable; -my $usage = "$0 [--all] [INBOX_DIRS] </path/to/message"; +my $help = <<EOF; +usage: public-inbox-purge [--all] [INBOX_DIRS] </path/to/message + + erase message entirely from an inbox (including history) + +options: + + --all purge from all configured inboxes + +See public-inbox-purge(1) man page for full documentation. +EOF + my $opt = { verbose => 1, all => 0, -min_inbox_version => 2 }; -GetOptions($opt, @PublicInbox::AdminEdit::OPT) or - die "bad command-line args\n$usage\n"; +GetOptions($opt, @PublicInbox::AdminEdit::OPT) or die $help; +if ($opt->{help}) { print $help; exit 0 }; my @ibxs = PublicInbox::Admin::resolve_inboxes(\@ARGV, $opt); PublicInbox::AdminEdit::check_editable(\@ibxs);
`-h' doesn't conflict with anything, and some users (including git users) may be more accustomed to using it rather than the rarely-seen-outside-of-Getopt::Long `-?' switch. We can also rely on the GetOptions() function to emit a proper error message instead of just "bad command-line args". --- script/public-inbox-compact | 9 ++++----- script/public-inbox-convert | 14 +++++--------- script/public-inbox-index | 10 ++++------ script/public-inbox-init | 7 +++---- script/public-inbox-xcpdb | 8 +++----- 5 files changed, 19 insertions(+), 29 deletions(-) diff --git a/script/public-inbox-compact b/script/public-inbox-compact index a6bb62bd..dfebac1c 100755 --- a/script/public-inbox-compact +++ b/script/public-inbox-compact @@ -4,10 +4,9 @@ use strict; use v5.10.1; use Getopt::Long qw(:config gnu_getopt no_ignore_case auto_abbrev); -my $usage = 'public-inbox-compact INBOX_DIR'; my $opt = { compact => 1, -coarse_lock => 1 }; my $help = <<EOF; # the following should fit w/o scrolling in 80x24 term: -Usage: $usage +usage: public-inbox-compact INBOX_DIR Compact Xapian DBs in an inbox @@ -18,10 +17,10 @@ options: See public-inbox-compact(1) man page for full documentation. EOF -GetOptions($opt, qw(all help|?), +GetOptions($opt, qw(all help|h), # compact options: qw(jobs|j=i quiet|q blocksize|b=s no-full|n fuller|F), -) or die "bad command-line args\n$usage\n"; +) or die $help; if ($opt->{help}) { print $help; exit 0 }; require PublicInbox::Admin; @@ -31,7 +30,7 @@ PublicInbox::Admin::progress_prepare($opt); require PublicInbox::InboxWritable; require PublicInbox::Xapcmd; my @ibxs = PublicInbox::Admin::resolve_inboxes(\@ARGV, $opt); -unless (@ibxs) { print STDERR "Usage: $usage\n"; exit 1 } +unless (@ibxs) { print STDERR $help; exit 1 } foreach (@ibxs) { my $ibx = PublicInbox::InboxWritable->new($_); PublicInbox::Xapcmd::run($ibx, 'compact', $opt); diff --git a/script/public-inbox-convert b/script/public-inbox-convert index 4ff198d1..017411fb 100755 --- a/script/public-inbox-convert +++ b/script/public-inbox-convert @@ -4,9 +4,8 @@ use strict; use v5.10.1; use Getopt::Long qw(:config gnu_getopt no_ignore_case auto_abbrev); -my $usage = 'Usage: public-inbox-convert [options] OLD NEW'; my $help = <<EOF; # the following should fit w/o scrolling in 80x24 term: -usage: $usage +usage: public-inbox-convert [options] OLD NEW convert v1 format inboxes to v2 @@ -15,9 +14,8 @@ options: --no-index do not index after conversion --jobs=NUM set shards (NUM=0) --verbose | -v increase verbosity (may be repeated) - --help | -? show this help -index options (see public-inbox-index(1) manpage for full description): +index options (see public-inbox-index(1) man page for full description): --no-fsync speed up indexing, risk corruption on power outage -L LEVEL `basic', `medium', or `full' (default: full) @@ -35,19 +33,17 @@ my $opt = { quiet => -1, compact => 0, maxsize => undef, fsync => 1, reindex => 1, # we always reindex }; -GetOptions($opt, qw(jobs|j=i index! help|?), +GetOptions($opt, qw(jobs|j=i index! help|h), # index options qw(verbose|v+ rethread compact|c+ fsync|sync! indexlevel|index-level|L=s max_size|max-size=s batch_size|batch-size=s sequential_shard|sequential-shard|seq-shard - )) or die <<EOF; -bad command-line args\n$usage -EOF + )) or die $help; if ($opt->{help}) { print $help; exit 0 }; my $old_dir = shift(@ARGV) // ''; my $new_dir = shift(@ARGV) // ''; -die $usage if (scalar(@ARGV) || $new_dir eq '' || $old_dir eq ''); +die $help if (scalar(@ARGV) || $new_dir eq '' || $old_dir eq ''); die "$new_dir exists\n" if -d $new_dir; die "$old_dir not a directory\n" unless -d $old_dir; diff --git a/script/public-inbox-index b/script/public-inbox-index index 9855c67d..89c6b782 100755 --- a/script/public-inbox-index +++ b/script/public-inbox-index @@ -8,9 +8,8 @@ use strict; use v5.10.1; use Getopt::Long qw(:config gnu_getopt no_ignore_case auto_abbrev); -my $usage = 'public-inbox-index [options] INBOX_DIR'; my $help = <<EOF; # the following should fit w/o scrolling in 80x24 term: -usage: $usage +usage: public-inbox-index [options] INBOX_DIR Create and update search indices @@ -28,7 +27,6 @@ options: --rethread regenerate thread IDs (if upgrading, use sparingly) --prune prune git storage on discontiguous history --verbose | -v increase verbosity (may be repeated) - --help | -? show this help BYTES may use `k', `m', and `g' suffixes (e.g. `10m' for 10 megabytes) See public-inbox-index(1) man page for full documentation. @@ -39,8 +37,8 @@ GetOptions($opt, qw(verbose|v+ reindex rethread compact|c+ jobs|j=i prune indexlevel|index-level|L=s max_size|max-size=s batch_size|batch-size=s sequential_shard|seq-shard|sequential-shard - skip-docdata all help|?)) - or die "bad command-line args\n$usage"; + skip-docdata all help|h)) + or die $help; if ($opt->{help}) { print $help; exit 0 }; die "--jobs must be >= 0\n" if defined $opt->{jobs} && $opt->{jobs} < 0; if ($opt->{xapian_only} && !$opt->{reindex}) { @@ -54,7 +52,7 @@ PublicInbox::Admin::require_or_die('-index'); my $cfg = PublicInbox::Config->new; # Config is loaded by Admin my @ibxs = PublicInbox::Admin::resolve_inboxes(\@ARGV, $opt, $cfg); PublicInbox::Admin::require_or_die('-index'); -unless (@ibxs) { print STDERR "Usage: $usage\n"; exit 1 } +unless (@ibxs) { print STDERR $help; exit 1 } my $mods = {}; foreach my $ibx (@ibxs) { diff --git a/script/public-inbox-init b/script/public-inbox-init index 037e8e56..ae4a575c 100755 --- a/script/public-inbox-init +++ b/script/public-inbox-init @@ -5,9 +5,8 @@ use strict; use v5.10.1; use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; use Fcntl qw(:DEFAULT); -my $usage = 'public-inbox-init NAME INBOX_DIR HTTP_URL ADDRESS [ADDRESS..]'; my $help = <<EOF; # the following should fit w/o scrolling in 80x24 term: -usage: $usage +usage: public-inbox-init NAME INBOX_DIR HTTP_URL ADDRESS [ADDRESS..] Initialize a public-inbox @@ -44,10 +43,10 @@ my %opts = ( 'j|jobs=i' => \$jobs, 'ng|newsgroup=s' => \$ng, 'skip-docdata' => \$skip_docdata, - 'help|?' => \$show_help, + 'help|h' => \$show_help, ); my $usage_cb = sub { - print STDERR "Usage: $usage\n"; + print STDERR $help; exit 1; }; GetOptions(%opts) or $usage_cb->(); diff --git a/script/public-inbox-xcpdb b/script/public-inbox-xcpdb index 2bfadc09..84620175 100755 --- a/script/public-inbox-xcpdb +++ b/script/public-inbox-xcpdb @@ -4,9 +4,8 @@ use strict; use v5.10.1; use Getopt::Long qw(:config gnu_getopt no_ignore_case auto_abbrev); -my $usage = 'Usage: public-inbox-xcpdb [options] INBOX_DIR'; my $help = <<EOF; # the following should fit w/o scrolling in 80x24 term: -usage: $usage +usage: public-inbox-xcpdb [options] INBOX_DIR upgrade or reshard Xapian DB(s) used by public-inbox @@ -18,7 +17,6 @@ options: --jobs=NUM limit parallelism to JOBS count --verbose | -v increase verbosity (may be repeated) --sequential-shard copy+index Xapian shards sequentially (for slow HDD) - --help | -? show this help index options (see public-inbox-index(1) man page for full description): @@ -35,7 +33,7 @@ GetOptions($opt, qw( sequential_shard|seq-shard|sequential-shard jobs|j=i quiet|q verbose|v blocksize|b=s no-full|n fuller|F - all help|?)) or die "bad command-line args\n$usage"; + all help|h)) or die $help; if ($opt->{help}) { print $help; exit 0 }; use PublicInbox::Admin; @@ -44,7 +42,7 @@ PublicInbox::Admin::require_or_die('-search'); require PublicInbox::Config; my $cfg = PublicInbox::Config->new; my @ibxs = PublicInbox::Admin::resolve_inboxes(\@ARGV, $opt, $cfg) or - die $usage; + die $help; my $idx_env = PublicInbox::Admin::index_prepare($opt, $cfg); # we only set XAPIAN_FLUSH_THRESHOLD for index, since cpdb doesn't
For consistency with other commands, though the protocol-specific options should refer users to the manpage. --- lib/PublicInbox/Daemon.pm | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/PublicInbox/Daemon.pm b/lib/PublicInbox/Daemon.pm index 000ba169..e5798a4b 100644 --- a/lib/PublicInbox/Daemon.pm +++ b/lib/PublicInbox/Daemon.pm @@ -77,7 +77,20 @@ sub daemon_prepare ($) { my $listener_names = {}; # sockname => IO::Handle my $oldset = PublicInbox::Sigfd::block_signals(); @CMD = ($0, @ARGV); - my %opts = ( + my ($prog) = ($CMD[0] =~ m!([^/]+)\z!g); + my $help = <<EOF; +usage: $prog [-l ADDRESS] [--cert=FILE] [--key=FILE] + +options: + + -l ADDRESS address to listen on (default: $default_listen) + --cert=FILE default SSL/TLS certificate + --key=FILE default SSL/TLS certificate + -W WORKERS number of worker processes to spawn (default: 1) + +See public-inbox-daemon(8) and $prog(1) man pages for more. +EOF + my %opt = ( 'l|listen=s' => \@cfg_listen, '1|stdout=s' => \$stdout, '2|stderr=s' => \$stderr, @@ -88,8 +101,10 @@ sub daemon_prepare ($) { 'D|daemonize' => \$daemonize, 'cert=s' => \$default_cert, 'key=s' => \$default_key, + 'help|h' => \(my $show_help), ); - GetOptions(%opts) or die "bad command-line args\n"; + GetOptions(%opt) or die $help; + if ($show_help) { print $help; exit 0 }; if (defined $pid_file && $pid_file =~ /\.oldbin\z/) { die "--pid-file cannot end with '.oldbin'\n";
"use Getopt::Long" doesn't seem too slow on a hot page cache, and it's probably used frequently enough to be in cache. We'll also start reducing the amount of markup in the .pod and favoring verbatim text in documentation for readability in source form, since the bold text seems excessive. --- Documentation/public-inbox-learn.pod | 2 +- Documentation/public-inbox-mda.pod | 2 +- script/public-inbox-learn | 23 ++++++++++++++++++----- script/public-inbox-mda | 18 ++++++++++++++---- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Documentation/public-inbox-learn.pod b/Documentation/public-inbox-learn.pod index cd9bf278..94c96fd5 100644 --- a/Documentation/public-inbox-learn.pod +++ b/Documentation/public-inbox-learn.pod @@ -4,7 +4,7 @@ public-inbox-learn - spam trainer and remover for public-inbox =head1 SYNOPSIS -B<public-inbox-learn> <spam|ham|rm> E<lt>MESSAGE + public-inbox-learn <spam|ham|rm> </path/to/RFC2822_message =head1 DESCRIPTION diff --git a/Documentation/public-inbox-mda.pod b/Documentation/public-inbox-mda.pod index 99c9053d..a5e353e5 100644 --- a/Documentation/public-inbox-mda.pod +++ b/Documentation/public-inbox-mda.pod @@ -4,7 +4,7 @@ public-inbox-mda - mail delivery agent for public-inbox =head1 SYNOPSIS -B<public-inbox-mda> E<lt>MESSAGE + public-inbox-mda </path/to/RFC2822_message =head1 DESCRIPTION diff --git a/script/public-inbox-learn b/script/public-inbox-learn index 5cd08d49..fb2d86ec 100755 --- a/script/public-inbox-learn +++ b/script/public-inbox-learn @@ -4,9 +4,22 @@ # # Used for training spam (via SpamAssassin) and removing messages from a # public-inbox -my $usage = "$0 <spam|ham|rm> </path/to/message"; +my $help = <<EOF; +usage: public-inbox-learn [OPTIONS] [spam|ham|rm] </path/to/RFC2822_message + +required action argument: + + spam unindex the message and train as spam + rm remove the message without training as spam + ham index the message (based on To:/Cc: headers) and train as ham + +options: + + --all scan all inboxes on `rm' + +See public-inbox-learn(1) man page for full documentation. +EOF use strict; -use warnings; use PublicInbox::Config; use PublicInbox::InboxWritable; use PublicInbox::Eml; @@ -14,11 +27,11 @@ use PublicInbox::Address; use PublicInbox::Spamcheck::Spamc; use Getopt::Long qw(:config gnu_getopt no_ignore_case auto_abbrev); my %opt = (all => 0); -GetOptions(\%opt, 'all') or die "bad command-line args\n"; +GetOptions(\%opt, qw(all help|h)) or die $help; -my $train = shift or die "usage: $usage\n"; +my $train = shift or die $help; if ($train !~ /\A(?:ham|spam|rm)\z/) { - die "`$train' not recognized.\nusage: $usage\n"; + die "`$train' not recognized.\n$help"; } die "--all only works with `rm'\n" if $opt{all} && $train ne 'rm'; diff --git a/script/public-inbox-mda b/script/public-inbox-mda index 02ca3431..3ed5abb6 100755 --- a/script/public-inbox-mda +++ b/script/public-inbox-mda @@ -3,11 +3,21 @@ # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> # # Mail delivery agent for public-inbox, run from your MTA upon mail delivery +my $help = <<EOF; +usage: public-inbox-mda [OPTIONS] </path/to/RFC2822_message + +options: + + --no-precheck skip internal checks for spam messages + +See public-inbox-mda(1) man page for full documentation. +EOF use strict; -use warnings; -my $usage = 'public-inbox-mda [OPTIONS] < rfc2822_message'; -my $precheck = grep(/\A--no-precheck\z/, @ARGV) ? 0 : 1; -my ($ems, $emm); +use Getopt::Long qw(:config gnu_getopt no_ignore_case auto_abbrev); +my ($ems, $emm, $show_help); +my $precheck = 1; +GetOptions('precheck!' => \$precheck, 'help|h' => \$show_help) or + do { print STDERR $help; exit 1 }; my $do_exit = sub { my ($code) = shift;
Just some golfing to reduce scrolling and hopefully readability. --- lib/PublicInbox/Config.pm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm index f9184bd2..ae9ad8de 100644 --- a/lib/PublicInbox/Config.pm +++ b/lib/PublicInbox/Config.pm @@ -19,7 +19,7 @@ sub _array ($) { ref($_[0]) eq 'ARRAY' ? $_[0] : [ $_[0] ] } # if keys may be multi-value, the value is an array ref containing all values sub new { my ($class, $file) = @_; - $file = default_file() unless defined($file); + $file //= default_file(); my $self; if (ref($file) eq 'SCALAR') { # used by some tests open my $fh, '<', $file or die; # PerlIO::scalar @@ -136,9 +136,7 @@ sub limiter { sub config_dir { $ENV{PI_DIR} // "$ENV{HOME}/.public-inbox" } sub default_file { - my $f = $ENV{PI_CONFIG}; - return $f if defined $f; - config_dir() . '/config'; + $ENV{PI_CONFIG} // (config_dir() . '/config'); } sub config_fh_parse ($$$) {
And avoid unnecessary POD markup in the man page. --- Documentation/public-inbox-watch.pod | 2 +- script/public-inbox-watch | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Documentation/public-inbox-watch.pod b/Documentation/public-inbox-watch.pod index f3e622b0..73340ec4 100644 --- a/Documentation/public-inbox-watch.pod +++ b/Documentation/public-inbox-watch.pod @@ -4,7 +4,7 @@ public-inbox-watch - mailbox watcher for public-inbox =head1 SYNOPSIS -B<public-inbox-watch> + public-inbox-watch In ~/.public-inbox/config: diff --git a/script/public-inbox-watch b/script/public-inbox-watch index b6c6b202..1d164aa3 100755 --- a/script/public-inbox-watch +++ b/script/public-inbox-watch @@ -1,13 +1,24 @@ #!/usr/bin/perl -w # Copyright (C) 2016-2020 all contributors <meta@public-inbox.org> # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +my $help = <<EOF; +usage: public-inbox-watch + +See public-inbox-watch(1) man page for full documentation. +EOF + use strict; -use IO::Handle; +use Getopt::Long qw(:config gnu_getopt no_ignore_case auto_abbrev); +use IO::Handle; # ->autoflush use PublicInbox::Watch; use PublicInbox::Config; use PublicInbox::DS; use PublicInbox::Sigfd; use PublicInbox::Syscall qw($SFD_NONBLOCK); +my $do_scan = 1; +GetOptions('scan!' => \$do_scan, # undocumented, testing only + 'help|h' => \(my $show_help)) or do { print STDERR $help; exit 1 }; +if ($show_help) { print $help; exit 0 }; my $oldset = PublicInbox::Sigfd::block_signals(); STDOUT->autoflush(1); STDERR->autoflush(1); @@ -44,9 +55,8 @@ if ($watch) { $sig->{QUIT} = $sig->{TERM} = $sig->{INT} = $quit; # --no-scan is only intended for testing atm, undocumented. - unless (grep(/\A--no-scan\z/, @ARGV)) { - PublicInbox::DS::requeue($scan); - } + PublicInbox::DS::requeue($scan) if $do_scan; + my $sigfd = PublicInbox::Sigfd->new($sig, $SFD_NONBLOCK); local %SIG = (%SIG, %$sig) if !$sigfd; if (!$sigfd) {
B<> decreases readability of the POD source and is of dubious usefulness in the man page. --- Documentation/public-inbox-httpd.pod | 2 +- Documentation/public-inbox-imapd.pod | 2 +- Documentation/public-inbox-nntpd.pod | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/public-inbox-httpd.pod b/Documentation/public-inbox-httpd.pod index 2f4e9e5d..f4e9945a 100644 --- a/Documentation/public-inbox-httpd.pod +++ b/Documentation/public-inbox-httpd.pod @@ -4,7 +4,7 @@ public-inbox-httpd - PSGI server optimized for public-inbox =head1 SYNOPSIS -B<public-inbox-httpd> [OPTIONS] [/path/to/myapp.psgi] + public-inbox-httpd [OPTIONS] [/path/to/myapp.psgi] =head1 DESCRIPTION diff --git a/Documentation/public-inbox-imapd.pod b/Documentation/public-inbox-imapd.pod index 02027f4f..a5c996b8 100644 --- a/Documentation/public-inbox-imapd.pod +++ b/Documentation/public-inbox-imapd.pod @@ -4,7 +4,7 @@ public-inbox-imapd - IMAP server for sharing public-inboxes =head1 SYNOPSIS -B<public-inbox-imapd> [OPTIONS] + public-inbox-imapd [OPTIONS] =head1 DESCRIPTION diff --git a/Documentation/public-inbox-nntpd.pod b/Documentation/public-inbox-nntpd.pod index 122fabea..18f83c9c 100644 --- a/Documentation/public-inbox-nntpd.pod +++ b/Documentation/public-inbox-nntpd.pod @@ -4,7 +4,7 @@ public-inbox-nntpd - NNTP server for sharing public-inbox =head1 SYNOPSIS -B<public-inbox-nntpd> [OPTIONS] + public-inbox-nntpd [OPTIONS] =head1 DESCRIPTION
Following "git init" as an example, we'll create every parent path up to the one specified, instead of attempting to continue on when Cwd::abs_path returns `undef'. --- script/public-inbox-convert | 7 +++++-- script/public-inbox-init | 10 ++++++++-- t/convert-compact.t | 20 ++++++++++---------- t/init.t | 12 ++++++++++++ 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/script/public-inbox-convert b/script/public-inbox-convert index 017411fb..b61c743f 100755 --- a/script/public-inbox-convert +++ b/script/public-inbox-convert @@ -52,7 +52,9 @@ Cwd->import('abs_path'); require PublicInbox::Config; require PublicInbox::InboxWritable; -$old_dir = abs_path($old_dir); +my $abs = abs_path($old_dir); +die "failed to resolve $old_dir: $!\n" if (!defined($abs)); + my $cfg = PublicInbox::Config->new; my $old; $cfg->each_inbox(sub { @@ -72,6 +74,7 @@ if ($old) { } die "Only conversion from v1 inboxes is supported\n" if $old->version >= 2; +require File::Spec; require PublicInbox::Admin; my $detected = PublicInbox::Admin::detect_indexlevel($old); $old->{indexlevel} //= $detected; @@ -85,7 +88,7 @@ if ($opt->{'index'}) { } local %ENV = (%$env, %ENV) if $env; my $new = { %$old }; -$new->{inboxdir} = abs_path($new_dir); +$new->{inboxdir} = File::Spec->canonpath($new_dir); $new->{version} = 2; $new = PublicInbox::InboxWritable->new($new, { nproc => $opt->{jobs} }); $new->{-no_fsync} = 1 if !$opt->{fsync}; diff --git a/script/public-inbox-init b/script/public-inbox-init index ae4a575c..c775eb31 100755 --- a/script/public-inbox-init +++ b/script/public-inbox-init @@ -138,8 +138,9 @@ close($fh) or die "failed to close $pi_config_tmp: $!\n"; my $pfx = "publicinbox.$name"; my @x = (qw/git config/, "--file=$pi_config_tmp"); -require Cwd; -$inboxdir = Cwd::abs_path($inboxdir); +require File::Spec; +$inboxdir = File::Spec->canonpath($inboxdir); + die "`\\n' not allowed in `$inboxdir'\n" if $inboxdir =~ /\n/s; if (-f "$inboxdir/inbox.lock") { if (!defined $version) { @@ -185,6 +186,11 @@ if ($skip_docdata) { $ibx->{-skip_docdata} = $skip_docdata; } $ibx->init_inbox(0, $skip_epoch, $skip_artnum); +require Cwd; +my $tmp = Cwd::abs_path($inboxdir); +defined($tmp) or die "failed to resolve $inboxdir: $!\n"; +$inboxdir = $tmp; +die "`\\n' not allowed in `$inboxdir'\n" if $inboxdir =~ /\n/s; # needed for git prior to v2.1.0 umask(0077) if defined $perm; diff --git a/t/convert-compact.t b/t/convert-compact.t index 26a8fca0..575262e8 100644 --- a/t/convert-compact.t +++ b/t/convert-compact.t @@ -78,33 +78,33 @@ ok(defined($hwm) && $hwm > 0, "highwater mark set #$hwm"); $cmd = [ '-convert', '--no-index', $ibx->{inboxdir}, "$tmpdir/no-index" ]; ok(run_script($cmd, undef, $rdr), 'convert --no-index works'); -$cmd = [ '-convert', $ibx->{inboxdir}, "$tmpdir/v2" ]; +$cmd = [ '-convert', $ibx->{inboxdir}, "$tmpdir/x/v2" ]; ok(run_script($cmd, undef, $rdr), 'convert works'); -@xdir = glob("$tmpdir/v2/xap*/*"); +@xdir = glob("$tmpdir/x/v2/xap*/*"); foreach (@xdir) { my @st = stat($_); is($st[2] & 07777, -f _ ? 0644 : 0755, 'sharedRepository respected after convert'); } -$cmd = [ '-compact', "$tmpdir/v2" ]; +$cmd = [ '-compact', "$tmpdir/x/v2" ]; my $env = { NPROC => 2 }; ok(run_script($cmd, $env, $rdr), 'v2 compact works'); -$ibx->{inboxdir} = "$tmpdir/v2"; +$ibx->{inboxdir} = "$tmpdir/x/v2"; $ibx->{version} = 2; is($ibx->mm->num_highwater, $hwm, 'highwater mark unchanged in v2 inbox'); -@xdir = glob("$tmpdir/v2/xap*/*"); +@xdir = glob("$tmpdir/x/v2/xap*/*"); foreach (@xdir) { my @st = stat($_); is($st[2] & 07777, -f _ ? 0644 : 0755, 'sharedRepository respected after v2 compact'); } -is(((stat("$tmpdir/v2/msgmap.sqlite3"))[2]) & 07777, 0644, +is(((stat("$tmpdir/x/v2/msgmap.sqlite3"))[2]) & 07777, 0644, 'sharedRepository respected for v2 msgmap'); -@xdir = (glob("$tmpdir/v2/git/*.git/objects/*/*"), - glob("$tmpdir/v2/git/*.git/objects/pack/*")); +@xdir = (glob("$tmpdir/x/v2/git/*.git/objects/*/*"), + glob("$tmpdir/x/v2/git/*.git/objects/pack/*")); foreach (@xdir) { my @st = stat($_); is($st[2] & 07777, -f _ ? 0444 : 0755, @@ -116,12 +116,12 @@ is(scalar @$msgs, 1, 'only one message in history'); $ibx = undef; $err = ''; -$cmd = [ qw(-index -j0 --reindex -c), "$tmpdir/v2" ]; +$cmd = [ qw(-index -j0 --reindex -c), "$tmpdir/x/v2" ]; ok(run_script($cmd, undef, $rdr), '--reindex -c'); like($err, qr/xapian-compact/, 'xapian-compact ran (-c)'); $rdr->{2} = \(my $err2 = ''); -$cmd = [ qw(-index -j0 --reindex -cc), "$tmpdir/v2" ]; +$cmd = [ qw(-index -j0 --reindex -cc), "$tmpdir/x/v2" ]; ok(run_script($cmd, undef, $rdr), '--reindex -c -c'); like($err2, qr/xapian-compact/, 'xapian-compact ran (-c -c)'); ok(($err2 =~ tr/\n/\n/) > ($err =~ tr/\n/\n/), '-compacted twice'); diff --git a/t/init.t b/t/init.t index a5a9debc..dba59231 100644 --- a/t/init.t +++ b/t/init.t @@ -59,6 +59,18 @@ sub quiet_fail { like($err, qr/`\\n' not allowed in `/s, 'reported \\n'); is_deeply([glob("$tmpdir/.public-inbox/pi-init-*")], [], 'no junk files left behind'); + + # "git init" does this, too + $cmd = [ '-init', 'deep-non-existent', "$tmpdir/a/b/c/d", + qw(http://example.com/abcd abcd@example.com) ]; + $err = ''; + ok(run_script($cmd, $env, $rdr), 'initializes non-existent hierarchy'); + ok(-d "$tmpdir/a/b/c/d", 'directory created'); + open my $fh, '>', "$tmpdir/d" or BAIL_OUT "open: $!"; + close $fh; + $cmd = [ '-init', 'd-f-conflict', "$tmpdir/d/f/conflict", + qw(http://example.com/conflict onflict@example.com) ]; + ok(!run_script($cmd, $env, $rdr), 'fails on D/F conflict'); } SKIP: {