#!/bin/bash # easy install for gitolite # you run this on the client side, and it takes care of all the server side # work. You don't have to do anything on the server side directly # to do a manual install (since I have tested this only on Linux), open this # script in a nice, syntax coloring, text editor and follow the instructions # prefixed by the word "MANUAL" in the comments below :-) # run without any arguments for "usage" info # important setting: bail on any errors (else we have to check every single # command!) set -e # ---------------------------------------------------------------------- # bootstrap and main # ---------------------------------------------------------------------- if [[ $1 != boot/strap ]] then # did someone tell you you can't call functions before they're defined in # bash? Don't believe everything you hear ;-) . $0 boot/strap main "$@" cleanup exit 0 fi # ---------------------------------------------------------------------- # no direct executable statements after this; only functions # ---------------------------------------------------------------------- main() { basic_sanity "$@" setup_tempdir version_info "$@" [[ -n $admin_name ]] && setup_local_ssh copy_gl # src, conf, etc run_install [[ $upgrade == 0 ]] && initial_conf_key # MANUAL: cd to $GL_ADMINDIR and run "src/gl-compile-conf" ssh $p_port $user@$host "cd $GL_ADMINDIR; src/gl-auth-command -e src/gl-compile-conf $quiet" setup_pta clone_it } # ---------------------------------------------------------------------- # setup temp files # ---------------------------------------------------------------------- setup_tempdir() { export tmpgli=tmp-gl-install trap cleanup 0 mkdir -p $tmpgli } cleanup() { rm -rf $tmpgli } # ---------------------------------------------------------------------- # service functions # ---------------------------------------------------------------------- die() { echo "$@"; echo; echo "run $0 without any arguments for help and tips"; cleanup; exit 1; } >&2 prompt() { # receives two arguments. A short piece of text to be displayed, without # pausing, in "quiet" mode, and a much longer one to be displayed, *with* # a pause, in normal (verbose) mode [[ $quiet == -q ]] && [[ -n $1 ]] && { eval "echo \"$1\"" return } shift echo echo echo ------------------------------------------------------------------------ eval "echo \"$1\"" echo read -p '...press enter to continue or Ctrl-C to bail out' } usage() { cat </dev/null || die "cant find at least some files in gitolite sources/config; aborting" # MANUAL: make sure you have password-less (pubkey) auth on the server. # That is, running "ssh git@server" should log in straight away, without # asking for a password [[ $port -ne 22 ]] && p_port="-p $port" ssh $p_port -o PasswordAuthentication=no $user@$host true || die "pubkey access didn't work; please set it up using 'ssh-copy-id' or something" } # ---------------------------------------------------------------------- # version info # ---------------------------------------------------------------------- version_info() { # MANUAL: if needed, make a note of the version you are upgrading from, and to # record which version is being sent across; we assume it's HEAD if git rev-parse --is-inside-work-tree >/dev/null 2>&1 then git describe --tags --long HEAD 2>/dev/null > conf/VERSION || echo '(unknown)' > conf/VERSION else [[ -f conf/VERSION ]] || echo '(unknown)' > conf/VERSION fi # what was the old version there? export upgrade_details="you are upgrading \ $(ssh $p_port $user@$host cat gitolite-install/conf/VERSION 2>/dev/null || echo '(or installing first-time)' ) \ to $(cat conf/VERSION)" prompt "$upgrade_details" "$v_upgrade_details" } # ---------------------------------------------------------------------- # new keypair, ssh-config para; only on "install" (not upgrade) # ---------------------------------------------------------------------- setup_local_ssh() { # MANUAL: create a new key for you as a "gitolite user" (as opposed to you # as the "gitolite admin" who needs to login to the server and get a # command line). For example, "ssh-keygen -t rsa ~/.ssh/sitaram"; this # would create two files in ~/.ssh (sitaram and sitaram.pub) prompt "setting up keypair..." "$v_setting_up_keypair" if [[ -f "$HOME/.ssh/$admin_name.pub" ]] then prompt "" "$v_reuse_pubkey" else ssh-keygen -t rsa -f "$HOME/.ssh/$admin_name" || die "ssh-keygen failed for some reason..." fi # MANUAL: copy the pubkey created to the server, say to /tmp. This would # be "scp ~/.ssh/sitaram.pub git@server:/tmp" (the script does this at a # later stage, you do it now for convenience). Note: only the pubkey # (sitaram.pub). Do NOT copy the ~/.ssh/sitaram file -- that is a private # key! # MANUAL: if you're running ssh-agent (see if you have an environment # variable called SSH_AGENT_PID in your "env"), you should add this new # key. The command is "ssh-add ~/.ssh/sitaram" if ssh-add -l &>/dev/null then prompt " ...adding key to agent..." "$v_ssh_add" ssh-add "$HOME/.ssh/$admin_name" fi # MANUAL: you now need to add some lines to the end of your ~/.ssh/config # file. If the file doesn't exist, create it. Make sure the file is # "chmod 644". # The lines to be included look like this: # host gitolite # user git # hostname server # port 22 # identityfile ~/.ssh/sitaram echo "host $host_nickname user $user hostname $host port $port identityfile ~/.ssh/$admin_name" > $tmpgli/.gl-stanza if grep "host *$host_nickname" "$HOME/.ssh/config" &>/dev/null then prompt "found gitolite para in ~/.ssh/config; assuming it is correct..." "$v_found_para" else prompt "creating gitolite para in ~/.ssh/config..." "$v_creating_para" cat $tmpgli/.gl-stanza >> "$HOME/.ssh/config" # if the file didn't exist at all, it might have the wrong permissions chmod 644 "$HOME/.ssh/config" fi } # ---------------------------------------------------------------------- # server side # ---------------------------------------------------------------------- copy_gl() { # MANUAL: copy the gitolite directories "src", "conf", and "doc" to the # server, to a directory called (for example) "gitolite-install". You may # have to create the directory first. ssh $p_port $user@$host mkdir -p gitolite-install scp $quiet ${p_port/p/P} -p -r src conf doc hooks $user@$host:gitolite-install/ # MANUAL: now log on to the server (ssh git@server) and get a command # line. This step is for your convenience; the script does it all from # the client side but that may be too much typing for manual use ;-) # MANUAL: cd to the "gitolite-install" directory where the sources are. # Then copy conf/example.gitolite.rc as ~/.gitolite.rc and edit it if you # wish to change any paths. Make a note of the GL_ADMINDIR and REPO_BASE # paths; you will need them later prompt "finding/creating gitolite rc..." "$v_edit_glrc" # lets try and get the file from there first if scp ${p_port/p/P} $user@$host:.gitolite.rc $tmpgli &>/dev/null then prompt " ...trying to reuse existing rc" \ "Oh hey... you already had a '.gitolite.rc' file on the server. Let's see if we can use that instead of the default one..." < $tmpgli/.gitolite.rc perl -ne 'print "$1\n" if /^\s*(\$\w+) *=/' | sort > $tmpgli/glrc.old < conf/example.gitolite.rc perl -ne 'print "$1\n" if /^\s*(\$\w+) *=/' | sort > $tmpgli/glrc.new # msysgit doesn't have "comm". diff is not ideal for our purposes # because we only care about differences in one direction, but we'll # have to make do... set +e diff -u $tmpgli/glrc.old $tmpgli/glrc.new | grep '^+.*\$' > $tmpgli/glrc.comm13 set -e if [[ ! -s $tmpgli/glrc.comm13 ]] then [[ $quiet == -q ]] || ${VISUAL:-${EDITOR:-vi}} $tmpgli/.gitolite.rc else echo new variables found in rc file: cat $tmpgli/glrc.comm13 echo # MANUAL: if you're upgrading, read the instructions below and # manually make sure your final ~/.gitolite.rc has both your existing # customisations as well as any new variables that the new version of # gitolite has introduced prompt "" "$v_upgrade_glrc" ${VISUAL:-${EDITOR:-vi}} conf/example.gitolite.rc $tmpgli/.gitolite.rc fi else cp conf/example.gitolite.rc $tmpgli/.gitolite.rc [[ $quiet == -q ]] || ${VISUAL:-${EDITOR:-vi}} $tmpgli/.gitolite.rc fi # copy the rc across scp $quiet ${p_port/p/P} $tmpgli/.gitolite.rc $user@$host: } run_install() { prompt "installing/upgrading..." "$v_ignore_stuff" # extract the GL_ADMINDIR, REPO_BASE and GIT_PATH locations GL_ADMINDIR=$(ssh $p_port $user@$host gitolite-install/src/gl-query-rc GL_ADMINDIR) REPO_BASE=$( ssh $p_port $user@$host gitolite-install/src/gl-query-rc REPO_BASE) GIT_PATH=$( ssh $p_port $user@$host gitolite-install/src/gl-query-rc GIT_PATH) # determine if this is an upgrade; we decide based on whether a file # called $GL_ADMINDIR/conf/gitolite.conf exists on the remote side. We # can't do this till we know the correct value for GL_ADMINDIR upgrade=0 if ssh $p_port $user@$host cat $GL_ADMINDIR/conf/gitolite.conf &> /dev/null then upgrade=1 ssh $p_port $user@$host cat $GL_ADMINDIR/conf/gitolite.conf 2> /dev/null | grep '@SHELL' && prompt "" "$v_at_shell_bwi" [[ -n $admin_name ]] && echo -e "\n *** WARNING ***: looks like an upgrade... ignoring argument '$admin_name'" else [[ -z $admin_name ]] && die " *** ERROR ***: doesn't look like an upgrade, so I need a name for the admin" fi # MANUAL: still in the "gitolite-install" directory? Good. Run # "src/gl-install" ssh $p_port $user@$host "cd gitolite-install; src/gl-auth-command -e src/gl-install $quiet" # MANUAL: if you're upgrading, run "src/gl-compile-conf" and you're done! # -- ignore the rest of this file for the purposes of an upgrade } # ---------------------------------------------------------------------- # from here on it's install only # ---------------------------------------------------------------------- # MANUAL: setup the initial config file. Edit $GL_ADMINDIR/conf/gitolite.conf # and add at least the following lines to it: # repo gitolite-admin # RW+ = sitaram initial_conf_key() { echo "#gitolite conf # please see doc/gitolite.conf.mkd for details on syntax and features repo gitolite-admin RW+ = $admin_name repo testing RW+ = @all " > $tmpgli/gitolite.conf # send the config and the key to the remote scp $quiet ${p_port/p/P} $tmpgli/gitolite.conf $user@$host:$GL_ADMINDIR/conf/ scp $quiet ${p_port/p/P} "$HOME/.ssh/$admin_name.pub" $user@$host:$GL_ADMINDIR/keydir } # ---------------------------------------------------------------------- # hey lets go the whole hog on this; setup push-to-admin! # ---------------------------------------------------------------------- setup_pta() { # MANUAL: you have to now make the first commit in the admin repo. This # is a little more complex, so read carefully and substitute the correct # paths. What you have to do is: # cd $REPO_BASE/gitolite-admin.git # GIT_WORK_TREE=$GL_ADMINDIR git add conf/gitolite.conf keydir # GIT_WORK_TREE=$GL_ADMINDIR git commit -am start # Substitute $GL_ADMINDIR and $REPO_BASE appropriately. Note there is no # space around the "=" in the second and third lines. echo "cd $REPO_BASE/gitolite-admin.git PATH=\$PATH:$GIT_PATH GIT_WORK_TREE=$GL_ADMINDIR git add conf/gitolite.conf keydir GIT_WORK_TREE=$GL_ADMINDIR git diff --cached --quiet 2>/dev/null || GIT_WORK_TREE=$GL_ADMINDIR git commit -am start " | ssh -T $p_port $user@$host # MANUAL: now that the admin repo is created, you have to set the hooks # properly. The install program does this. So cd back to the # "gitolite-install" directory and run "src/gl-install" ssh $p_port $user@$host "cd gitolite-install; src/gl-auth-command -e src/gl-install $quiet" # MANUAL: you're done! Log out of the server, come back to your # workstation, and clone the admin repo using "git clone # gitolite:gitolite-admin", or pull once again if you already have a # clone } clone_it() { cleanup cd "$HOME" if [[ -d $host_nickname-admin ]] then echo $HOME/$host_nickname-admin exists, skipping clone step... else prompt "cloning $host_nickname-admin repo..." "$v_cloning" git clone $host_nickname:gitolite-admin $host_nickname-admin fi # MANUAL: be sure to read the message below; this applies to you too... echo echo echo --------------------------------------------------------------- eval "echo \"$v_done\"" } # ---------------------------------------------------------------------- # prompt strings # ---------------------------------------------------------------------- v_upgrade_details=" \$upgrade_details Note: getting '(unknown)' for the 'from' version should only happen once. Getting '(unknown)' for the 'to' version means you are probably installing from a tar file dump, not a real clone. This is not an error but it's nice to have those version numbers in case you need support. Try and install from a clone " v_setting_up_keypair=" the next command will create a new keypair for your gitolite access The pubkey will be \$HOME/.ssh/\$admin_name.pub. You will have to choose a passphrase or hit enter for none. I recommend not having a passphrase for now, *especially* if you do not have a passphrase for the key which you are already using to get server access! Add one using 'ssh-keygen -p' after all the setup is done and you've successfully cloned and pushed the gitolite-admin repo. After that, install 'keychain' or something similar, and add the following command to your bashrc (since this is a non-default key) ssh-add "\\\$HOME/.ssh/\$admin_name" This makes using passphrases very convenient. " v_reuse_pubkey=" Hmmm... pubkey \$HOME/.ssh/\$admin_name.pub exists; should I just (re-)use it? IMPORTANT: once the install completes, *this* key can no longer be used to get a command line on the server -- it will be used by gitolite, for git access only. If that is a problem, please ABORT now. doc/ssh-troubleshooting.mkd will explain what is happening here, if you need more info. " v_ssh_add=" you're running ssh-agent. We'll try and do an ssh-add of the private key we just created, otherwise this key won't get picked up. If you specified a passphrase in the previous step, you'll get asked for one now -- type in the same one. " v_found_para=" your \\\$HOME/.ssh/config already has settings for gitolite. I will assume they're correct, but if they're not, please edit that file, delete that paragraph (that line and the following few lines), Ctrl-C, and rerun. In case you want to check right now (from another terminal) if they're correct, here's what they are *supposed* to look like: \$(cat \$tmpgli/.gl-stanza) " v_creating_para=" creating settings for your gitolite access in \$HOME/.ssh/config; these are the lines that will be appended to your ~/.ssh/config: \$(cat \$tmpgli/.gl-stanza) " v_edit_glrc=" the gitolite rc file needs to be edited by hand. The defaults are sensible, so if you wish, you can just exit the editor. Otherwise, make any changes you wish and save it. Read the comments to understand what is what -- the rc file's documentation is inline. Please remember this file will actually be copied to the server, and that all the paths etc. represent paths on the server! " v_upgrade_glrc=" looks like you're upgrading, and there are some new rc variables that this version is expecting that your old rc file doesn't have. I'm going to run your \\\$EDITOR with two filenames. The first is the example file from this gitolite version. It will have a block (code and comments) for each of the variables shown above with a '+' sign. The second is your current rc file, the destination. Copy those lines into this file, preferably *with* the surrounding comments (for clarity) and save it. This is necessary; please dont skip this! [It's upto you to figure out how your \\\$EDITOR handles 2 filename arguments, switch between them, copy lines, etc ;-)] " v_ignore_stuff=" ignore any 'please edit this file' or 'run this command' type lines in the next set of command outputs coming up. They're only relevant for a manual install, not this one... " v_at_shell_bwi=" you are using the @SHELL feature in your gitolite config. This feature has now changed in a backward incompatible way; see doc/ssh-troubleshooting.mkd for information on migrating this to the new syntax. DO NOT hit enter unless you have understood that information and properly migrated your setup, or you are sure you have shell access to the server through some other means than the $admin_name key. " v_done=" done! IMPORTANT NOTE -- PLEASE READ!!! *Your* URL for cloning any repo from this server will be \$host_nickname:reponame.git Note: If you are upgrading and you set a host nickname during initial setup, please use that host nickname instead of \"gitolite\" above. *Other* users you set up will have to use \$user@\$host:reponame.git However, if your server uses a non-standard ssh port, they should use ssh://\$user@\$host:\$port/reponame.git If this is your first time installing gitolite, please also: tail -31 \$0 for next steps. " v_cloning=" now we will clone the gitolite-admin repo to your workstation and see if it all hangs together. We'll do this in your \\\$HOME for now, and you can move it elsewhere later if you wish to. " tail=" NOTE: All the below stuff is on your *workstation*. You should not, normally, have to do anything directly on your server to administer/use gitolite. The admin repo is currently cloned at ~/gitolite-admin. You can reclone it anywhere else if you wish. To administer gitolite, make changes to the config file (conf/gitolite.conf) and/or the pubkeys (in subdirectory 'keydir') in any clone, then git add, git commit, and git push. ADDING REPOS: Do NOT add repos manually on the server. Edit the config file to give *some* user access to the repo. When you push, an empty repo will be created on the server. ADDING USERS: copy their pubkey as keydir/.pub, add it, commit and push. CONFIG FILE FORMAT: see doc/gitolite.conf.mkd SSH MAGIC: Remember you (the admin) now have *two* keys to access the server hosting your gitolite setup -- one to get you a command line, and one to get you gitolite access; see doc/ssh-troubleshooting.mkd. If you're not using keychain or some such software, you may have to run an 'ssh-add' command to add that key each time you log in. URLS: *Your* URL for cloning any repo on this server is different from the url that the *other* users have to use. The easy install command should tell you what these URLs look like, at the end of each successful run. Feel free to re-run easy install again (using the same arguments) if you missed it. UPGRADING GITOLITE: just pull a fresh clone from github, and run the same easy install command as before, with the same arguments. "