Created
June 8, 2017 13:11
-
-
Save mjhennig/a1c533ab235b0d1495b8abc50c901b0b to your computer and use it in GitHub Desktop.
Combining Git and Mercurial using a custom login shell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # This script is part of the Uplink project. It is used as login-shell for | |
| # SSH users git@ and hg@ in development, allowing for integration of both Git | |
| # and Mercurial workflows, and for the user to push into any repository that | |
| # is identified by a valid name, irregardless whether it exists already. | |
| basename="`basename \"$0\"`" | |
| # Login shells are meant to be executed with option -c followed by a command | |
| if [ $# -ne 2 -o "x-c" != "x$1" ]; then | |
| echo "$basename: Invalid or malformed login shell command: $@" >&2 | |
| exit 1 | |
| fi | |
| # Environment variable $SSH_ORIGINAL_COMMAND is required by hg-ssh(8) only, | |
| # but made available to the entire process, including any Git triggers: | |
| SSH_ORIGINAL_COMMAND="$2" | |
| export SSH_ORIGINAL_COMMAND | |
| # Expand the parameter list according to the given command: | |
| set -e -- $2 | |
| # Determine which SCM the client is using: | |
| case "$USER" in | |
| *hg*|*mercurial*) # https://www.mercurial-scm.org/wiki/SharedSSH#hg-ssh | |
| if [ $# -eq 5 -a "# $1 $2 ... $4 $5" = "# hg -R ... serve --stdio" ]; then | |
| backend="hg-ssh" | |
| convert="push" | |
| repository="$3" | |
| set -- "$repository" | |
| else | |
| echo "$basename: Malformed or unrecognized Mercurial command: $@" >&2 | |
| exit 1 | |
| fi;; | |
| *git*) # https://git-scm.com/docs/git-shell | |
| if [ $# -eq 2 -a "# ${1%%-*}-command ..." = "# git-command ..." ]; then | |
| backend="git-shell" | |
| convert="pull" | |
| repository=${2%"'"}; repository=${repository#"'"} | |
| set -- -c "$1 '$repository/.git'" | |
| else | |
| echo "$basename: Malformed or unrecognized Git command: $@" >&2 | |
| exit 1 | |
| fi;; | |
| *) echo "$basename: Try Git or Mercurial instead of: $@" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| # Ensure the repository name is neither empty nor contains any path fragments: | |
| case "$repository" in */*|*.*|'') | |
| echo "$basename: Invalid repository name: '$repository'" >&2 | |
| exit 1;; | |
| esac | |
| # The directory associated with the repository hosts not only the Mercurial | |
| # and Git resources, but also the lock file for remote operations, hence it | |
| # must exist even before the repositories are crated on-demand (see below) | |
| mkdir -p "$repository" | |
| # All interaction with the repository is done in transaction scope: After | |
| # aquiring a lock on the repository, execution is delegated to either the | |
| # Git or Mercurial handler, before finally synchronizing the repositories | |
| # and releasing the lock: | |
| ( if ! flock -n 9; then | |
| echo "$basename: Encountered lock on \"$repository\"" >&2 | |
| exit 1 | |
| fi | |
| # Ensure the Mercurial repository has been initialized | |
| test -d "$repository/.hg" || hg init -q "$repository" >&2 | |
| # Ensure the Git repository has been initialized | |
| test -d "$repository/.git" || git init -q --bare "$repository/.git" >&2 | |
| # Invoke the "original" SCM shell handler: | |
| $backend "$@" | |
| # Perform the subsequent synchronization via hg-git pull or push: | |
| hg -R "$repository" $convert -q --force "$repository/.git" >&2 | |
| ) 9>"$repository/.lock" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment