From 3c0f17748157740eefd8f41c15af269c100edc2b Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 9 Jun 2012 07:48:56 +0530 Subject: [PATCH] Allow user-specified programs to override system-installed ones (manually tested) - new rc var: GL_BINDIR2; see doc update in this commit - added _which() function to search both $GL_BINDIR and $GL_BINDIR2 - 'gitolite ', non-perl triggers, VREFs, and sugar, use this - unshifted $GL_BINDIR2/lib into @INC upfront in Rc.pm - perl triggers use this --- doc/rc.mkd | 22 ++++++++++++++++++++++ src/gitolite | 15 ++++----------- src/lib/Gitolite/Conf/Sugar.pm | 2 +- src/lib/Gitolite/Hooks/Update.pm | 4 ++-- src/lib/Gitolite/Rc.pm | 26 +++++++++++++++++++++++--- 5 files changed, 52 insertions(+), 17 deletions(-) diff --git a/doc/rc.mkd b/doc/rc.mkd index 2c84d88..17f2616 100644 --- a/doc/rc.mkd +++ b/doc/rc.mkd @@ -97,3 +97,25 @@ information. require the '@' to be escaped: DEFAULT_ROLE_PERMS => "READERS \@all\nWRITERS \@senior_devs", + + * `GL_BINDIR2`, string + + This is useful when you install gitolite system-wide, but want to add or + override commands, VREFs, triggers, etc., by putting them somewhere in the + hosting user's home directory (i.e., without requiring root privileges). + + Add a new variable `GL_BINDIR2` to the the rc file. Example: + + GL_BINDIR2 => "$ENV{HOME}/gitolite/src2", + + In that directory, create as much of the following directory structure as + you need to add your programs: + + . + |-- commands + |-- lib + | `-- Gitolite + | `-- Triggers + |-- syntactic-sugar + |-- triggers + `-- VREF diff --git a/src/gitolite b/src/gitolite index aeca6af..2498737 100755 --- a/src/gitolite +++ b/src/gitolite @@ -73,9 +73,10 @@ if ( $command eq 'setup' ) { } elsif ( $command eq 'trigger' ) { trigger(@args); -} elsif ( -x "$rc{GL_BINDIR}/commands/$command" ) { - trace( 2, "attempting gitolite command $command" ); - run_command( $command, @args ); +} elsif ( my $c = _which("commands/$command", 'x' ) ) { + trace( 2, "attempting gitolite command $c" ); + _system( $c, @args ); + exit 0; } elsif ( $command eq 'list-phy-repos' ) { _chdir( $rc{GL_REPO_BASE} ); @@ -99,11 +100,3 @@ sub args { } # ---------------------------------------------------------------------- - -sub run_command { - my $pgm = shift; - my $fullpath = "$ENV{GL_BINDIR}/commands/$pgm"; - _die "'$pgm' not found or not executable" if not -x $fullpath; - _system( $fullpath, @_ ); - exit 0; -} diff --git a/src/lib/Gitolite/Conf/Sugar.pm b/src/lib/Gitolite/Conf/Sugar.pm index dca1c44..d02bfa0 100644 --- a/src/lib/Gitolite/Conf/Sugar.pm +++ b/src/lib/Gitolite/Conf/Sugar.pm @@ -52,7 +52,7 @@ sub sugar { # perl-ism; apart from keeping the full path separate from the # simple name, this also protects %rc from change by implicit # aliasing, which would happen if you touched $s itself - my $sfp = "$ENV{GL_BINDIR}/syntactic-sugar/$s"; + my $sfp = _which("syntactic-sugar/$s", 'r'); _warn("skipped sugar script '$s'"), next if not -r $sfp; $lines = SugarBox::run_sugar_script( $sfp, $lines ); diff --git a/src/lib/Gitolite/Hooks/Update.pm b/src/lib/Gitolite/Hooks/Update.pm index 568cfc4..5bef2ed 100644 --- a/src/lib/Gitolite/Hooks/Update.pm +++ b/src/lib/Gitolite/Hooks/Update.pm @@ -61,8 +61,8 @@ sub check_vrefs { } } else { my ( $dummy, $pgm, @args ) = split '/', $vref; - $pgm = "$ENV{GL_BINDIR}/VREF/$pgm"; - -x $pgm or _die "'$vref': helper program missing or unexecutable"; + $pgm = _which("VREF/$pgm", 'x'); + $pgm or _die "'$vref': helper program missing or unexecutable"; open( my $fh, "-|", $pgm, @_, $vref, @args ) or _die "'$vref': can't spawn helper program: $!"; while (<$fh>) { diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 8dbe1e7..81479fe 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -9,6 +9,7 @@ package Gitolite::Rc; query_rc version trigger + _which $REMOTE_COMMAND_PATT $REF_OR_FILENAME_PATT @@ -83,9 +84,11 @@ unshift @{ $rc{ACCESS_1} }, 'Writable::access_1'; # 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 some env vars, setup gitolite internal "env" vars (aka rc vars) +# setup some perl/rc/env vars # ---------------------------------------------------------------------- +unshift @INC, "$rc{GL_BINDIR2}/lib" if $rc{GL_BINDIR2}; + $ENV{PATH} = "$ENV{GL_BINDIR}:$ENV{PATH}"; { @@ -215,9 +218,9 @@ sub trigger { Gitolite::Triggers::run( $module, $sub, @args, $rc_section, @_ ); } else { - $pgm = "$ENV{GL_BINDIR}/triggers/$pgm"; + $pgm = _which("triggers/$pgm", 'x'); - _warn("skipped command '$s'"), next if not -x $pgm; + _warn("skipped command '$s'"), next if not $pgm; trace( 2, "command: $s" ); _system( $pgm, @args, $rc_section, @_ ); # they better all return with 0 exit codes! } @@ -228,6 +231,23 @@ sub trigger { trace( 2, "'$rc_section' not found in rc" ); } +sub _which { + # looks for a file in GL_BINDIR2 or GL_BINDIR. Returns whichever exists + # (GL_BINDIR2 preferred if defined) or 0 if not found. + my $file = shift; + my $mode = shift; # could be 'x' or 'r' + + my @files = ("$rc{GL_BINDIR}/$file"); + unshift @files, ("$rc{GL_BINDIR2}/$file") if $rc{GL_BINDIR2}; + + for my $f ( @files ) { + return $f if -x $f; + return $f if -r $f and $mode eq 'r'; + } + + return 0; +} + # ---------------------------------------------------------------------- =for args