X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FConfig.pm;h=cc8c1eafb804e12f8c2c34d53740b24479ed4f11;hb=42f390c5e4d8e6619d234a43aa5397c9977cf070;hp=09f9179b085a4dd90aed20e0d8b277ede66cc870;hpb=fe86054ee1e2d93b19762a34ed1aaebe43635ff0;p=public-inbox.git
diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm
index 09f9179b..cc8c1eaf 100644
--- a/lib/PublicInbox/Config.pm
+++ b/lib/PublicInbox/Config.pm
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2018 all contributors
+# Copyright (C) 2014-2019 all contributors
# License: AGPL-3.0+
#
# Used throughout the project for reading configuration
@@ -10,7 +10,7 @@
package PublicInbox::Config;
use strict;
use warnings;
-require PublicInbox::Inbox;
+use PublicInbox::Inbox;
use PublicInbox::Spawn qw(popen_rd);
sub _array ($) { ref($_[0]) eq 'ARRAY' ? $_[0] : [ $_[0] ] }
@@ -20,16 +20,22 @@ sub _array ($) { ref($_[0]) eq 'ARRAY' ? $_[0] : [ $_[0] ] }
sub new {
my ($class, $file) = @_;
$file = default_file() unless defined($file);
- $file = ref $file ? $file : git_config_dump($file);
- my $self = bless $file, $class;
-
+ my $self;
+ if (ref($file) eq 'SCALAR') { # used by some tests
+ open my $fh, '<', $file or die; # PerlIO::scalar
+ $self = config_fh_parse($fh, "\n", '=');
+ } else {
+ $self = git_config_dump($file);
+ }
+ bless $self, $class;
# caches
- $self->{-by_addr} ||= {};
- $self->{-by_name} ||= {};
- $self->{-by_newsgroup} ||= {};
- $self->{-no_obfuscate} ||= {};
- $self->{-limiters} ||= {};
- $self->{-code_repos} ||= {}; # nick => PublicInbox::Git object
+ $self->{-by_addr} = {};
+ $self->{-by_list_id} = {};
+ $self->{-by_name} = {};
+ $self->{-by_newsgroup} = {};
+ $self->{-no_obfuscate} = {};
+ $self->{-limiters} = {};
+ $self->{-code_repos} = {}; # nick => PublicInbox::Git object
$self->{-cgitrc_unparsed} = $self->{'publicinbox.cgitrc'};
if (my $no = delete $self->{'publicinbox.noobfuscate'}) {
@@ -57,80 +63,50 @@ sub new {
$self;
}
+sub noop {}
+sub fill_all ($) { each_inbox($_[0], \&noop) }
+
+sub _lookup_fill ($$$) {
+ my ($self, $cache, $key) = @_;
+ $self->{$cache}->{$key} // do {
+ fill_all($self);
+ $self->{$cache}->{$key};
+ }
+}
+
sub lookup {
my ($self, $recipient) = @_;
- my $addr = lc($recipient);
- my $ibx = $self->{-by_addr}->{$addr};
- return $ibx if $ibx;
-
- my $pfx;
-
- foreach my $k (keys %$self) {
- $k =~ m!\A(publicinbox\.[^/]+)\.address\z! or next;
- my $v = $self->{$k};
- if (ref($v) eq "ARRAY") {
- foreach my $alias (@$v) {
- (lc($alias) eq $addr) or next;
- $pfx = $1;
- last;
- }
- } else {
- (lc($v) eq $addr) or next;
- $pfx = $1;
- last;
- }
- }
- defined $pfx or return;
- _fill($self, $pfx);
+ _lookup_fill($self, '-by_addr', lc($recipient));
+}
+
+sub lookup_list_id {
+ my ($self, $list_id) = @_;
+ _lookup_fill($self, '-by_list_id', lc($list_id));
}
sub lookup_name ($$) {
my ($self, $name) = @_;
- $self->{-by_name}->{$name} || _fill($self, "publicinbox.$name");
+ $self->{-by_name}->{$name} // _fill($self, "publicinbox.$name");
}
sub each_inbox {
- my ($self, $cb) = @_;
- if (my $section_order = $self->{-section_order}) {
- foreach my $section (@$section_order) {
- next if $section !~ m!\Apublicinbox\.([^/]+)\z!;
- $self->{"publicinbox.$1.mainrepo"} or next;
- my $ibx = lookup_name($self, $1) or next;
- $cb->($ibx);
- }
- } else {
- my %seen;
- foreach my $k (keys %$self) {
- $k =~ m!\Apublicinbox\.([^/]+)\.mainrepo\z! or next;
- next if $seen{$1};
- $seen{$1} = 1;
- my $ibx = lookup_name($self, $1) or next;
- $cb->($ibx);
- }
+ my ($self, $cb, $arg) = @_;
+ # may auto-vivify if config file is non-existent:
+ foreach my $section (@{$self->{-section_order}}) {
+ next if $section !~ m!\Apublicinbox\.([^/]+)\z!;
+ my $ibx = lookup_name($self, $1) or next;
+ $cb->($ibx, $arg);
}
}
sub lookup_newsgroup {
my ($self, $ng) = @_;
- $ng = lc($ng);
- my $ibx = $self->{-by_newsgroup}->{$ng};
- return $ibx if $ibx;
-
- foreach my $k (keys %$self) {
- $k =~ m!\A(publicinbox\.[^/]+)\.newsgroup\z! or next;
- my $v = $self->{$k};
- my $pfx = $1;
- if ($v eq $ng) {
- $ibx = _fill($self, $pfx);
- return $ibx;
- }
- }
- undef;
+ _lookup_fill($self, '-by_newsgroup', lc($ng));
}
sub limiter {
my ($self, $name) = @_;
- $self->{-limiters}->{$name} ||= do {
+ $self->{-limiters}->{$name} //= do {
require PublicInbox::Qspawn;
my $max = $self->{"publicinboxlimiter.$name.max"} || 1;
my $limiter = PublicInbox::Qspawn::Limiter->new($max);
@@ -139,7 +115,7 @@ sub limiter {
};
}
-sub config_dir { $ENV{PI_DIR} || "$ENV{HOME}/.public-inbox" }
+sub config_dir { $ENV{PI_DIR} // "$ENV{HOME}/.public-inbox" }
sub default_file {
my $f = $ENV{PI_CONFIG};
@@ -147,19 +123,14 @@ sub default_file {
config_dir() . '/config';
}
-sub git_config_dump {
- my ($file) = @_;
- my (%section_seen, @section_order);
- return {} unless -e $file;
- my @cmd = (qw/git config/, "--file=$file", '-l');
- my $cmd = join(' ', @cmd);
- my $fh = popen_rd(\@cmd) or die "popen_rd failed for $file: $!\n";
+sub config_fh_parse ($$$) {
+ my ($fh, $rs, $fs) = @_;
my %rv;
- local $/ = "\n";
+ my (%section_seen, @section_order);
+ local $/ = $rs;
while (defined(my $line = <$fh>)) {
chomp $line;
- my ($k, $v) = split(/=/, $line, 2);
-
+ my ($k, $v) = split($fs, $line, 2);
my ($section) = ($k =~ /\A(\S+)\.[^\.]+\z/);
unless (defined $section_seen{$section}) {
$section_seen{$section} = 1;
@@ -177,12 +148,22 @@ sub git_config_dump {
$rv{$k} = $v;
}
}
- close $fh or die "failed to close ($cmd) pipe: $?";
$rv{-section_order} = \@section_order;
\%rv;
}
+sub git_config_dump {
+ my ($file) = @_;
+ return {} unless -e $file;
+ my @cmd = (qw/git config -z -l/, "--file=$file");
+ my $cmd = join(' ', @cmd);
+ my $fh = popen_rd(\@cmd) or die "popen_rd failed for $file: $!\n";
+ my $rv = config_fh_parse($fh, "\0", "\n");
+ close $fh or die "failed to close ($cmd) pipe: $?";
+ $rv;
+}
+
sub valid_inbox_name ($) {
my ($name) = @_;
@@ -225,8 +206,8 @@ sub cgit_repo_merge ($$$) {
$self->{-cgit_remove_suffix} and
$rel =~ s!/?\.git\z!!;
}
- $self->{"coderepo.$rel.dir"} ||= $path;
- $self->{"coderepo.$rel.cgiturl"} ||= $rel;
+ $self->{"coderepo.$rel.dir"} //= $path;
+ $self->{"coderepo.$rel.cgiturl"} //= $rel;
}
sub is_git_dir ($) {
@@ -307,7 +288,7 @@ sub parse_cgitrc {
}
} elsif (m!\Ainclude=(.+)\z!) {
parse_cgitrc($self, $1, $nesting + 1);
- } elsif (m!\A(scan-hidden-path|remove-suffix)=(\d+)\z!) {
+ } elsif (m!\A(scan-hidden-path|remove-suffix)=([0-9]+)\z!) {
my ($k, $v) = ($1, $2);
$k =~ tr/-/_/;
$self->{"-cgit_$k"} = $v;
@@ -357,7 +338,7 @@ sub _fill_code_repo {
# cgit supports "/blob/?id=%s", but it's only a plain-text
# display and requires an unabbreviated id=
foreach my $t (qw(blob commit tag)) {
- $git->{$t.'_url_format'} ||= map {
+ $git->{$t.'_url_format'} //= map {
"$_/$t/?id=%s"
} @$cgits;
}
@@ -366,36 +347,50 @@ sub _fill_code_repo {
$git;
}
+sub _git_config_bool ($) {
+ my ($val) = @_;
+ if ($val =~ /\A(?:false|no|off|[\-\+]?(?:0x)?0+)\z/i) {
+ 0;
+ } elsif ($val =~ /\A(?:true|yes|on|[\-\+]?(?:0x)?[0-9]+)\z/i) {
+ 1;
+ } else {
+ undef;
+ }
+}
+
sub _fill {
my ($self, $pfx) = @_;
my $ibx = {};
- foreach my $k (qw(mainrepo filter url newsgroup
- infourl watch watchheader httpbackendmax
+ foreach my $k (qw(inboxdir filter newsgroup
+ watch watchheader httpbackendmax
replyto feedmax nntpserver indexlevel)) {
my $v = $self->{"$pfx.$k"};
$ibx->{$k} = $v if defined $v;
}
+
+ # backwards compatibility:
+ $ibx->{inboxdir} //= $self->{"$pfx.mainrepo"};
+
foreach my $k (qw(obfuscate)) {
my $v = $self->{"$pfx.$k"};
defined $v or next;
- if ($v =~ /\A(?:false|no|off|0)\z/) {
- $ibx->{$k} = 0;
- } elsif ($v =~ /\A(?:true|yes|on|1)\z/) {
- $ibx->{$k} = 1;
+ if (defined(my $bval = _git_config_bool($v))) {
+ $ibx->{$k} = $bval;
} else {
warn "Ignoring $pfx.$k=$v in config, not boolean\n";
}
}
# TODO: more arrays, we should support multi-value for
# more things to encourage decentralization
- foreach my $k (qw(address altid nntpmirror coderepo hide)) {
+ foreach my $k (qw(address altid nntpmirror coderepo hide listid url
+ infourl)) {
if (defined(my $v = $self->{"$pfx.$k"})) {
$ibx->{$k} = _array($v);
}
}
- return unless $ibx->{mainrepo};
+ return unless defined($ibx->{inboxdir});
my $name = $pfx;
$name =~ s/\Apublicinbox\.//;
@@ -412,6 +407,11 @@ sub _fill {
$self->{-by_addr}->{$lc_addr} = $ibx;
$self->{-no_obfuscate}->{$lc_addr} = 1;
}
+ if (my $listids = $ibx->{listid}) {
+ foreach my $list_id (@$listids) {
+ $self->{-by_list_id}->{$list_id} = $ibx;
+ }
+ }
if (my $ng = $ibx->{newsgroup}) {
$self->{-by_newsgroup}->{$ng} = $ibx;
}
@@ -419,7 +419,7 @@ sub _fill {
if ($ibx->{obfuscate}) {
$ibx->{-no_obfuscate} = $self->{-no_obfuscate};
$ibx->{-no_obfuscate_re} = $self->{-no_obfuscate_re};
- each_inbox($self, sub {}); # noop to populate -no_obfuscate
+ fill_all($self); # noop to populate -no_obfuscate
}
if (my $ibx_code_repos = $ibx->{coderepo}) {
@@ -431,7 +431,7 @@ sub _fill {
$valid += valid_inbox_name($_) foreach (@parts);
$valid == scalar(@parts) or next;
- my $repo = $code_repos->{$nick} ||=
+ my $repo = $code_repos->{$nick} //=
_fill_code_repo($self, $nick);
push @$repo_objs, $repo if $repo;
}