diff options
Diffstat (limited to 'src/lib/Gitolite/Easy.pm')
-rw-r--r-- | src/lib/Gitolite/Easy.pm | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/src/lib/Gitolite/Easy.pm b/src/lib/Gitolite/Easy.pm new file mode 100644 index 0000000..8f530f2 --- /dev/null +++ b/src/lib/Gitolite/Easy.pm @@ -0,0 +1,240 @@ +package Gitolite::Easy; + +# easy access to gitolite from external perl programs +# ---------------------------------------------------------------------- +# most/all functions in this module test $ENV{GL_USER}'s rights and +# permissions so it needs to be set. + +# "use"-ing this module +# ---------------------------------------------------------------------- +# Using this module from within a gitolite trigger or command is easy; you +# just need 'use lib $ENV{GL_LIBDIR};' before the 'use Gitolite::Easy;'. +# +# Using it from something completely outside gitolite requires a bit more +# work. First, run 'gitolite query-rc -a' to find the correct values for +# GL_BINDIR and GL_LIBDIR in your installation. Then use this code in your +# external program, using the paths you just found: +# +# BEGIN { +# $ENV{HOME} = "/home/git"; # or whatever is the hosting user's $HOME +# $ENV{GL_BINDIR} = "/full/path/to/gitolite/src"; +# $ENV{GL_LIBDIR} = "/full/path/to/gitolite/src/lib"; +# } +# use lib $ENV{GL_LIBDIR}; +# use Gitolite::Easy; + +# API documentation +# ---------------------------------------------------------------------- +# documentation for each function is at the top of the function. +# Documentation is NOT in pod format; just read the source with a nice syntax +# coloring text editor and you'll be happy enough. (I do not like POD; please +# don't send me patches for this aspect of the module). + +#<<< +@EXPORT = qw( + is_admin + is_super_admin + in_group + in_role + + owns + can_read + can_write + + config + + textfile + + %rc + say + say2 + _die + _warn + _print + usage + + option +); +#>>> +use Exporter 'import'; + +use Gitolite::Rc; +use Gitolite::Common; +use Gitolite::Conf::Load; + +use strict; +use warnings; + +my $user; + +# ---------------------------------------------------------------------- + +# is_admin() + +# return true if $ENV{GL_USER} is set and has W perms to the admin repo + +# shell equivalent +# if gitolite access -q gitolite-admin $GL_USER W; then ... + +sub is_admin { + valid_user(); + return not( access( 'gitolite-admin', $user, 'W', 'any' ) =~ /DENIED/ ); +} + +# is_super_admin() + +# (useful only if you are using delegation) + +# return true if $ENV{GL_USER} is set and has W perms to any file in the admin +# repo + +# shell equivalent +# if gitolite access -q gitolite-admin $GL_USER W VREF/NAME/; then ... +sub is_super_admin { + valid_user(); + return not( access( 'gitolite-admin', $user, 'W', 'VREF/NAME/' ) =~ /DENIED/ ); +} + +# in_group() + +# return true if $ENV{GL_USER} is set and is in the given group + +# shell equivalent +# if gitolite list-memberships $GL_USER | grep -x $GROUPNAME >/dev/null; then ... +sub in_group { + valid_user(); + my $g = shift; + $g =~ s/^\@?/@/; + + return grep { $_ eq $g } @{ Gitolite::Conf::Load::list_memberships( '-u', $user ) }; +} + +# in_role() + +# return true if $ENV{GL_USER} is set and has the given role for the given repo + +# shell equivalent +# if gitolite list-memberships -u $GL_USER -r $GL_REPO | grep -x $ROLENAME >/dev/null; then ... +sub in_role { + valid_user(); + my $r = shift; + $r =~ s/^\@?/@/; + my $repo = shift; + + return grep { $_ eq $r } @{ Gitolite::Conf::Load::list_memberships( "-u", $user, "-r", $repo ) }; +} + +# owns() + +# return true if $ENV{GL_USER} is set and is an OWNER of the given repo. + +# shell equivalent (assuming GL_USER is set) +# if gitolite owns $REPONAME; then ... +sub owns { + valid_user(); + my $r = shift; + + # prevent unnecessary disclosure of repo existence info + return 0 if repo_missing($r); + + return ( creator($r) eq $user or $rc{OWNER_ROLENAME} and in_role( $rc{OWNER_ROLENAME}, $r ) ); +} + +# can_read() +# return true if $ENV{GL_USER} is set and can read the given repo + +# shell equivalent +# if gitolite access -q $REPONAME $GL_USER R; then ... +sub can_read { + valid_user(); + my $r = shift; + return not( access( $r, $user, 'R', 'any' ) =~ /DENIED/ ); +} + +# can_write() +# return true if $ENV{GL_USER} is set and can write to the given repo. +# Optional second argument can be '+' to check that instead of 'W'. Optional +# third argument can be a full ref name instead of 'any'. + +# shell equivalent +# if gitolite access -q $REPONAME $GL_USER W; then ... +sub can_write { + valid_user(); + my ( $r, $aa, $ref ) = @_; + $aa ||= 'W'; + $ref ||= 'any'; + return not( access( $r, $user, $aa, $ref ) =~ /DENIED/ ); +} + +# config() +# given a repo and a key, return a hash containing all the git config +# variables for that repo where the section+key match the regex. If none are +# found, return an empty hash. If you don't want it as a regex, use \Q +# appropriately + +# shell equivalent +# foo=$(gitolite git-config -r $REPONAME foo\\.bar) +sub config { + my $repo = shift; + my $key = shift; + + return () if repo_missing($repo); + + my $ret = git_config( $repo, $key ); + return %$ret; +} + +# ---------------------------------------------------------------------- + +# maintain a textfile; see comments in code for details, and calls in various +# other programs (like 'motd', 'desc', and 'readme') for how to call +sub textfile { + my %h = @_; + my $repodir; + + # target file + _die "need file" unless $h{file}; + _die "'$h{file}' contains a '/'" if $h{file} =~ m(/); + Gitolite::Conf::Load::sanity($h{file}, $REPONAME_PATT); + + # target file's location. This can come from one of two places: dir + # (which comes from our code, so does not need to be sanitised), or repo, + # which may come from the user + _die "need exactly one of repo or dir" unless $h{repo} xor $h{dir}; + _die "'$h{dir}' does not exist" if $h{dir} and not -d $h{dir}; + if ($h{repo}) { + Gitolite::Conf::Load::sanity($h{repo}, $REPONAME_PATT); + $h{dir} = "$rc{GL_REPO_BASE}/$h{repo}.git"; + _die "repo '$h{repo}' does not exist" if not -d $h{dir}; + + my $umask = option( $h{repo}, 'umask' ); + # note: using option() moves us to ADMIN_BASE, but we don't care here + umask oct($umask) if $umask; + } + + # final full file name + my $f = "$h{dir}/$h{file}"; + + # operation + _die "can't have both prompt and text" if defined $h{prompt} and defined $h{text}; + if (defined $h{prompt}) { + print STDERR $h{prompt}; + my $t = join( "", <> ); + _print($f, $t); + } elsif (defined $h{text}) { + _print($f, $h{text}); + } else { + return slurp($f) if -f $f; + } + + return ''; +} + +# ---------------------------------------------------------------------- + +sub valid_user { + _die "GL_USER not set" unless exists $ENV{GL_USER}; + $user = $ENV{GL_USER}; +} + +1; |