package Gitolite::Conf;

# explode/parse a conf file
# ----------------------------------------------------------------------

@EXPORT = qw(
  compile
  explode
  parse
);

use Exporter 'import';

use Gitolite::Rc;
use Gitolite::Common;
use Gitolite::Conf::Sugar;
use Gitolite::Conf::Store;

use strict;
use warnings;

# ----------------------------------------------------------------------

sub compile {
    _die "'gitolite compile' does not take any arguments" if @_;

    _chdir( $rc{GL_ADMIN_BASE} );
    _chdir("conf");

    parse( sugar('gitolite.conf') );

    # the order matters; new repos should be created first, to give store a
    # place to put the individual gl-conf files
    new_repos();

    # cache control
    if ($rc{CACHE}) {
        require Gitolite::Cache;
        Gitolite::Cache->import(qw(cache_control));

        cache_control('stop');
    }

    store();

    if ($rc{CACHE}) {
        cache_control('start');
    }

    # remove entries from POST_CREATE which also exist in POST_COMPILE.  This
    # not only saves us having to implement an optimisation in *those*
    # scripts, but more importantly, moves the optimisation one step up -- we
    # don't even *call* those scripts now.
    my %pco = map { $_ => 1 } @{ $rc{POST_COMPILE} };
    @{ $rc{POST_CREATE} } = grep { ! exists $pco{$_} } @{ $rc{POST_CREATE} };

    for my $repo ( @{ $rc{NEW_REPOS_CREATED} } ) {
        trigger( 'POST_CREATE', $repo );
    }

    # process rule template data
    _system("gitolite compile-template-data");
}

sub parse {
    my $lines = shift;
    trace( 3, scalar(@$lines) . " lines incoming" );

    my ( $fname, $lnum );
    for my $line (@$lines) {
        ( $fname, $lnum ) = ( $1, $2 ), next if $line =~ /^# (\S+) (\d+)$/;
        # user or repo groups
        if ( $line =~ /^(@\S+) = (.*)/ ) {
            add_to_group( $1, split( ' ', $2 ) );
        } elsif ( $line =~ /^repo (.*)/ ) {
            set_repolist( split( ' ', $1 ) );
        } elsif ( $line =~ /^(-|C|R|RW\+?(?:C?D?|D?C?)M?) (.* )?= (.+)/ ) {
            my $perm  = $1;
            my @refs  = parse_refs( $2 || '' );
            my @users = parse_users($3);

            for my $ref (@refs) {
                for my $user (@users) {
                    add_rule( $perm, $ref, $user, $fname, $lnum );
                }
            }
        } elsif ( $line =~ /^config (.+) = ?(.*)/ ) {
            my ( $key, $value ) = ( $1, $2 );
            $value =~ s/^['"](.*)["']$/$1/;
            my @validkeys = split( ' ', ( $rc{GIT_CONFIG_KEYS} || '' ) );
            push @validkeys, "gitolite-options\\..*";
            my @matched = grep { $key =~ /^$_$/i } @validkeys;
            _die "git config '$key' not allowed\ncheck GIT_CONFIG_KEYS in the rc file" if ( @matched < 1 );
            _die "bad config value '$value'" if $value =~ $UNSAFE_PATT;
            while ( my ( $mk, $mv ) = each %{ $rc{SAFE_CONFIG} } ) {
                $value =~ s/%$mk/$mv/g;
            }
            add_config( 1, $key, $value );
        } elsif ( $line =~ /^subconf (\S+)$/ ) {
            trace( 3, $line );
            set_subconf($1);
        } else {
            _warn "syntax error, ignoring: '$line'";
        }
    }
    parse_done();
}

1;
