]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/Config.pm
qspawn: wire up RLIMIT_* handling to limiters
[public-inbox.git] / lib / PublicInbox / Config.pm
index cead7fc287c1220b7af6905f2d04132d2c2a0a1f..6f62712f0eb1ea43b645e52a4a7fabe3c0cc1e9c 100644 (file)
@@ -30,9 +30,10 @@ sub new {
        $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'}) {
-               $no = [ $no ] if ref($no) ne 'ARRAY';
+               $no = _array($no);
                my @domains;
                foreach my $n (@$no) {
                        my @n = split(/\s+/, $n);
@@ -90,13 +91,22 @@ sub lookup_name ($$) {
 
 sub each_inbox {
        my ($self, $cb) = @_;
-       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);
+       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);
+               }
        }
 }
 
@@ -123,7 +133,9 @@ sub limiter {
        $self->{-limiters}->{$name} ||= do {
                require PublicInbox::Qspawn;
                my $max = $self->{"publicinboxlimiter.$name.max"};
-               PublicInbox::Qspawn::Limiter->new($max);
+               my $limiter = PublicInbox::Qspawn::Limiter->new($max);
+               $limiter->setup_rlimit($name, $self);
+               $limiter;
        };
 }
 
@@ -137,7 +149,8 @@ sub default_file {
 
 sub git_config_dump {
        my ($file) = @_;
-       my ($in, $out);
+       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";
@@ -146,8 +159,14 @@ sub git_config_dump {
        while (defined(my $line = <$fh>)) {
                chomp $line;
                my ($k, $v) = split(/=/, $line, 2);
-               my $cur = $rv{$k};
 
+               my ($section) = ($k =~ /\A(\S+)\.[^\.]+\z/);
+               unless (defined $section_seen{$section}) {
+                       $section_seen{$section} = 1;
+                       push @section_order, $section;
+               }
+
+               my $cur = $rv{$k};
                if (defined $cur) {
                        if (ref($cur) eq "ARRAY") {
                                push @$cur, $v;
@@ -159,6 +178,7 @@ sub git_config_dump {
                }
        }
        close $fh or die "failed to close ($cmd) pipe: $?";
+       $rv{-section_order} = \@section_order;
 
        \%rv;
 }
@@ -180,15 +200,59 @@ sub valid_inbox_name ($) {
        1;
 }
 
+sub cgit_repo_merge ($$) {
+       my ($self, $repo) = @_;
+       # $repo = { url => 'foo.git', path => '/path/to/foo.git' }
+       my $nick = $repo->{url};
+       $self->{"coderepo.$nick.dir"} ||= $repo->{path};
+       $self->{"coderepo.$nick.cgiturl"} ||= $nick;
+}
+
+sub parse_cgitrc {
+       my ($self, $cgitrc, $nesting) = @_;
+
+       # same limit as cgit/configfile.c::parse_configfile
+       return if $nesting > 8;
+
+       open my $fh, '<', $cgitrc or do {
+               warn "failed to open cgitrc=$cgitrc: $!\n";
+               return;
+       };
+
+       # FIXME: this doesn't support macro expansion via $VARS, yet
+       my $repo;
+       foreach (<$fh>) {
+               chomp;
+               if (m!\Arepo\.url=(.+?)/*\z!) {
+                       my $nick = $1;
+                       cgit_repo_merge($self, $repo) if $repo;
+                       $repo = { url => $nick };
+               } elsif (m!\Arepo\.path=(.+)\z!) {
+                       if (defined $repo) {
+                               $repo->{path} = $1;
+                       } else {
+                               warn "$_ without repo.url\n";
+                       }
+               } elsif (m!\Ainclude=(.+)\z!) {
+                       parse_cgitrc($self, $1, $nesting + 1);
+               }
+       }
+       cgit_repo_merge($self, $repo) if $repo;
+}
+
 # parse a code repo
 # Only git is supported at the moment, but SVN and Hg are possibilities
 sub _fill_code_repo {
        my ($self, $nick) = @_;
        my $pfx = "coderepo.$nick";
 
+       # TODO: support gitweb and other repository viewers?
+       if (defined(my $cgitrc = delete $self->{-cgitrc_unparsed})) {
+               parse_cgitrc($self, $cgitrc, 0);
+       }
        my $dir = $self->{"$pfx.dir"}; # aka "GIT_DIR"
        unless (defined $dir) {
-               warn "$pfx.repodir unset";
+               warn "$pfx.dir unset";
                return;
        }
 
@@ -209,8 +273,6 @@ sub _fill_code_repo {
                        } @$cgits;
                }
        }
-       # TODO: support gitweb and other repository viewers?
-       # TODO: parse cgitrc
 
        $git;
 }
@@ -275,7 +337,11 @@ sub _fill {
                my $code_repos = $self->{-code_repos};
                my $repo_objs = $rv->{-repo_objs} = [];
                foreach my $nick (@$ibx_code_repos) {
-                       valid_inbox_name($nick) or next;
+                       my @parts = split(m!/!, $nick);
+                       my $valid = 0;
+                       $valid += valid_inbox_name($_) foreach (@parts);
+                       $valid == scalar(@parts) or next;
+
                        my $repo = $code_repos->{$nick} ||=
                                                _fill_code_repo($self, $nick);
                        push @$repo_objs, $repo if $repo;