#!/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]}" if [ "$PWD" = "$working_directory" ]; then if ! [[ -d $workspace_dir ]]; then { mkdir -p ./$workspace_dir; } fi # check if the directory is empty. If so, clone the # customer repository if ! find ./$workspace_dir -mindepth 1 -maxdepth 1 | read; then log_debug "$func:${LINENO} cloning ${1} ..." if { cd ./$workspace_dir ; }; 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_dir}/$customer_id ]]; then local m="wrong repository: $(ls -d './${workspace_dir}/*')" log_fatal "$func:${LINENO} $m" else log_debug \ "$func:${LINENO} ./${workspace_dir}/$customer_id exists" 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 # 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 }