UpdateController/git_helpers

265 lines
8.1 KiB
Bash
Executable File

#!/bin/bash
# set -x
# if [ ${git_helpers_sourced:-1} = "1" ]; then
# readonly git_helpers_sourced=${BASH_SOURCE[0]}
#else
# return 0
#fi
# source ./log_helpers
readonly GIT_SSL_NO_VERIFY=true
readonly repository_already_up_to_date=2
#
exec_git_command () {
local func="${FUNCNAME[0]}"
log_debug "$func:${LINENO} exec-ing [$*]"
exec {fd}< <($@)
local ps_pid=$! # remember pid of process substitution
local git_result=""
while read t <&$fd; do
if ! [ -z "$t" ]; then
git_result="${git_result}$t"
fi
done
exec {fd}>&- # close fd (i.e. process substitution)
wait $ps_pid # wait for the subshell to finish
git_result=$(printf "$git_result" | tr '\n' ' ')
printf "%s\n" $git_result
}
#
latest_commit () {
local func="${FUNCNAME[0]}"
# git reflog -> 46c5896 HEAD@{0}: commit: Made update_helpers.sh executable
local c=$(git reflog | grep "HEAD@{0}" | cut -d" " -f1)
if ! [ -z "$c" ]; then
if grep -qE "^[[:xdigit:]]{6,}$" <<< $c; then
log_debug "$func:${LINENO} commit -> $c"
printf "%s\n" $c
else
log_crit "$func:${LINENO} wrong format for commit c=$c"
fi
else
log_crit "$func:${LINENO} 'git reflog' result empty"
fi
}
# fallback if something went wrong: revert to last valid commit
revert_to_commit_before_pull () {
local func="${FUNCNAME[0]}"
if ! [ -z "$commit_before_pull" ]; then
if grep -qE "^[[:xdigit:]]{6,}$" <<< $commit_before_pull; then
`git reset --hard "$commit_before_pull"`
if [ $? -eq 0 ]; then
log_info "$func: git reset --hard $commit_before_pull"
return 0
fi
log_crit "$func: 'git reset --hard $commit_before_pull' failed!"
fi
log_crit "$func: wrong format for commit_before_pull"
fi
log_crit "$func: empty commit_before_pull"
return 1
}
# revert_to_commit_before_pull
# clone the customer repository in ./UpdateController/workspace.
# this is done only once.
clone_customer_repository () {
local func="${FUNCNAME[0]}"
current_dir=${PWD##*/}
current_dir="./${current_dir:-/}"
if [ "$current_dir" = "./UpdateController" ]; then
if ! [[ -d ./workspace ]]; then
{ mkdir -p ./workspace; }
fi
# check if the directory is empty. If so, clone the
# customer repository
if ! find ./workspace -mindepth 1 -maxdepth 1 | read; then
log_debug "$func:${LINENO} cloning ${1} ..."
if { cd ./workspace ; }; then
$(exec_git_command git clone "$1")
if [ $? -eq 0 ]; then
log_debug "$func:${LINENO} cloning ${1} done"
cd - ; return 0
fi
cd -
fi
else
# the directory is not empty, so we assume the customer-repository
# has been cloned alread
if ! [[ -d ./workspace/$customer_id ]]; then
local m="wrong repository: $(ls -d './workspace/*')"
log_fatal "$func:${LINENO} $m"
else
return 0
fi
fi
fi
return 1
}
# clone_customer_repository ->
# https://git.mimbach49.de/GerhardHoffmann/customer_281.git
cd_customer_repository () {
# has to be called in ./UpdateController
local func="${FUNCNAME[0]}"
current_dir=${PWD##*/}
current_dir="./${current_dir:-/}"
if [ "$current_dir" = "./UpdateController" ]; then
repository_dir="./workspace/${customer_id}"
if ! [[ -d "$repository_dir" ]]; then
log_crit "$func:${LINENO}: $repository_dir does not exist!"
return 1
fi
if ! { cd $repository_dir; } ; then
log_crit "$func:${LINENO}: cannot change to $repository_dir!"
return 1
fi
log_debug "$func:${LINENO}: cd to $repository_dir!"
return 0
fi
return 1
}
cd_home () {
if cd - &>/dev/null ; then
return 0
fi
return 1
}
pull_customer_repository () {
# has to be called in ./UpdateController
local func="${FUNCNAME[0]}"
if ! cd_customer_repository ; then
return 1
fi
local commit_before_pull=$(latest_commit)
if [ -z $commit_before_pull ]; then
cd_home ; return 1
fi
log_debug "$func:${LINENO}: commit_before_pull=$commit_before_pull"
local git_result=$(exec_git_command 'git pull')
if [ -z "$git_result" ]; then
log_warn "$func:${LINENO}: git result empty" ; cd_home;
return 1
fi
# see 'man -Pless\ +/parameter/pattern/string/bash'
git_result=${git_result//[$'\r\n\t']/ }
log_debug "$func:${LINENO} git-pull-result=${git_result}"
if grep -qE "^Already\s+\up\s+\to\s+date.*$" <<< $git_result; then
log_warn "$func:${LINENO}: repository $PWD already up to date."
read $1 <<< 'yes'
cd_home ; return 1
fi
local commit_after_pull=$(latest_commit)
if [ -z $commit_after_pull ]; then
cd_home ; return 1
fi
log_debug "$func:${LINENO}: commit_after_pull=$commit_after_pull"
# Note: # 'git pull' is a 'git fetch' followed by a 'git merge'.
# Here's the fetch portion:
#
# remote: Counting objects: 11, done.
# remote: Compressing objects: 100% (5/5), done.
# remote: Total 7 (delta 2), reused 0 (delta 0)
#
# At this point, you've told the remote what you want.
# It finds all the objects it needs to give you,
# compresses them for faster transfer over the network,
# and then reports what it's sending you.
#
# Unpacking objects: 100% (7/7), done.
#
# You receive the pack (set of compressed objects) and unpack it.
#
# From ssh://my.remote.host.com/~/git/myproject
# * branch master -> FETCH_HEAD
# You've fetched the branch 'master' from the given remote;
# the ref FETCH_HEAD now points to it.
# Now we move on to the merge - precisely, git will merge
# FETCH_HEAD (the remote's master branch) into your current branch
# (presumably master).
#
#######################################################################
# here starts "message"
#
# Updating 9d447d2..f74fb21
# Fast forward
#
# It turns out that you haven't diverged from the remote's master branch,
# so the merge is a fast-forward (a trivial merge where it simply moves
# you forward in the history).
#
# Git notes the original position of your master branch (9d447d2)
# and the new position (f74fb21) it's been fast-forwarded to.
# If you had diverged from the remote's master branch,
# you'd see the output of a recursive merge here - Merge made
# by recursive, possibly along with some Auto-merged <file>
# and (oh no!) merge conflicts!
#
# szeged/1/1/etc/psa_config/device.conf | 13 +++++++------
# szeged/update.conf | 2 +-
# 2 files changed, 8 insertions(+), 7 deletions(-)
#
# Finally, it shows you the diffstat between the original and post-merge
# position of your master branch;
# this is basically what you'd get from
#
# git diff --stat master@{1} master.
#
update_commit="${commit_before_pull}..${commit_after_pull}"
if ! grep -qE ".*Updating\s+${update_commit}.*?" <<< $git_result; then
log_crit "$func:${LINENO}: no $update_commit in [ $git_result ]"
cd_home ; return 1
fi
cd_home ; return 0
}
# pull_customer_repository customer_281
changed_file_names () {
local func="${FUNCNAME[0]}"
if cd_customer_repository ; then
local git_res=$(exec_git_command 'git diff --stat master@{1} master')
git_res=${git_res//[$'\r\n\t']/ }
log_debug "$func:${LINENO}: git_res=$git_res"
local file_names=""
for f in 'update.conf' 'opkg_commands' ; do
if grep -qE ".*${f}.*?" <<< $git_res; then
file_names="$f $file_names"
fi
done
cd_home ; printf "$file_names"
else
log_crit "$func:${LINENO}: cannot cd to $customer_repository "\
"while in $PWD"
fi
}