]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/Config.pm
declare Inbox object for reusability
[public-inbox.git] / lib / PublicInbox / Config.pm
1 # Copyright (C) 2014-2015 all contributors <meta@public-inbox.org>
2 # License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
3 #
4 # Used throughout the project for reading configuration
5 package PublicInbox::Config;
6 use strict;
7 use warnings;
8 use base qw/Exporter/;
9 our @EXPORT_OK = qw/try_cat/;
10 require PublicInbox::Inbox;
11 use File::Path::Expand qw/expand_filename/;
12
13 # returns key-value pairs of config directives in a hash
14 # if keys may be multi-value, the value is an array ref containing all values
15 sub new {
16         my ($class, $file) = @_;
17         $file = default_file() unless defined($file);
18         my $self = bless git_config_dump($file), $class;
19         $self->{-by_addr} = {};
20         $self->{-by_name} = {};
21         $self;
22 }
23
24 sub lookup {
25         my ($self, $recipient) = @_;
26         my $addr = lc($recipient);
27         my $inbox = $self->{-by_addr}->{$addr};
28         return $inbox if $inbox;
29
30         my $pfx;
31
32         foreach my $k (keys %$self) {
33                 $k =~ /\A(publicinbox\.[\w-]+)\.address\z/ or next;
34                 my $v = $self->{$k};
35                 if (ref($v) eq "ARRAY") {
36                         foreach my $alias (@$v) {
37                                 (lc($alias) eq $addr) or next;
38                                 $pfx = $1;
39                                 last;
40                         }
41                 } else {
42                         (lc($v) eq $addr) or next;
43                         $pfx = $1;
44                         last;
45                 }
46         }
47         defined $pfx or return;
48         _fill($self, $pfx);
49 }
50
51 sub lookup_name {
52         my ($self, $name) = @_;
53         my $rv = $self->{-by_name}->{$name};
54         return $rv if $rv;
55         $self->{-by_name}->{$name} = _fill($self, "publicinbox.$name");
56 }
57
58 sub get {
59         my ($self, $inbox, $key) = @_;
60
61         $self->{"publicinbox.$inbox.$key"};
62 }
63
64 sub config_dir { $ENV{PI_DIR} || expand_filename('~/.public-inbox') }
65
66 sub default_file {
67         my $f = $ENV{PI_CONFIG};
68         return $f if defined $f;
69         config_dir() . '/config';
70 }
71
72 sub git_config_dump {
73         my ($file) = @_;
74         my ($in, $out);
75         my @cmd = (qw/git config/, "--file=$file", '-l');
76         my $cmd = join(' ', @cmd);
77         my $pid = open(my $fh, '-|', @cmd);
78         defined $pid or die "$cmd failed: $!";
79         my %rv;
80         foreach my $line (<$fh>) {
81                 chomp $line;
82                 my ($k, $v) = split(/=/, $line, 2);
83                 my $cur = $rv{$k};
84
85                 if (defined $cur) {
86                         if (ref($cur) eq "ARRAY") {
87                                 push @$cur, $v;
88                         } else {
89                                 $rv{$k} = [ $cur, $v ];
90                         }
91                 } else {
92                         $rv{$k} = $v;
93                 }
94         }
95         close $fh or die "failed to close ($cmd) pipe: $!";
96         $? and warn "$$ $cmd exited with: ($pid) $?";
97         \%rv;
98 }
99
100 sub try_cat {
101         my ($path) = @_;
102         my $rv;
103         if (open(my $fh, '<', $path)) {
104                 local $/;
105                 $rv = <$fh>;
106         }
107         $rv;
108 }
109
110 sub _fill {
111         my ($self, $pfx) = @_;
112         my $rv = {};
113
114         foreach my $k (qw(mainrepo address filter url)) {
115                 my $v = $self->{"$pfx.$k"};
116                 $rv->{$k} = $v if defined $v;
117         }
118         my $inbox = $pfx;
119         $inbox =~ s/\Apublicinbox\.//;
120         $rv->{name} = $inbox;
121         my $v = $rv->{address} ||= 'public-inbox@example.com';
122         $rv->{-primary_address} = ref($v) eq 'ARRAY' ? $v->[0] : $v;
123         $rv = PublicInbox::Inbox->new($rv);
124         if (ref($v) eq 'ARRAY') {
125                 $self->{-by_addr}->{lc($_)} = $rv foreach @$v;
126         } else {
127                 $self->{-by_addr}->{lc($v)} = $rv;
128         }
129         $rv;
130 }
131
132
133 1;