All checks were successful
CI / Packaging - Kali Linux (pull_request) Successful in 5m38s
CI / Packaging - OpenSUSE Tumbleweed (pull_request) Successful in 4m52s
CI / Packaging test (pull_request) Successful in 0s
CI / Packaging - Kali Linux (push) Successful in 5m15s
CI / Packaging - OpenSUSE Tumbleweed (push) Successful in 4m57s
CI / Packaging test (push) Successful in 0s
projects_dir is searched by looking for a directory named .git up the direcctory lineage. That does't work for worktrees, which are regular files pointing back to worktree git dir within the the real git directory. Broaden the check from "test -d .git" to "test -e .git". Signed-off-by: Jan Lindemann <jan@janware.com>
361 lines
8 KiB
Shell
361 lines
8 KiB
Shell
#!/bin/sh
|
|
|
|
# ----------------- Helper functions
|
|
|
|
log()
|
|
{
|
|
local prefix="| "
|
|
[ "$porcelain" = 0 ] || prefix=""
|
|
if [ "$1" ]; then
|
|
echo "$prefix$*" >&2
|
|
else
|
|
sed "s/^/$prefix/" >&2
|
|
fi
|
|
}
|
|
|
|
err()
|
|
{
|
|
log "$@"
|
|
}
|
|
|
|
fatal()
|
|
{
|
|
err "$@"
|
|
exit 1
|
|
}
|
|
|
|
counter()
|
|
{
|
|
[ "$n_projects" != 1 ] || return
|
|
echo " [$cur/$n_projects]"
|
|
}
|
|
|
|
marker()
|
|
{
|
|
log "# -------------$(counter) $*"
|
|
}
|
|
|
|
fat_marker()
|
|
{
|
|
if [ "$n_projects" = 1 ]; then
|
|
marker "$@"
|
|
return
|
|
fi
|
|
log "# ====================================================$(counter) $*"
|
|
}
|
|
|
|
log_start_stop()
|
|
{
|
|
[ "$porcelain" = 1 ] && return
|
|
local b e
|
|
if [ "$1" = start ]; then
|
|
b=","
|
|
e=">"
|
|
else
|
|
b="\`"
|
|
e="<"
|
|
fi
|
|
shift
|
|
echo "$b----------------------------------------------- Running $cmdline --$e--" >&2
|
|
}
|
|
|
|
goodbye()
|
|
{
|
|
log_start_stop stop
|
|
}
|
|
|
|
#
|
|
# Guess and set the following global variables:
|
|
#
|
|
# - projects_dir: The directory all projects are contained in
|
|
# - project_dirs: A space separated list of all directories containing a project
|
|
# - n_projects: the number of projects
|
|
#
|
|
set_global_variables()
|
|
{
|
|
[ "$projects_dir" ] || {
|
|
projects_dir=`pwd`
|
|
# If we're in a toplevel directory, suppose projects_dir == project_dirs,
|
|
# i.e. we only want to target this Git repo
|
|
if [ ! -e .git ]; then
|
|
while [ ! -r Makefile ] || ! grep -q 'include $(JWBDIR)/make/projects-dir\.mk\|some-random-string-to-id-this-makefile' Makefile; do
|
|
[ "$projects_dir" = / ] && fatal "Failed to find projects directory"
|
|
projects_dir=`dirname $projects_dir`
|
|
done
|
|
fi
|
|
}
|
|
|
|
[ "$project_dirs" ] || {
|
|
if [ "$PGIT_SH_PROJECTS" ]; then
|
|
project_dirs="$PGIT_SH_PROJECTS"
|
|
else
|
|
project_dirs=`(cd $projects_dir; ls -d */.git 2>/dev/null | sed 's%/.git%%')`
|
|
fi
|
|
}
|
|
n_projects=`echo $project_dirs | wc -w`
|
|
}
|
|
|
|
run_git()
|
|
{
|
|
marker git "$@"
|
|
if [ "$porcelain" = 1 ]; then
|
|
git "$@"
|
|
else
|
|
git "$@" 2>&1 | log
|
|
fi
|
|
}
|
|
|
|
# ----------------- Commands
|
|
|
|
cmd_run()
|
|
(
|
|
local d
|
|
local cmd=$1
|
|
shift
|
|
|
|
set_global_variables
|
|
cd $projects_dir
|
|
|
|
if [ "$PGIT_KEEP_GOING" != y ]; then set -e; fi
|
|
for d in $project_dirs; do
|
|
cur=`expr $cur + 1`
|
|
run_git -C $d $cmd "$@"
|
|
done
|
|
)
|
|
|
|
cmd_exec()
|
|
(
|
|
local d
|
|
|
|
set_global_variables
|
|
cd $projects_dir
|
|
|
|
if [ "$PGIT_KEEP_GOING" != y ]; then set -e; fi
|
|
for d in $project_dirs; do
|
|
cur=`expr $cur + 1`
|
|
fat_marker $d: "$@"
|
|
(
|
|
cd $d
|
|
"$@"
|
|
)
|
|
done
|
|
)
|
|
|
|
cmd_commit()
|
|
(
|
|
local d do_cvs
|
|
local ignore="$PGIT_IGNORE"
|
|
|
|
if [ "$1" = --cvs ]; then
|
|
do_cvs=true
|
|
shift
|
|
fi
|
|
|
|
set_global_variables
|
|
cd $projects_dir
|
|
|
|
if [ "$PGIT_KEEP_GOING" != y ]; then set -e; fi
|
|
for d in $project_dirs; do
|
|
cur=`expr $cur + 1`
|
|
if echo $ignore | grep -q "\b$d\b"; then
|
|
marker "$d is in PGIT_IGNORE, not committing anything"
|
|
continue
|
|
fi
|
|
if run_git -C $d diff-index --quiet HEAD --; then
|
|
log "Nothing to commit"
|
|
continue
|
|
fi
|
|
run_git -C $d commit "$@"
|
|
done
|
|
)
|
|
|
|
cmd_get()
|
|
(
|
|
run_clone() {
|
|
local url="$1"
|
|
local p="$2"
|
|
run_git $GIT_GLOBAL_OPTS clone "$url" "$p"
|
|
if [[ "$GIT_GLOBAL_OPTS" =~ proactiveAuth ]]; then
|
|
run_git -C $p config set http.proactiveAuth basic
|
|
fi
|
|
}
|
|
|
|
project_current_revision() {
|
|
local dir="$1"
|
|
if [ -d $dir ]; then
|
|
git -C $dir rev-parse --abbrev-ref HEAD
|
|
else
|
|
echo master
|
|
fi
|
|
}
|
|
|
|
local remote_base="$global_remote_base"
|
|
local remote_subpath="$global_remote_subpath"
|
|
local whoami="$(id -un)"
|
|
set_global_variables
|
|
cd $projects_dir
|
|
local projects="$PGIT_SH_PROJECTS"
|
|
local ignore="$PGIT_IGNORE"
|
|
local this_dir="${0%/*}"
|
|
local jw_pkg="/usr/bin/python3 $this_dir/jw-pkg.py"
|
|
local create_remote_user_repos=false
|
|
local long_opts="create-remote-user-repos"
|
|
local refspec_arg refspec=()
|
|
long_opts="$long_opts,refspec:"
|
|
|
|
local opts
|
|
opts=$(getopt -o C --long "$long_opts" -n get -- "$@") || fatal "Failed to parse options $*"
|
|
eval set -- "$opts"
|
|
while [ "$1" != -- ]; do
|
|
case "$1" in
|
|
-C | --create-remote-user-repos)
|
|
create_remote_user_repos=true
|
|
;;
|
|
--refspec)
|
|
refspec_arg="$2"
|
|
refspec=(${refspec_arg//:/ })
|
|
shift
|
|
;;
|
|
*)
|
|
fatal "Unknown option $1"
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
local git_srv_admin="$SSH $remote_user@devgit.janware.com /opt/jw-pkg/bin/git-srv-admin.sh"
|
|
local from_user="${refspec[0]}"
|
|
[ "$from_user" ] || from_user=$whoami
|
|
|
|
if [ -z "$projects" ]; then
|
|
projects=`$jw_pkg --interactive false projects list-repos --from-owner $from_user $remote_base`
|
|
[ "$?" != 0 ] && fatal "Failed to enumerate repositories"
|
|
fi
|
|
|
|
if [ "$remote_user" ]; then
|
|
[ "${remote_base/@/}" = "${remote_base}" ] || fatal "Specified both --login $remote_user and user in URL $remote_base"
|
|
remote_base=$(echo $remote_base | sed "s|://|://$remote_user@|")
|
|
fi
|
|
|
|
n_projects=`echo $projects | wc -w`
|
|
if [ "$PGIT_KEEP_GOING" != y ]; then set -e; fi
|
|
local project_dir
|
|
for project_dir in $projects; do
|
|
local project_name=$(readlink -f $project_dir | xargs basename)
|
|
echo $ignore | grep -q "\b$project_name\b" && continue
|
|
cur=`expr $cur + 1`
|
|
local pull_url=$remote_base/$from_user$remote_subpath/$project_name
|
|
local push_url=$remote_base/$remote_user$remote_subpath/$project_name
|
|
local cur_ref=$(project_current_revision $project_dir)
|
|
local remote_name="jw-$from_user"
|
|
local from_ref="${refspec[1]}"
|
|
local to_ref="${refspec[2]}"
|
|
[ "$from_ref" ] || from_ref=master
|
|
[ "$from_user" = "$remote_user" ] && remote_name="origin"
|
|
[ "$to_ref" = "current-branch" ] && to_ref=$cur_ref
|
|
[ "$from_ref" = "current-branch" ] && from_ref=$cur_ref
|
|
local log_refspec="$from_user:$from_ref"
|
|
[ "$to_ref" ] && log_refspec="$log_refspec -> $to_ref"
|
|
[ "$refspec_arg" -a "$refspec_arg" != "$from_user:$from_ref:$to_ref" ] && log_refspec="$log_refspec ($refspec_arg)"
|
|
fat_marker "Getting project $project_name from $log_refspec"
|
|
if [ -d $project_dir ]; then
|
|
git -C $project_dir remote | grep -q "^$remote_name$" || {
|
|
run_git -C $project_dir remote add $remote_name $pull_url
|
|
[ "$from_user" = "$remote_user" ] || run_git -C $project_dir remote set-url --push $remote_name no_push
|
|
}
|
|
run_git -C $project_dir fetch --prune --recurse-submodules=on-demand $remote_name $from_ref
|
|
run_git -C $project_dir submodule foreach --recursive 'git fetch --tags -f origin'
|
|
if [ "$to_ref" ]; then
|
|
run_git -C $project_dir rebase --autostash $remote_name/$from_ref $to_ref
|
|
run_git -C $project_dir merge --ff-only $remote_name/$from_ref $to_ref
|
|
fi
|
|
else
|
|
run_clone $remote_base/$from_user$remote_subpath/$project_name $project_dir
|
|
if [ "$from_user" != "$remote_user" ]; then
|
|
run_git -C $project_dir remote rename origin $remote_name || fatal "Failed to rename remote in $project_dir"
|
|
run_git -C $project_dir remote set-url --push $remote_name no_push
|
|
if [ $create_remote_user_repos = true ]; then
|
|
$git_srv_admin -u $remote_user -j create-personal-project $project_name
|
|
run_git -C $project_dir remote add origin $push_url
|
|
run_git -C $project_dir push --recurse-submodules=on-demand origin master
|
|
$git_srv_admin -u $remote_user -j update-descriptions $project_name
|
|
run_git -C $project_dir branch --set-upstream-to origin/master master
|
|
fi
|
|
fi
|
|
fi
|
|
run_git -C $project_dir submodule update --init --recursive || fatal "git submodule update failed in $project_dir"
|
|
done
|
|
)
|
|
|
|
cmd_diff()
|
|
(
|
|
local d
|
|
set_global_variables
|
|
cd $projects_dir
|
|
for d in $project_dirs; do
|
|
cur=`expr $cur + 1`
|
|
# marker $d
|
|
run_git -C $d diff --src-prefix=$d/ --dst-prefix=$d/ "$@"
|
|
done
|
|
)
|
|
|
|
set -o pipefail
|
|
|
|
myname=${0##*/}
|
|
cmdline="$myname $*"
|
|
porcelain=0
|
|
|
|
log_start_stop start
|
|
log "GIT_SSH=$GIT_SSH"
|
|
log "JW_PKG_SSH_EXTRA_OPTS=$JW_PKG_SSH_EXTRA_OPTS"
|
|
|
|
cur=0
|
|
SSH=ssh
|
|
[ "$GIT_SSH" ] && SSH=$GIT_SSH
|
|
global_remote_base="ssh://devgit.janware.com"
|
|
|
|
while [ "${1:0:1}" = - ]; do
|
|
case "$1" in
|
|
'--remote-base')
|
|
global_remote_base="$2"
|
|
shift
|
|
;;
|
|
'--porcelain')
|
|
porcelain=1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# Only janware.com ssh git supports subdirectories below users
|
|
if [[ "$global_remote_base" =~ devgit.janware.com ]]; then
|
|
global_remote_subpath="/proj"
|
|
else
|
|
global_remote_subpath=""
|
|
fi
|
|
|
|
cmd=$1
|
|
shift
|
|
|
|
remote_user=$(id -un)
|
|
while [ "${1:0:1}" = - ]; do
|
|
case $1 in
|
|
'--login')
|
|
remote_user="$2"
|
|
shift
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
case $cmd in
|
|
get|diff|commit|exec)
|
|
cmd_${cmd//-/_} "$@"
|
|
;;
|
|
*)
|
|
cmd_run $cmd "$@"
|
|
;;
|
|
esac
|