diff --git a/doc/gitolite.conf.mkd b/doc/gitolite.conf.mkd index ce2efba..e7ac5c7 100644 --- a/doc/gitolite.conf.mkd +++ b/doc/gitolite.conf.mkd @@ -71,6 +71,15 @@ will include the contents of the file "foo.conf" from the same directory as the main config file. You can also use an absolute path if you like, although in the interests of cloning the admin-repo sanely you should avoid doing this! +You can also use a glob, as in: + + include "*.conf" + +which will include all the ".conf" files from the directory in which the main +config file exists. + +Files that have been already processed once are skipped, with a warning. + [Advanced users: the include statement cannot be used inside a delegated config file, for security reasons]. diff --git a/src/gl-compile-conf b/src/gl-compile-conf index f0bfdf1..9799841 100755 --- a/src/gl-compile-conf +++ b/src/gl-compile-conf @@ -93,10 +93,19 @@ sub expand_list return @new_list; } +sub device_inode { + my $file = shift; + return join("/", (stat $file)[0,1]); +} + # ---------------------------------------------------------------------------- # "compile" GL conf # ---------------------------------------------------------------------------- +# detect recursion in include files; see processing of "include" statement later +our %included; +$included{device_inode("conf/gitolite.conf")}++; + sub check_fragment_repo_disallowed { # trying to set access for $repo (='foo')... @@ -250,12 +259,16 @@ sub parse_conf_line # include elsif ($line =~ /^include "(.+)"/) { - my $file = $1; - $file = "$GL_ADMINDIR/conf/$file" unless $file =~ /^\//; - die "$ABRT $fragment attempting to include configuration\n" if $fragment ne 'master'; - die "$ABRT included file not found: '$file'\n" unless -f $file; + my $include_glob = $1; + for my $file (glob($include_glob =~ m(^/) ? $include_glob : "conf/$include_glob")) { + die "$ABRT $fragment attempting to include configuration\n" if $fragment ne 'master'; + die "$ABRT included file not found: '$file'\n" unless -f $file; - parse_conf_file( $file, $fragment ); + my $file_id = device_inode($file); + warn("$WARN $file already included\n"), next if ($included{$file_id}++); + + parse_conf_file( $file, $fragment ); + } } # very simple syntax for the gitweb description of repo; one of: # reponame = "some description string" diff --git a/t/t68-include b/t/t68-include new file mode 100644 index 0000000..f1be71d --- /dev/null +++ b/t/t68-include @@ -0,0 +1,62 @@ +cd $TESTDIR +$TESTDIR/rollback || die "rollback failed" +# ---------- + +name "setup" +echo " + repo foo + RW = u1 u2 +" | ugc +notexpect ABORT +expect "remote: creating foo..." +expect "remote: Initialized empty Git repository in $TEST_BASE_FULL/foo.git/" +expect "remote: u3(u3.pub),u4(u4.pub),u5(u5.pub),u6(u6.pub)" + +name "add i1.conf, i2.conf, and i3" +cd ~/gitolite-admin +echo " + repo bar + RW = u3 u4 +" > conf/i1.conf +echo " + repo baz + RW = u5 +" > conf/i2.conf +echo " + repo frob + RW = u6 +" > conf/i3 +ugc < /dev/null +notexpect "remote: creating bar..." +notexpect "remote: Initialized empty Git repository in $TEST_BASE_FULL/bar.git/" +notexpect "remote: creating baz..." +notexpect "remote: Initialized empty Git repository in $TEST_BASE_FULL/baz.git/" + +name "add include statement" +echo " + include \"*.conf\" +" | ugc + +expect "remote: conf/gitolite.conf already included" +notexpect "remote: conf/i1.conf already included" +notexpect "remote: conf/i2.conf already included" +expect "remote: creating bar..." +expect "remote: Initialized empty Git repository in $TEST_BASE_FULL/bar.git/" +expect "remote: creating baz..." +expect "remote: Initialized empty Git repository in $TEST_BASE_FULL/baz.git/" +expect "remote: u6(u6.pub)" +notexpect frob +notexpect "u3(u3.pub)" +notexpect "u4(u4.pub)" +notexpect "u5(u5.pub)" + +name "append again to conf" +echo " + include \"i*.conf\" +" | ugc + +expect "remote: conf/gitolite.conf already included" +expect "remote: conf/i1.conf already included" +expect "remote: conf/i2.conf already included" + +name INTERNAL