summaryrefslogtreecommitdiffstats
path: root/src/lib/Gitolite/Conf/Explode.pm
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Gitolite/Conf/Explode.pm')
-rw-r--r--src/lib/Gitolite/Conf/Explode.pm118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/lib/Gitolite/Conf/Explode.pm b/src/lib/Gitolite/Conf/Explode.pm
new file mode 100644
index 0000000..cf89620
--- /dev/null
+++ b/src/lib/Gitolite/Conf/Explode.pm
@@ -0,0 +1,118 @@
+package Gitolite::Conf::Explode;
+
+# include/subconf processor
+# ----------------------------------------------------------------------
+
+@EXPORT = qw(
+ explode
+);
+
+use Exporter 'import';
+
+use Gitolite::Rc;
+use Gitolite::Common;
+
+use strict;
+use warnings;
+
+# ----------------------------------------------------------------------
+
+# 'seen' for include/subconf files
+my %included = ();
+# 'seen' for group names on LHS
+my %prefixed_groupname = ();
+
+sub explode {
+ trace( 3, @_ );
+ my ( $file, $subconf, $out ) = @_;
+
+ # seed the 'seen' list if it's empty
+ $included{ device_inode("gitolite.conf") }++ unless %included;
+
+ my $fh = _open( "<", $file );
+ while (<$fh>) {
+ my $line = cleanup_conf_line($_);
+ next unless $line =~ /\S/;
+
+ # subst %HOSTNAME word if rc defines a hostname, else leave as is
+ $line =~ s/%HOSTNAME\b/$rc{HOSTNAME}/g if $rc{HOSTNAME};
+
+ $line = prefix_groupnames( $line, $subconf ) if $subconf ne 'master';
+
+ if ( $line =~ /^(include|subconf) (?:(\S+) )?(\S.+)$/ ) {
+ incsub( $1, $2, $3, $subconf, $out );
+ } else {
+ # normal line, send it to the callback function
+ push @{$out}, "# $file $.";
+ push @{$out}, $line;
+ }
+ }
+}
+
+sub incsub {
+ my $is_subconf = ( +shift eq 'subconf' );
+ my ( $new_subconf, $include_glob, $current_subconf, $out ) = @_;
+
+ _die "subconf '$current_subconf' attempting to run 'subconf'\n" if $is_subconf and $current_subconf ne 'master';
+
+ _die "invalid include/subconf file/glob '$include_glob'"
+ unless $include_glob =~ /^"(.+)"$/
+ or $include_glob =~ /^'(.+)'$/;
+ $include_glob = $1;
+
+ trace( 3, $is_subconf, $include_glob );
+
+ for my $file ( glob($include_glob) ) {
+ _warn("included file not found: '$file'"), next unless -f $file;
+ _die "invalid include/subconf filename '$file'" unless $file =~ m(([^/]+).conf$);
+ my $basename = $1;
+
+ next if already_included($file);
+
+ if ($is_subconf) {
+ push @{$out}, "subconf " . ( $new_subconf || $basename );
+ explode( $file, ( $new_subconf || $basename ), $out );
+ push @{$out}, "subconf $current_subconf";
+ } else {
+ explode( $file, $current_subconf, $out );
+ }
+ }
+}
+
+sub prefix_groupnames {
+ my ( $line, $subconf ) = @_;
+
+ my $lhs = '';
+ # save 'foo' if it's an '@foo = list' line
+ $lhs = $1 if $line =~ /^@(\S+) = /;
+ # prefix all @groups in the line
+ $line =~ s/(^| )(@\S+)(?= |$)/ $1 . ($prefixed_groupname{$subconf}{$2} || $2) /ge;
+ # now prefix the LHS and store it if needed
+ if ($lhs) {
+ $line =~ s/^@\S+ = /"\@$subconf.$lhs = "/e;
+ $prefixed_groupname{$subconf}{"\@$lhs"} = "\@$subconf.$lhs";
+ trace( 3, "prefixed_groupname.$subconf.\@$lhs = \@$subconf.$lhs" );
+ }
+
+ return $line;
+}
+
+sub already_included {
+ my $file = shift;
+
+ my $file_id = device_inode($file);
+ return 0 unless $included{$file_id}++;
+
+ _warn("$file already included");
+ trace( 3, "$file already included" );
+ return 1;
+}
+
+sub device_inode {
+ my $file = shift;
+ trace( 3, $file, ( stat $file )[ 0, 1 ] );
+ return join( "/", ( stat $file )[ 0, 1 ] );
+}
+
+1;
+