Skip to content

Instantly share code, notes, and snippets.

@jorsn
Last active May 8, 2024 14:15
Show Gist options
  • Save jorsn/398ba31ac6fbfcf1c25eb6e0e07a3773 to your computer and use it in GitHub Desktop.
Save jorsn/398ba31ac6fbfcf1c25eb6e0e07a3773 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# This script sets up git similar to the git bridge of Overleaf. It is based on
# instructions by Tobias Bora (https://github.com/sagemathinc/cocalc/issues/3811#issuecomment-493138304).
# If the repository and git hooks do not exist, they are created.
# If they do exist, then this script tells you about config conflicts and how to
# resolve them.
#
#
# Usage:
#
# 1. Copy this file to your cocalc project, e.g. via ssh,
# or copy it to the clipboard, type in a terminal in cocalc
#
# $ cat <<'EOS' > git-bridge-setup.sh
# <paste clipboard, e.g. Ctrl+v>
# EOS
#
# 2. run it (e.g. 'bash git-bridge-setup.sh')
# Optionally, you can specify the GIT_PROJECT_PATH (Default: 'repo'):
#
# $ GIT_PROJECT_PATH=foo bash git-bridge-setup.sh
#
# It is either absolute or interpreted relative to the home directory.
#
#
# MIT License
#
# Copyright (c) Johannes Rosenberger
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
GIT_PROJECT_PATH="${GIT_PROJECT_PATH:-repo}"
cd /home/user
mkdir -p bin "$GIT_PROJECT_PATH"
#########################
# set up git-server-hooks
maybe_continue_ask() {
echo -n "Continue (y/*)? " >&2
read response
if [ "$response" == y ]; then
echo "Continuing..." >&2
else
echo "Exiting." >&2
exit
fi
}
write_hook() {
file="/home/user/bin/$1"
content="$2"
if [ -f "$file" ]; then
echo "cocalc-setup-git-bridge: warning: file '$file' exists. Please set up hook manually:" >&2
echo ''
echo "$content" | sed 's/^/ /'
echo ''
maybe_continue_ask
else
echo "$content" > "$file"
chmod u+x "$file"
fi
}
write_hook git-upload-pack "$(cat <<EOF
#!/usr/bin/env bash
GIT_PROJECT_PATH="\${GIT_PROJECT_PATH:-$GIT_PROJECT_PATH}"
(>&2 echo "====== Let's first commit if needed =====")
cd "\$GIT_PROJECT_PATH"
(git add . && git commit -am "Online change") 1>&2
(>&2 echo "====== Now let's do the clone/pull =====")
cd ~/
/usr/bin/git-upload-pack "\$@"
EOF
)"
write_hook git-receive-pack "$(cat <<EOF
#!/usr/bin/env bash
GIT_PROJECT_PATH="\${GIT_PROJECT_PATH:-$GIT_PROJECT_PATH}"
(>&2 echo "====== Let's first commit if needed =====")
cd "\$GIT_PROJECT_PATH"
(git add . && git commit -am "Online change") 1>&2
(>&2 echo "====== Now let's do the push =====")
cd ~/
/usr/bin/git-receive-pack "\$@"
(>&2 echo "====== Push finished, let's reset on server =====")
cd "\$GIT_PROJECT_PATH"
git reset --hard HEAD 1>&2
EOF
)"
#################
# set up git repo
error_conflicting_git_config() {
cat <<EOF >&2
cocalc-setup-git-bridge: warning: conflicting git config. Please ensure the following settings:
$gitconfig receive.denyCurrentBranch = ignore # necessary for git push to work
# some safety/security settings
$gitconfig receive.denyDeleteCurrent = true
$gitconfig receive.denyNonFastForwards = true
$gitconfig receive.denyDeletes = true
EOF
exit 1
}
gitconfig_try_set() {
key="$1"
valueNew="$2"
valueOld="$($gitconfig --get "$key")"
if [ $? == 0 ]; then
if [ "$valueOld" != "$valueNew" ]; then
error_conflicting_git_config
fi
else
echo "setting $gitconfig '$key' '$valueNew'"
$gitconfig "$key" "$valueNew"
fi
}
gitconfig='git config --local'
cd
cd "$GIT_PROJECT_PATH"
git_new=false
if [ ! -d .git ]; then
git_new=true
git init
fi
# set user.{email,name}, if unset
for key in user.{email,name}; do
$gitconfig --get $key >/dev/null || $gitconfig $key cocalc
done
# allow pushing to checked-out branch
gitconfig_try_set receive.denyCurrentBranch ignore
# some safety/security measures against accidental destruction
for key in receive.{denyDeleteCurrent,denyNonFastForwards,denyDeletes}; do
gitconfig_try_set "$key" true
done
# set up .gitignore
cat <<'EOF' >> .gitignore
/build # if you want to use a build dir in the repo, which won't be deleted on container restart
build/
*.pdf # comment out if you want to sync pdf built by cocalc
*.synctex.gz
*.syncdb
*.sage-chat
EOF
######################################
# instructions for local ssh+git setup
SSH_USER="${COCALC_PROJECT_ID//-/}"
cat <<EOF
Git-bridge config files are set up. To complete configuration, add
"PATH": "/home/user/bin",
to the 'Custom Environment Variables' in the project settings.
Then, you can setup an ssh key, e.g. with
ssh-keygen -t ed25519
and copy the public key into your cocalc profile or the project settings.
The default key location is ~/.ssh/id_<keytype>.pub, e.g. ~/.ssh/id_ed25519.pub.
Then, clone this to your local git repo using
git clone [email protected]:$GIT_PROJECT_PATH [<target directory>]
or, in your local git repo, add the cocalc project as a git remote, e.g. as 'origin', using
git remote add origin [email protected]:$GIT_PROJECT_PATH
git pull --rebase
git push
Now, you can also ssh into the project with the command
ssh "\$(git remote get-url $* | sed 's/\(@[^:]\+\)\(:.*\)\?\$/\1/g')"
The cocalc project must be running in order to connect using git/ssh.
You can start the project with a button in the cocalc console, in the project settings,
or via the api as folows:
First, set up an api key in the project settings and store it in the file 'cocalc_api_key'.
Then, you can start the project using
regex='^([a-z0-9]{8})([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]+)@ssh.cocalc.com.*\$'
project_id="\$(git remote get-url cocalc | sed -E s/"\$regex"/'\\1-\\2-\\3-\\4-\\5'/)"
curl -u \$(cat cocalc_api_key): -d bash=true -d command=true -d project_id="\$project_id" \
https://cocalc.com/api/v1/project_exec
WARNING:
1. Do not store a user key in cocalc_api_key, only a project key. Otherwise, when you sync
this file via git, everyone with access to the repo would have access to your user and all your projects.
2. Watch out if you share the git repo outside its cocalc project: Whoever knows to the api key
can modify the cocalc project and add/remove collaborators.
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment