diff --git a/Gitolite/Commands/QueryRc.pm b/Gitolite/Commands/QueryRc.pm index a36e4bd..4d241b4 100644 --- a/Gitolite/Commands/QueryRc.pm +++ b/Gitolite/Commands/QueryRc.pm @@ -40,7 +40,7 @@ my $all = 0; # ---------------------------------------------------------------------- sub query_rc { - trace( 1, "rc file not found; default should be " . glrc_default_filename() ) if not glrc_filename(); + trace( 1, "rc file not found; default should be " . glrc('default-filename') ) if not glrc('filename'); my @vars = args(); diff --git a/Gitolite/Commands/Setup.pm b/Gitolite/Commands/Setup.pm index aa312ad..939de8e 100644 --- a/Gitolite/Commands/Setup.pm +++ b/Gitolite/Commands/Setup.pm @@ -56,7 +56,7 @@ sub setup { sub first_run { # if the rc file could not be found, it's *definitely* a first run! - return not glrc_filename(); + return not glrc('filename'); } sub args { @@ -91,7 +91,7 @@ sub args { sub setup_glrc { trace(1); - _print( glrc_default_filename(), glrc_default_text() ); + _print( glrc('default-filename'), glrc('default-text') ); } sub setup_gladmin { @@ -99,7 +99,7 @@ sub setup_gladmin { trace( 1, $admin ); # reminder: 'admin files' are in ~/.gitolite, 'admin repo' is - # $GL_REPO_BASE/gitolite-admin.git + # $rc{GL_REPO_BASE}/gitolite-admin.git # grab the pubkey content before we chdir() away @@ -111,8 +111,8 @@ sub setup_gladmin { # set up the admin files in admin-base - _mkdir($GL_ADMIN_BASE); - _chdir($GL_ADMIN_BASE); + _mkdir( $rc{GL_ADMIN_BASE} ); + _chdir( $rc{GL_ADMIN_BASE} ); _mkdir("conf"); my $conf; @@ -132,15 +132,15 @@ sub setup_gladmin { # set up the admin repo in repo-base _chdir(); - _mkdir($GL_REPO_BASE); - _chdir($GL_REPO_BASE); + _mkdir( $rc{GL_REPO_BASE} ); + _chdir( $rc{GL_REPO_BASE} ); new_repo("gitolite-admin"); # commit the admin files to the admin repo - $ENV{GIT_WORK_TREE} = $GL_ADMIN_BASE; - _chdir("$GL_REPO_BASE/gitolite-admin.git"); + $ENV{GIT_WORK_TREE} = $rc{GL_ADMIN_BASE}; + _chdir("$rc{GL_REPO_BASE}/gitolite-admin.git"); system("git add conf/gitolite.conf"); system("git add keydir") if $pubkey; tsh_try("git config --get user.email") or tsh_run( "git config user.email $ENV{USER}\@" . `hostname` ); diff --git a/Gitolite/Conf.pm b/Gitolite/Conf.pm index 8f7e111..cffee63 100644 --- a/Gitolite/Conf.pm +++ b/Gitolite/Conf.pm @@ -34,7 +34,7 @@ sub compile { trace(3); # XXX assume we're in admin-base/conf - _chdir($GL_ADMIN_BASE); + _chdir( $rc{GL_ADMIN_BASE} ); _chdir("conf"); explode( 'gitolite.conf', 'master', \&parse ); @@ -99,7 +99,7 @@ sub parse { } } elsif ( $line =~ /^config (.+) = ?(.*)/ ) { my ( $key, $value ) = ( $1, $2 ); - my @validkeys = split( ' ', ( $GL_GITCONFIG_KEYS || '' ) ); + my @validkeys = split( ' ', ( $rc{GL_GITCONFIG_KEYS} || '' ) ); push @validkeys, "gitolite-options\\..*"; my @matched = grep { $key =~ /^$_$/ } @validkeys; # XXX move this also to add_config: _die "git config $key not allowed\ncheck GL_GITCONFIG_KEYS in the rc file for how to allow it" if (@matched < 1); @@ -123,8 +123,8 @@ sub incsub { # XXX move this to Macros... substitute HOSTNAME word if GL_HOSTNAME defined, otherwise leave as is # $include_glob =~ s/\bHOSTNAME\b/$GL_HOSTNAME/ if $GL_HOSTNAME; - # XXX g2 diff: include glob is *implicitly* from $GL_ADMIN_BASE/conf, not *explicitly* - # for my $file (glob($include_glob =~ m(^/) ? $include_glob : "$GL_ADMIN_BASE/conf/$include_glob")) { + # XXX g2 diff: include glob is *implicitly* from $rc{GL_ADMIN_BASE}/conf, not *explicitly* + # for my $file (glob($include_glob =~ m(^/) ? $include_glob : "$rc{GL_ADMIN_BASE}/conf/$include_glob")) { trace( 3, $is_subconf, $include_glob ); diff --git a/Gitolite/Conf/Load.pm b/Gitolite/Conf/Load.pm index 9367296..3237748 100644 --- a/Gitolite/Conf/Load.pm +++ b/Gitolite/Conf/Load.pm @@ -92,7 +92,7 @@ sub access { sub load_common { - _chdir("$GL_ADMIN_BASE"); + _chdir( $rc{GL_ADMIN_BASE} ); # we take an unusual approach to caching this function! # (requires that first call to load_common is before first call to load_1) @@ -118,7 +118,7 @@ sub load_1 { my $repo = shift; trace( 4, $repo ); - _chdir("$GL_REPO_BASE"); + _chdir( $rc{GL_REPO_BASE} ); if ( $repo eq $last_repo ) { $repos{$repo} = $one_repo{$repo}; @@ -172,7 +172,7 @@ sub memberships { } sub data_version_mismatch { - return $data_version ne $current_data_version; + return $data_version ne glrc('current-data-version'); } # ---------------------------------------------------------------------- @@ -192,10 +192,10 @@ Usage: gitolite list-groups load_common(); my @g = (); - while (my ($k, $v) = each ( %groups )) { - push @g, @{ $v }; + while ( my ( $k, $v ) = each(%groups) ) { + push @g, @{$v}; } - return (sort_u(\@g)); + return ( sort_u( \@g ) ); } sub list_users { @@ -213,19 +213,18 @@ Usage: gitolite list-users load_common(); - my @u = map { keys %{ $_ } } values %repos; - $total = scalar(keys %split_conf); + my @u = map { keys %{$_} } values %repos; + $total = scalar( keys %split_conf ); warn "WARNING: you have $total repos to check; this could take some time!\n" if $total > 100; for my $one ( keys %split_conf ) { load_1($one); - $count++; print STDERR "$count / $total\r" if not ( $count % 100 ) and timer(5); - push @u, map { keys %{ $_ } } values %one_repo; + $count++; print STDERR "$count / $total\r" if not( $count % 100 ) and timer(5); + push @u, map { keys %{$_} } values %one_repo; } print STDERR "\n"; - return (sort_u(\@u)); + return ( sort_u( \@u ) ); } - sub list_repos { die " @@ -241,7 +240,7 @@ Usage: gitolite list-repos my @r = keys %repos; push @r, keys %split_conf; - return (sort_u(\@r)); + return ( sort_u( \@r ) ); } sub list_memberships { @@ -258,7 +257,7 @@ Usage: gitolite list-memberships load_common(); my @m = memberships($name); - return (sort_u(\@m)); + return ( sort_u( \@m ) ); } sub list_members { @@ -276,13 +275,13 @@ Usage: gitolite list-members load_common(); my @m = (); - while (my ($k, $v) = each ( %groups )) { - for my $g ( @{ $v } ) { + while ( my ( $k, $v ) = each(%groups) ) { + for my $g ( @{$v} ) { push @m, $k if $g eq $name; } } - return (sort_u(\@m)); + return ( sort_u( \@m ) ); } # ---------------------------------------------------------------------- diff --git a/Gitolite/Conf/Store.pm b/Gitolite/Conf/Store.pm index 518a750..b99ac0b 100644 --- a/Gitolite/Conf/Store.pm +++ b/Gitolite/Conf/Store.pm @@ -145,14 +145,14 @@ sub set_subconf { sub new_repos { trace(3); - _chdir($GL_REPO_BASE); + _chdir( $rc{GL_REPO_BASE} ); # normal repos my @repos = grep { $_ =~ $REPONAME_PATT and not /^@/ } sort keys %repos; # add in members of repo groups map { push @repos, keys %{ $groups{$_} } } grep { /^@/ } keys %repos; - for my $repo ( @{ sort_u(\@repos) } ) { + for my $repo ( @{ sort_u( \@repos ) } ) { next unless $repo =~ $REPONAME_PATT; # skip repo patterns next if $repo =~ m(^\@|EXTCMD/); # skip groups and fake repos @@ -170,7 +170,7 @@ sub new_repo { _mkdir("$repo.git"); _chdir("$repo.git"); system("git init --bare >&2"); - _chdir($GL_REPO_BASE); + _chdir( $rc{GL_REPO_BASE} ); hook_1($repo); # XXX ignoring creator for now @@ -180,7 +180,7 @@ sub new_repo { sub hook_repos { trace(3); # all repos, all hooks - _chdir($GL_REPO_BASE); + _chdir( $rc{GL_REPO_BASE} ); # XXX g2 diff: we now don't care if it's a symlink -- it's upto the admin # on the server to make sure things are kosher @@ -195,14 +195,14 @@ sub store { trace(3); # first write out the ones for the physical repos - _chdir($GL_REPO_BASE); + _chdir( $rc{GL_REPO_BASE} ); my $phy_repos = list_phy_repos(1); - for my $repo (@{ $phy_repos }) { + for my $repo ( @{$phy_repos} ) { store_1($repo); } - _chdir($GL_ADMIN_BASE); + _chdir( $rc{GL_ADMIN_BASE} ); store_common(); } @@ -261,7 +261,7 @@ sub store_common { my $cc = "conf/gitolite.conf-compiled.pm"; my $compiled_fh = _open( ">", "$cc.new" ); - my $data_version = $current_data_version; + my $data_version = glrc('current-data-version'); trace( 1, "data_version = $data_version" ); print $compiled_fh Data::Dumper->Dump( [$data_version], [qw(*data_version)] ); @@ -296,20 +296,20 @@ sub store_common { # reset the gitolite supplied hooks, in case someone fiddled with # them, but only once per run if ( not $hook_reset ) { - _mkdir("$GL_ADMIN_BASE/hooks/common"); - _mkdir("$GL_ADMIN_BASE/hooks/gitolite-admin"); - _print( "$GL_ADMIN_BASE/hooks/common/update", update_hook() ); - _print( "$GL_ADMIN_BASE/hooks/gitolite-admin/post-update", post_update_hook() ); - chmod 0755, "$GL_ADMIN_BASE/hooks/common/update"; - chmod 0755, "$GL_ADMIN_BASE/hooks/gitolite-admin/post-update"; + _mkdir("$rc{GL_ADMIN_BASE}/hooks/common"); + _mkdir("$rc{GL_ADMIN_BASE}/hooks/gitolite-admin"); + _print( "$rc{GL_ADMIN_BASE}/hooks/common/update", update_hook() ); + _print( "$rc{GL_ADMIN_BASE}/hooks/gitolite-admin/post-update", post_update_hook() ); + chmod 0755, "$rc{GL_ADMIN_BASE}/hooks/common/update"; + chmod 0755, "$rc{GL_ADMIN_BASE}/hooks/gitolite-admin/post-update"; $hook_reset++; } # propagate user hooks - ln_sf( "$GL_ADMIN_BASE/hooks/common", "*", "$repo.git/hooks" ); + ln_sf( "$rc{GL_ADMIN_BASE}/hooks/common", "*", "$repo.git/hooks" ); # propagate admin hook - ln_sf( "$GL_ADMIN_BASE/hooks/gitolite-admin", "*", "$repo.git/hooks" ) if $repo eq 'gitolite-admin'; + ln_sf( "$rc{GL_ADMIN_BASE}/hooks/gitolite-admin", "*", "$repo.git/hooks" ) if $repo eq 'gitolite-admin'; # g2 diff: no "site-wide" hooks (the stuff in between gitolite hooks # and user hooks) anymore. I don't think anyone used them anyway... diff --git a/Gitolite/Hooks/PostUpdate.pm b/Gitolite/Hooks/PostUpdate.pm index 813733f..1ce07b2 100644 --- a/Gitolite/Hooks/PostUpdate.pm +++ b/Gitolite/Hooks/PostUpdate.pm @@ -27,7 +27,7 @@ sub post_update { _die "no files/dirs called 'hooks' or 'logs' are allowed" if tsh_text() =~ /^(hooks|logs)$/; { - local $ENV{GIT_WORK_TREE} = $GL_ADMIN_BASE; + local $ENV{GIT_WORK_TREE} = $rc{GL_ADMIN_BASE}; tsh_try("git checkout -f --quiet master"); } system("$ENV{GL_BINDIR}/gitolite compile"); diff --git a/Gitolite/Rc.pm b/Gitolite/Rc.pm index 94f6613..6fe0ff9 100644 --- a/Gitolite/Rc.pm +++ b/Gitolite/Rc.pm @@ -4,24 +4,14 @@ package Gitolite::Rc; # ---------------------------------------------------------------------- @EXPORT = qw( - $GL_ADMIN_BASE - $GL_REPO_BASE - - $GL_UMASK - - $GL_GITCONFIG_KEYS - - glrc_default_text - glrc_default_filename - glrc_filename + %rc + glrc $ADC_CMD_ARGS_PATT $REF_OR_FILENAME_PATT $REPONAME_PATT $REPOPATT_PATT $USERNAME_PATT - - $current_data_version ); use Exporter 'import'; @@ -32,14 +22,12 @@ use Gitolite::Common; # variables that are/could be/should be in the rc file # ---------------------------------------------------------------------- -$GL_ADMIN_BASE = "$ENV{HOME}/.gitolite"; -$GL_REPO_BASE = "$ENV{HOME}/repositories"; +$rc{GL_ADMIN_BASE} = "$ENV{HOME}/.gitolite"; +$rc{GL_REPO_BASE} = "$ENV{HOME}/repositories"; # variables that should probably never be changed # ---------------------------------------------------------------------- -$current_data_version = "3.0"; - $ADC_CMD_ARGS_PATT = qr(^[0-9a-zA-Z._\@/+:-]*$); $REF_OR_FILENAME_PATT = qr(^[0-9a-zA-Z][0-9a-zA-Z._\@/+ :,-]*$); $REPONAME_PATT = qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@/+-]*$); @@ -48,44 +36,56 @@ $USERNAME_PATT = qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$); # ---------------------------------------------------------------------- +my $current_data_version = "3.0"; + +my $rc = glrc('filename'); +do $rc if -r $rc; +# let values specified in rc file override our internal ones +@rc{ keys %RC } = values %RC; + +# ---------------------------------------------------------------------- + use strict; use warnings; # ---------------------------------------------------------------------- -my $rc = glrc_filename(); -do $rc if -r $rc; - +my $glrc_default_text = ''; { - my $glrc_default_text = ''; + local $/ = undef; + $glrc_default_text = ; +} - sub glrc_default_text { +sub glrc { + my $cmd = shift; + if ( $cmd eq 'default-filename' ) { + trace( 1, "..should happen only on first run" ); + return "$ENV{HOME}/.gitolite.rc"; + } elsif ( $cmd eq 'default-text' ) { trace( 1, "..should happen only on first run" ); return $glrc_default_text if $glrc_default_text; - local $/ = undef; - $glrc_default_text = ; + _die "rc file default text not set; this should not happen!"; + } elsif ( $cmd eq 'filename' ) { + # where is the rc file? + trace(4); + + # search $HOME first + return "$ENV{HOME}/.gitolite.rc" if -f "$ENV{HOME}/.gitolite.rc"; + trace( 2, "$ENV{HOME}/.gitolite.rc not found" ); + + # XXX for fedora, we can add the following line, but I would really prefer + # if ~/.gitolite.rc on each $HOME was just a symlink to /etc/gitolite.rc + # XXX return "/etc/gitolite.rc" if -f "/etc/gitolite.rc"; + + return ''; + } elsif ( $cmd eq 'current-data-version' ) { + return $current_data_version; + } else { + _die "unknown argument to glrc: $cmd"; } } -sub glrc_default_filename { - trace( 1, "..should happen only on first run" ); - return "$ENV{HOME}/.gitolite.rc"; -} - -# where is the rc file? -sub glrc_filename { - trace(4); - - # search $HOME first - return "$ENV{HOME}/.gitolite.rc" if -f "$ENV{HOME}/.gitolite.rc"; - trace( 2, "$ENV{HOME}/.gitolite.rc not found" ); - - # XXX for fedora, we can add the following line, but I would really prefer - # if ~/.gitolite.rc on each $HOME was just a symlink to /etc/gitolite.rc - # XXX return "/etc/gitolite.rc" if -f "/etc/gitolite.rc"; - - return ''; -} +# ---------------------------------------------------------------------- 1; @@ -99,8 +99,10 @@ __DATA__ # this file is in perl syntax. However, you do NOT need to know perl to edit # it; it should be fairly self-explanatory and easy to maintain -$GL_UMASK = 0077; -$GL_GITCONFIG_KEYS = ""; +%RC = ( + GL_UMASK => 0077, + GL_GITCONFIG_KEYS => "", +); # ------------------------------------------------------------------------------ # per perl rules, this should be the last line in such a file: diff --git a/gitolite b/gitolite index 8cd39d2..d8d1c3e 100755 --- a/gitolite +++ b/gitolite @@ -79,7 +79,7 @@ sub args { print "$_\n" for ( @{ list_repos() } ); } elsif ( $command eq 'list-phy-repos' ) { shift @ARGV; - _chdir($GL_REPO_BASE); + _chdir( $rc{GL_REPO_BASE} ); print "$_\n" for ( @{ list_phy_repos() } ); } elsif ( $command eq 'list-memberships' ) { shift @ARGV; diff --git a/gitolite-shell b/gitolite-shell index 479773c..59b2984 100755 --- a/gitolite-shell +++ b/gitolite-shell @@ -38,7 +38,7 @@ my $ret = access( $repo, $user, $aa, 'unknown' ); trace( 1, "access($repo, $user, $aa, 'unknown') -> $ret" ); _die $ret if $ret =~ /DENIED/; -$repo = "'$GL_REPO_BASE/$repo.git'"; +$repo = "'$rc{GL_REPO_BASE}/$repo.git'"; exec( "git", "shell", "-c", "$verb $repo" ); # ---------------------------------------------------------------------- diff --git a/src/Gitolite/Rc.pm b/src/Gitolite/Rc.pm new file mode 100644 index 0000000..e84ee0c --- /dev/null +++ b/src/Gitolite/Rc.pm @@ -0,0 +1,214 @@ +package Gitolite::Rc; + +# everything to do with 'rc'. Also defines some 'constants' +# ---------------------------------------------------------------------- + +@EXPORT = qw( + %rc + glrc + query_rc + version + + $REMOTE_COMMAND_PATT + $REF_OR_FILENAME_PATT + $REPONAME_PATT + $REPOPATT_PATT + $USERNAME_PATT +); + +use Exporter 'import'; +use Getopt::Long; + +use Gitolite::Common; + +# ---------------------------------------------------------------------- + +our %rc; + +# ---------------------------------------------------------------------- + +# variables that are/could be/should be in the rc file +# ---------------------------------------------------------------------- + +$rc{GL_BINDIR} = $ENV{GL_BINDIR}; +$rc{GL_ADMIN_BASE} = "$ENV{HOME}/.gitolite"; +$rc{GL_REPO_BASE} = "$ENV{HOME}/repositories"; + +# variables that should probably never be changed +# ---------------------------------------------------------------------- + +$REMOTE_COMMAND_PATT = qr(^[- 0-9a-zA-Z\@\%_=+:,./]*$); +$REF_OR_FILENAME_PATT = qr(^[0-9a-zA-Z][0-9a-zA-Z._\@/+ :,-]*$); +$REPONAME_PATT = qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@/+-]*$); +$REPOPATT_PATT = qr(^\@?[0-9a-zA-Z[][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/,-]*$); +$USERNAME_PATT = qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$); + +# ---------------------------------------------------------------------- + +my $current_data_version = "3.0"; + +my $rc = glrc('filename'); +do $rc if -r $rc; +_die "$rc seems to be for older gitolite" if defined($GL_ADMINDIR); +# let values specified in rc file override our internal ones +@rc{ keys %RC } = values %RC; + +# testing sometimes requires all of it to be overridden silently; use an +# env var that is highly unlikely to appear in real life :) +do $ENV{G3T_RC} if exists $ENV{G3T_RC} and -r $ENV{G3T_RC}; + +# fix PATH (TODO: do it only if 'gitolite' isn't in PATH) +$ENV{PATH} = "$ENV{GL_BINDIR}:$ENV{PATH}"; + +# ---------------------------------------------------------------------- + +use strict; +use warnings; + +# ---------------------------------------------------------------------- + +my $glrc_default_text = ''; +{ + local $/ = undef; + $glrc_default_text = ; +} + +sub glrc { + my $cmd = shift; + if ( $cmd eq 'default-filename' ) { + return "$ENV{HOME}/.gitolite.rc"; + } elsif ( $cmd eq 'default-text' ) { + return $glrc_default_text if $glrc_default_text; + _die "rc file default text not set; this should not happen!"; + } elsif ( $cmd eq 'filename' ) { + # where is the rc file? + + # search $HOME first + return "$ENV{HOME}/.gitolite.rc" if -f "$ENV{HOME}/.gitolite.rc"; + + # XXX for fedora, we can add the following line, but I would really prefer + # if ~/.gitolite.rc on each $HOME was just a symlink to /etc/gitolite.rc + # XXX return "/etc/gitolite.rc" if -f "/etc/gitolite.rc"; + + return ''; + } elsif ( $cmd eq 'current-data-version' ) { + return $current_data_version; + } else { + _die "unknown argument to glrc: $cmd"; + } +} + +# ---------------------------------------------------------------------- +# implements 'gitolite query-rc' and 'version' +# ---------------------------------------------------------------------- + +# ---------------------------------------------------------------------- + +my $all = 0; +my $nonl = 0; + +sub query_rc { + + my @vars = args(); + + no strict 'refs'; + + if ($all) { + for my $e ( sort keys %rc ) { + print "$e=" . ( defined( $rc{$e} ) ? $rc{$e} : 'undef' ) . "\n"; + } + return; + } + + print join( "\t", map { $rc{$_} || '' } @vars ) . ( $nonl ? '' : "\n" ) if @vars; +} + +sub version { + my $version = ''; + $version = '(unknown)'; + for ("$rc{GL_ADMIN_BASE}/VERSION") { + $version = slurp($_) if -r $_; + } + chomp($version); + return $version; +} + +# ---------------------------------------------------------------------- + +=for args +Usage: gitolite query-rc -a + gitolite query-rc [-n] + + -a print all variables and values + -n do not append a newline + +Example: + + gitolite query-rc GL_ADMIN_BASE UMASK + # prints "/home/git/.gitolite0077" or similar + + gitolite query-rc -a + # prints all known variables and values, one per line +=cut + +sub args { + my $help = 0; + + GetOptions( + 'all|a' => \$all, + 'nonl|n' => \$nonl, + 'help|h' => \$help, + ) or usage(); + + usage("'-a' cannot be combined with other arguments") if $all and @ARGV; + usage() if not $all and not @ARGV or $help; + return @ARGV; +} + +1; + +# ---------------------------------------------------------------------- + +__DATA__ +# configuration variables for gitolite + +# This file is in perl syntax. But you do NOT need to know perl to edit it -- +# just mind the commas and make sure the brackets and braces stay matched up! + +# (Tip: perl allows a comma after the last item in a list also!) + +%RC = ( + UMASK => 0077, + GL_GITCONFIG_KEYS => "", + + # comment out or uncomment as needed + # these will run in sequence during the conf file parse + SYNTACTIC_SUGAR => + [ + # 'continuation-lines', + ], + + # comment out or uncomment as needed + # these will run in sequence after post-update + POST_COMPILE => + [ + 'post-compile/ssh-authkeys', + ], + + # comment out or uncomment as needed + # these are available to remote users + COMMANDS => + { + 'help' => 1, + 'info' => 1, + }, +); + +# ------------------------------------------------------------------------------ +# per perl rules, this should be the last line in such a file: +1; + +# Local variables: +# mode: perl +# End: +# vim: set syn=perl: