diff options
Diffstat (limited to 'git-repo')
-rwxr-xr-x | git-repo | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/git-repo b/git-repo new file mode 100755 index 0000000..8bded4f --- /dev/null +++ b/git-repo @@ -0,0 +1,221 @@ +#!/usr/bin/env bash +BASEDIR=$HOME/git + +C_bg_green=$(echo -e "\e[42m") +C_bg_magenta=$(echo -e "\e[45m") +C_bg_default=$(echo -e "\e[49m") +C_bg_lblue=$(echo -e "\e[104m") + +_getent() { + local db=$1 + local key=$2 + getent $db $key | cut -d ':' -f 1 +} + +_list_repo_dirs() { + find "$1" -maxdepth 6 -type d -path "/home/*/git/*" -not -path '*.git/*' -name '*.git' 2>/dev/null +} + +do_list() { + if [ -n "$1" ]; then + local root_path=$(readlink -f "$1") + else + local root_path=/home + fi + echo -n "Working.. listing repositories under $root_path" + for repo_path in $(_list_repo_dirs $root_path | sort); do + echo -ne "\r" # to remove working + eval $(stat -f 'local repo_path_uid=%u repo_path_gid=%g repo_path_mode=%Lp' "$repo_path") + if [ "$repo_path_uid" != "$UID" ]; then + # so there must be a matching gid + local pass=false + for user_gid in $(id -G); do + if [ "$repo_path_gid" == "$user_gid" ]; then + pass=true + fi + done + if ! $pass; then + continue # skip that repo since uid and gids don't match + fi + + fi + + # and is it marked as shared ? + local repo_git_shared=$(GIT_DIR="$repo_path" git config --get core.sharedrepository) + + local repo_name="~${repo_path#/home/}" + local shortdesc=$(cut -c 1-40 < "$repo_path/description") + if [ $(( 0$repo_path_mode & 07 )) -gt 0 ]; then # public + local shared="($C_bg_magenta$repo_path_mode$C_bg_default git.shared=${repo_git_shared} gid=$repo_path_gid/$(_getent group $repo_path_gid))" + elif [ $(( 0$repo_path_mode & 070 )) -gt 0 ]; then # shared + local shared="($C_bg_lblue$repo_path_mode$C_bg_default git.shared=${repo_git_shared} gid=$repo_path_gid/$(_getent group $repo_path_gid))" + else + local shared="($C_bg_green$repo_path_mode$C_bg_default)" + fi + + printf "%-60s %s (%s)\n" "$repo_name" "$shared" "$shortdesc" + done +} + +_create_repo() { + local label=$1 + local shared=$2 + local group=$3 + local is_public=$4 + + read -p 'New repository name.git: ' + local repo_name=$REPLY + + if ! `expr "$repo_name" : '.*\.git' >/dev/null`; then + echo "Repository name must end with .git" + return 1 + fi + + local repo_dir=$BASEDIR/${repo_name} + + test \! -e "$repo_dir" || { echo "Repo $repo_dir already exist"; exit 1; } + + read -p 'Set Description: ' + local repo_desc=$REPLY + + read -p "Create $label in $repo_dir Ok? (y/N)" + test "$REPLY" == "y" || exit 1 + + mkdir -p "$repo_dir" + git init --bare --shared=$shared "$repo_dir" + chgrp -R "$group" "$repo_dir" + echo "$repo_desc" > "$repo_dir/description" + + if $is_public; then + touch "$repo_dir/PUBLIC" + echo "created $repo_dir/PUBLIC to expose via cgit" + fi + + echo "done creating $label in $repo_dir" + echo "use 'git repo show $repo_dir' for details" + return 0 +} + +do_create_public() { + _create_repo "public repository" "0664" "share" true + return $? +} + +do_create_shared() { + _create_repo "group-writeable repository" "0660" "share" false + return $? +} + +do_create_private() { + _create_repo "private repository" "0600" "$USER" false + return $? +} + +do_show() { + for repo_path in $*; do + if ! [ -f "$repo_path/HEAD" ]; then + echo "Not a git repository: $repo_path" + continue + fi + + echo "========== Actions on: $repo_path" + local repo_file_mode=$(stat -f %Lp "$repo_path") + local repo_file_uid=$(stat -f %u "$repo_path") + local repo_file_user=$(_getent passwd $repo_file_uid) + local repo_file_gid=$(stat -f %g "$repo_path") + local repo_file_group=$(_getent group $repo_file_gid) + + echo " ✔ Permissions mode ${repo_file_mode} (uid=${repo_file_uid}/${repo_file_user} gid=${repo_file_gid}/${repo_file_group})" + echo " ⚡ To clone from remote execute: " + echo " git clone 'ssh://localnet.cc/~${repo_path##/home/}'" + if [ $(( 0$repo_file_mode & 07 )) -gt 0 ]; then + echo " git clone 'http://localnet.cc/cgit/cgit.cgi/${repo_path##/home/}' (read-only)" + fi + echo " ☛ To update description execute: $EDITOR $repo_path/description" + echo " ☛ For limited ssh-access with current user configure ~/.ssh/authorized_keys with:" + echo " command=\"git shell -c \\\"\$SSH_ORIGINAL_COMMAND\\\"\",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAAB3....." + done +} + +do_mirror() { + local root_path=$(readlink -f "$1") + for repo_path in $(_list_repo_dirs $root_path); do + local mirror_url=$(sed -n -e 's/^Mirror for \(https.*\)$/\1/p' < $repo_path/description) + #todo + done +} + +do_make_public() { + local repo_path=$1 + test -f "$repo_path/HEAD" || { echo "$repo_path is not a git repository"; exit 1; } + set -x + git init -q --bare --shared=0664 "$repo_path" + find "$repo_path" -type d -exec chown $USER:share \{\} \; + find "$repo_path" -type d -exec chmod 0775 \{\} \; + find "$repo_path" -type f -exec chmod 0664 \{\} \; + touch "$repo_path/PUBLIC" + set +x +} + +do_make_shared() { + local repo_path=$1 + test -f "$repo_path/HEAD" || { echo "$repo_path is not a git repository"; exit 1; } + set -x + git init -q --bare --shared=0660 "$repo_path" + find "$repo_path" -type d -exec chown $USER:share \{\} \; + find "$repo_path" -type d -exec chmod 0770 \{\} \; + find "$repo_path" -type f -exec chmod 0660 \{\} \; + rm -f "$repo_path/PUBLIC" + set +x +} + +do_make_private() { + local repo_path=$1 + test -f "$repo_path/HEAD" || { echo "$repo_path is not a git repository"; exit 1; } + set -x + git init -q --bare --shared=0600 "$repo_path" + find "$repo_path" -type d -exec chown $USER:$USER \{\} \; + find "$repo_path" -type d -exec chmod 0700 \{\} \; + find "$repo_path" -type f -exec chmod 0600 \{\} \; + rm -f "$repo_path/PUBLIC" + set +x +} + +case "$1" in + list) do_list "$2" ;; + create-public) do_create_public ;; + create-shared) do_create_shared ;; + create-private) do_create_private ;; + make-public) do_make_public "$2" ;; + make-shared) do_make_shared "$2" ;; + make-private) do_make_private "$2" ;; + show) + shift + do_show $* + ;; + mirror) do_mirror "$2" ;; + *) + cat <<HERE +Unknown subcommand: '$1' + +Subcommands of git repo: + list [<dir>] List infos (optional: only below <dir>) + show <dir...> Show Commands for repo <dir> + mirror <dir> Mirror git repositories under <dir> by looking + for 'Mirror for https://..' in description" + create-public Create new repository that is + - Read/Write by Owner + - Read/Write by 'share' group. + - Read-Only through www via cgit + create-shared Create new repository that is + - Read/Write by Owner + - Read/Write by 'share' group. + create-private Create new repository that is + - Read/Write by Owner only + make-public <dir> Change permissions to public + make-shared <dir> Change permissions to shared + make-private <dir> Change permissions to private +HERE + ;; +esac + |