GL_BINDIR2 becomes LOCAL_CODE, allows hook propagation also...

plus a bunch of doc changes
This commit is contained in:
Sitaram Chamarty 2012-06-13 14:43:19 +05:30
parent 3c0f177481
commit 4373c5c74c
8 changed files with 126 additions and 106 deletions

View file

@ -5,7 +5,9 @@ not considered "core". This keeps the core simpler, and allows you to enhance
gitolite for your own purposes without too much fuss. (As an extreme example,
even mirroring is not in core now!)
(Also, please see the [developer notes][dev-notes] page).
This document will tell you about the types of non-core programs, and
how/where to install your own. (Actually *writing* the code is described in
the [developer notes][dev-notes] page).
----
@ -13,13 +15,13 @@ even mirroring is not in core now!)
----
## types of non-core programs
## introduction
There are 5 basic types of non-core programs.
* *Commands* can be run from the shell command line. Among those, the ones
listed in the COMMANDS hash of the rc file can also be run remotely.
* *Hooks* are standard git hooks; see below.
* *Hooks* are standard git hooks.
* *Sugar scripts* change the conf language for your convenience. The word
sugar comes from "syntactic sugar".
* *Triggers* are to gitolite what hooks are to git. I just chose a
@ -29,9 +31,76 @@ There are 5 basic types of non-core programs.
[Here][non-core] is a list of non-core programs shipped with gitolite, with
some description of each.
## #commands gitolite "commands"
## locations
Gitolite comes with several commands that users can run. Remote users run the
### default/primary location of non-core programs
Regardless of how you installed gitolite, `gitolite query-rc GL_BINDIR` will
tell you where the programs reside. Within that directory, the locations of
non-core programs are:
* `commands` for commands.
* `syntactic-sugar` for sugar scripts.
* `triggers` and `lib/Gitolite/Triggers` for triggers ([this][triggers] will
explain the difference).
* `VREF` for [VREFs][vref].
### #localcode alternate location -- the `LOCAL_CODE` rc variable
If you want to add new non-core programs to your installation, or override the
shipped non-core programs with your own versions, it's easy enough to simply
copy your programs to the appropriate directory above, but then they'd get
wiped out on the next upgrade.
A simple, "git-ish", method is to maintain a "local" branch in your clone of
the gitolite source repo and make your changes there. Maintain them using
rebase or merge when you 'git pull' gitolite itself, then use the rebased or
merged "local" as the source for your gitolite upgrades. Works very nicely,
and uses nothing but your git knowledge.
Sadly, it doesn't work for people installing from RPMs/DEBs; their "primary
location" has already been setup, so any site-local customisations have to be
done elsewhere.
This is where `LOCAL_CODE` comes in. If you define the `LOCAL_CODE` rc
variable, then its value (**please use a FULL path**) describes a location
where you can have any or all of these subdirectories:
* `commands`
* `hooks/common`
* `syntactic-sugar`
* `triggers` and `lib/Gitolite/Triggers`
* `VREF`
You might have noticed there's a new `hooks/common` directory here so you can
add hooks also using this mechanism. Unlike the rest of the directories,
adding new hooks to `hooks/common` requires that you follow up with `gitolite
setup`, or at least `gitolite setup --hooks-only`.
### #pushcode managing custom code via the gitolite-admin repo
The location given in `LOCAL_CODE` could be anywhere on disk.
However, if you point it to someplace inside `$GL_ADMIN_BASE` (i.e.,
`$HOME/.gitolite`), then you can version those programs using the
gitolite-admin repo.
I suggest using a directory called "local-code" within the gitolite-admin repo
that contains as much of the above directory structure you need. If you do
that, then this is what you'd have in the rc file:
LOCAL_CODE => "$ENV{HOME}/.gitolite/local-code",
When you do this, gitolite takes care of everything automatically, including
running `gitolite setup --hooks-only` when you change any hooks and push.
**However, if you do this, anyone who can push changes to the admin repo will
effectively be able to run any arbitrary command on the server.**
## types of non-core programs
### #commands gitolite "commands"
Gitolite comes with several commands that users can run. Remote users run
commands by saying:
ssh git@host command-name [args...]
@ -46,23 +115,25 @@ checking for the presence of env var `GL_USER`.
You can get a **list of available commands** by using the `help` command.
Naturally, a remote user will see a much smaller list than the server user.
You add commands to the "allowed from remote" list by adding its name (or
uncommenting it if it's already added but commented out) to the COMMANDS hash
in the [rc][] file.
You allow a command to be run from remote clients by adding its name to (or
uncommenting it if it's already added but commented out) the COMMANDS hash in
the [rc][] file.
If you write your own commands, put them in src/commands.
### #hooks hooks and gitolite
## #hooks hooks and gitolite
You can install any hooks except these:
Gitolite uses the `update` hook for all repos. In addition, it uses the
`post-update` hook for the gitolite-admin repo.
* (all repos) gitolite reserves the `update` hook. See the "update hook"
section in [dev-notes][] if you want additional update hook functionality.
If you want to add your own hook, it's easy as long as it's not the 'update'
hook. Just add it to `$HOME/.gitolite/hooks/common` and run `gitolite setup`.
* (gitolite-admin repo only) gitolite reserves the `post-update` hook.
The rest is between you and 'man githooks' :-)
How/where to install them is described in detail in the "locations" section
above, especially [this][localcode] and [this][pushcode]. The summary is that
you put them in the "hooks/common" sub-directory within the directory whose
name is given in the `LOCAL_CODE` rc variable.
## #sugar syntactic sugar
### #sugar syntactic sugar
Sugar scripts help you change the perceived syntax of the conf language. The
base syntax of the language is very simple, so sugar scripts take something
@ -74,10 +145,10 @@ lines), while the parser in the core gitolite engine does not change.
If you want to write your own sugar scripts, please read the "your own sugar"
section in [dev-notes][] first then email me.
## triggers
### triggers
Triggers have their own [document][triggers].
## VREFs
### VREFs
VREFs also have their own [document][vref].

View file

@ -7,8 +7,9 @@
Gitolite has a huge bunch of existing features that gradually need to moved
over. Plus you may want to write your own programs to interact with it.
Here are some random notes on developing hooks, commands, triggers, and sugar
scripts.
**This document is about *writing* hooks, commands, triggers, VREFS, and sugar
scripts. *Installing* them, including "where and how", is described
[here][localcode]**.
## environment variables and other inputs
@ -56,14 +57,19 @@ serve as documentation.
## writing your own...
### ...commands
Commands are standalone programs, in any language you like. They simply
receive the arguments you append. In addition, the env var `GL_USER` is
available if it is being run remotely. src/commands/desc is the best example
at present.
### ...hooks
#### anything but the update hook
If you want to add your own hook, it's easy as long as it's not the 'update'
hook. Just add it to `$HOME/.gitolite/hooks/common` and run `gitolite setup`.
The rest is between you and 'man githooks' :-)
If you want to add any hook other than the update hook, 'man githooks' is all
you need.
#### update hook
@ -71,7 +77,8 @@ If you want to add additional `update` hook functionality, do this:
* Write and test your update hook separately from gitolite.
* Now add the code to src/VREF. Let's say it is called "foo".
* Now add the code as a VREF (see [here][localcode] for details). Let's say
you called it "foo".
* To call your new update hook to all accesses for all repos, add this to
the end of your conf file:
@ -79,24 +86,13 @@ If you want to add additional `update` hook functionality, do this:
repo @all
- VREF/foo = @all
As you probably guessed, you can now make your additional update hooks more
As you probably guessed, you can make your additional update hooks more
selective, applying them only to some repos / users / combinations.
Note: a normal update hook expects 3 arguments (ref, old SHA, new SHA). A
VREF will get those three, followed by at least 4 more. Your VREF should just
ignore the extra args.
### ...commands
You can add your own commands. You can run them on the server (example,
`gitolite access`). Then you can enable certain commands to be allowed to run
by a remote user by adding them to the "COMMANDS" hash of the [rc][] file.
Commands are standalone programs, in any language you like. They simply
receive the arguments you append. In addition, the env var `GL_USER` is
available if it is being run remotely. src/commands/desc is the best example
at present.
### ...trigger programs
Trigger programs run at specific points in gitolite's execution, with specific

View file

@ -101,7 +101,7 @@
* the [subconf][] command
* ([link][partial-copy]: faking selective READ control)
* using pubkeys obtained [from elsewhere][keysonly]
* [updating hooks][pushhook] via the admin repo
* ([link][pushcode]: updating code via the admin repo)
## interfacing with [external][] tools

View file

@ -98,24 +98,7 @@ information.
DEFAULT_ROLE_PERMS => "READERS \@all\nWRITERS \@senior_devs",
* `GL_BINDIR2`, string
* `LOCAL_CODE`, 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
This is described in more detail [here][localcode]. Please be aware
**this must be a FULL path**, not a relative path.

View file

@ -68,41 +68,3 @@ Then write a script that
Run this from cron or however you want.
## #pushhook updating hooks via the admin repo
Gitolite by default maintains the distinction between someone who can push to
the admin repo and someone who has shell access to the server. As a result,
you cannot change any hooks merely by pushing the admin repo.
But some people don't care about this and want to do it anyway. Besides,
there *is* one advantage: your hooks can also be versioned now.
So here's how to add/change hooks when you push the gitolite-admin repo:
1. Put all common hooks in a new directory called 'common-hooks'.
2. Create a trigger program called 'propagate-hooks' in 'src/triggers' that
contains this:
#!/bin/sh
cd $GL_ADMIN_BASE
cp -a common-hooks/* hooks/common
gitolite setup --hooks-only
3. Add this to the `POST_COMPILE` trigger list in the rc file.
And that should be it, pretty much.
If you have lots of repos this is inefficient -- because the hook fixup will
run on *any* change to the admin repo, even if the change has nothing to do
with hooks.
If you're concerned about this, put the script in 'src/commands' instead of
'src/triggers'. (You might want to add some access control; see other
commands for inspiration, but it's not really needed in this case).
Then, whenever any hooks have changed, the admin can run
ssh git@host propagate-hooks

View file

@ -323,14 +323,13 @@ sub store_common {
$hook_reset++;
}
# propagate user hooks
# propagate user-defined (custom) hooks to all repos
ln_sf( "$rc{LOCAL_CODE}/hooks/common", "*", "$repo.git/hooks" ) if $rc{LOCAL_CODE};
# override/propagate gitolite defined hooks for all repos
ln_sf( "$rc{GL_ADMIN_BASE}/hooks/common", "*", "$repo.git/hooks" );
# propagate admin hook
# override/propagate gitolite defined hooks for the admin repo
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...
}
}

View file

@ -25,11 +25,20 @@ sub post_update {
tsh_try("git ls-tree --name-only master");
_die "no files/dirs called 'hooks' or 'logs' are allowed" if tsh_text() =~ /^(hooks|logs)$/m;
my $hooks_changed = 0;
{
local $ENV{GIT_WORK_TREE} = $rc{GL_ADMIN_BASE};
tsh_try("git diff --name-only master");
$hooks_changed++ if tsh_text() =~ m(/hooks/common/);
# the leading slash ensure that this hooks/common directory is below
# some top level directory, not *at* the top. That's LOCAL_CODE, and
# it's actual name could be anything but it doesn't matter to us.
tsh_try("git checkout -f --quiet master");
}
_system("gitolite compile");
_system("gitolite setup --hooks-only") if $hooks_changed;
_system("gitolite trigger POST_COMPILE");
exit 0;

View file

@ -87,7 +87,7 @@ do $ENV{G3T_RC} if exists $ENV{G3T_RC} and -r $ENV{G3T_RC};
# setup some perl/rc/env vars
# ----------------------------------------------------------------------
unshift @INC, "$rc{GL_BINDIR2}/lib" if $rc{GL_BINDIR2};
unshift @INC, "$rc{LOCAL_CODE}/lib" if $rc{LOCAL_CODE};
$ENV{PATH} = "$ENV{GL_BINDIR}:$ENV{PATH}";
@ -232,13 +232,13 @@ sub trigger {
}
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.
# looks for a file in LOCAL_CODE or GL_BINDIR. Returns whichever exists
# (LOCAL_CODE 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};
unshift @files, ("$rc{LOCAL_CODE}/$file") if $rc{LOCAL_CODE};
for my $f ( @files ) {
return $f if -x $f;