scripts/updatemodules

251 lines
5.8 KiB
Plaintext
Raw Normal View History

2022-11-16 15:01:09 +01:00
#!/bin/bash
set -e
2023-02-20 18:33:44 +01:00
# config options
declare -A keep
2023-02-23 17:05:34 +01:00
REMOTE="origin"
BASE_BRANCH="main"
PACKAGE_BASE_URL=
PACKAGE_RELATIVE_URL="../../rpm"
2023-02-20 18:33:44 +01:00
# https://api.opensuse.org/public/source/openSUSE:Factory:Rings:0-Bootstrap
2023-03-02 13:43:35 +01:00
OBSPKGLIST=
2023-02-23 17:05:34 +01:00
DATE="$(date "+%s %z")"
2023-02-20 18:33:44 +01:00
keep["dummy-release"]=1
# command line only
single=
verbose=0
2023-02-23 17:05:34 +01:00
cfg_file=
###################
2023-02-20 18:33:44 +01:00
# constant needed to aid quoting
nl=$'\n'
2023-03-02 13:43:35 +01:00
declare -A obs
2023-02-20 18:33:44 +01:00
declare -A new
declare -A drop
declare -A revs
gitmodules_rev=
2022-11-16 15:01:09 +01:00
helpandquit()
{
cat <<-EOF
Usage: $0 [OPTIONS] [<module> ...]
OPTIONS:
2023-02-20 18:33:44 +01:00
--single create single commit for all changes
-h help screen
EOF
exit 0
}
2023-02-20 18:33:44 +01:00
show_status()
{
git for-each-ref 'refs/pq/*'
exit 0
}
clear_queue()
{
while read -r ref; do
git update-ref -d "$ref"
done < <(git for-each-ref 'refs/pq/*' --format '%(refname)')
exit 0
}
isnew()
{
local p="${1:?}"
[ -n "${new[$p]}" ]
}
todrop()
{
local p="${1:?}"
[ -n "${drop[$p]}" ]
}
log_info()
{
[ "$verbose" -gt 0 ] || return 0
echo "$@"
}
makedict()
{
local dict="$1"
shift
mapfile -t a < <("$@")
for k in "${a[@]}"; do
eval "$dict"["$k"]=1
done
}
getopttmp=$(getopt -o hc:v --long help,single,branch:,config:,date:,remote:,status,verbose,clear -n "${0##*/}" -- "$@")
eval set -- "$getopttmp"
2023-02-07 17:15:44 +01:00
while true ; do
case "$1" in
-h|--help) helpandquit; shift ;;
2023-02-20 18:33:44 +01:00
-v|--verbose) verbose=$((++verbose)); shift ;;
-c|--config) cfg_file="$2"; shift 2 ;;
--single) single=1; shift ;;
2023-02-23 17:05:34 +01:00
--remote) REMOTE="$2"; shift 2 ;;
--branch) BASE_BRANCH="$2"; shift 2 ;;
2023-02-20 18:33:44 +01:00
--status) show_status; exit 0 ;;
--clear) clear_queue; exit 0 ;;
2023-02-23 17:05:34 +01:00
--date) DATE="$2"; shift 2 ;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
modules=("$@")
2023-02-20 18:33:44 +01:00
2023-02-23 17:05:34 +01:00
PACKAGE_BASE_URL="$(git config --get remote."$REMOTE".url)"
# shellcheck disable=SC1090
. "${cfg_file:-.settings}"
if [ "${DATE:0:1}" = '@' ]; then
DATE="$(stat -c %Y "${DATE:1}") +0100"
2023-02-20 18:33:44 +01:00
fi
2022-11-16 15:01:09 +01:00
export GIT_AUTHOR_NAME="Auto"
export GIT_AUTHOR_EMAIL="auto@suse.de"
2023-02-23 17:05:34 +01:00
export GIT_AUTHOR_DATE="$DATE"
2022-11-16 15:01:09 +01:00
export GIT_COMMITTER_NAME="Auto"
export GIT_COMMITTER_EMAIL="auto@suse.de"
2023-02-23 17:05:34 +01:00
export GIT_COMMITTER_DATE="$DATE"
2022-11-16 15:01:09 +01:00
tmpfile=$(mktemp updatemodules.XXXXXX)
2023-02-20 18:33:44 +01:00
tmpfile2=$(mktemp updatemodules.XXXXXX)
2022-11-16 15:01:09 +01:00
cleanup()
{
2023-02-20 18:33:44 +01:00
rm -f "$tmpfile" "$tmpfile2"
2022-11-16 15:01:09 +01:00
}
trap cleanup EXIT
2023-02-07 17:15:44 +01:00
# read all submodules
while read -r m t cid p; do
2023-02-20 18:33:44 +01:00
if [ "$t" = blob ] && [ "$p" = ".gitmodules" ]; then
gitmodules_rev="$cid"
fi
[ "$t" = "commit" ] || continue
2022-11-16 15:01:09 +01:00
revs["$p"]="$cid"
2023-02-23 17:05:34 +01:00
done < <(git cat-file -p "$REMOTE/$BASE_BRANCH^{tree}")
2023-02-20 18:33:44 +01:00
2023-03-02 13:43:35 +01:00
if [ -n "$OBSPKGLIST" ]; then
2023-02-20 18:33:44 +01:00
while read -r p; do
2023-03-02 13:43:35 +01:00
obs["$p"]=1
2023-02-20 18:33:44 +01:00
[ -n "${revs[$p]}" ] || new["$p"]=1
2023-03-02 13:43:35 +01:00
done < <(curl -s -f "$OBSPKGLIST"|sed -ne 's/.*entry name="\([^":]*\).*\/>/\1/p'|sort -u | grep -v AGGR)
2023-02-20 18:33:44 +01:00
for m in "${!revs[@]}"; do
2023-03-02 13:43:35 +01:00
[ -n "${obs[$m]}" -o -n "${keep[$m]}" ] || drop["$m"]=1
2023-02-20 18:33:44 +01:00
done
fi
2022-11-16 15:01:09 +01:00
2023-02-20 18:33:44 +01:00
[ -z "${new[*]}" ] || log_info "new: ${!new[*]}"
[ -z "${drop[*]}" ] || log_info "drop: ${!drop[*]}"
if [ "${#modules[@]}" = 0 ]; then
modules=("${!revs[@]}" "${!new[@]}")
2022-11-16 15:01:09 +01:00
fi
2023-02-23 18:12:04 +01:00
# push queue
declare -A pq
makedict pq git for-each-ref 'refs/pq/*' --format '%(refname)'
2023-02-07 17:15:44 +01:00
# check remotes for updates
2022-11-16 15:01:09 +01:00
declare -A commits
2023-02-23 17:05:34 +01:00
treetext=$(git cat-file -p "$REMOTE/$BASE_BRANCH^{tree}")
git cat-file -p "$REMOTE/$BASE_BRANCH":.gitmodules > "$tmpfile"
2023-02-20 18:33:44 +01:00
cat "$tmpfile" > "$tmpfile2"
2022-11-16 15:01:09 +01:00
for m in "${modules[@]}"; do
2023-02-20 18:33:44 +01:00
if isnew "$m"; then
path="$m"
2023-02-23 17:05:34 +01:00
url="$PACKAGE_RELATIVE_URL/$m"
2023-02-20 18:33:44 +01:00
smbranch=
git config -f "$tmpfile" --add "submodule.$m.path" "$path"
git config -f "$tmpfile" --add "submodule.$m.url" "$url"
else
path="$(git config -f "$tmpfile" --get "submodule.$m.path")"
url="$(git config -f "$tmpfile" --get "submodule.$m.url")"
smbranch="$(git config -f "$tmpfile" --get "submodule.$m.branch" || :)"
fi
2023-02-07 17:15:44 +01:00
if [ -z "$path" ] || [ -z "$url" ]; then
2022-11-16 15:01:09 +01:00
echo "$m unknown" >&2
continue
fi
if [ "${url:0:3}" = '../' ]; then
2023-02-23 17:05:34 +01:00
url="$PACKAGE_BASE_URL/$url"
2022-11-16 15:01:09 +01:00
fi
2023-02-20 18:33:44 +01:00
cid=
if ! todrop "$m"; then
read -r cid _d < <(git ls-remote "$url" "${smbranch:-HEAD}")
if [ -z "$cid" ]; then
echo "$path not in pool" >&2
continue
fi
2022-11-16 15:01:09 +01:00
fi
2023-02-20 18:33:44 +01:00
2023-02-07 17:15:44 +01:00
# create a new commit for this package
2022-11-16 15:01:09 +01:00
if [ "${revs[$path]}" != "$cid" ]; then
2023-02-20 18:33:44 +01:00
log_info "Needs update: $path@${revs[$path]:-NEW} -> ${cid:-DROP}"
if isnew "$m"; then
newtreetext="$treetext${nl}160000 commit $cid $m"
elif todrop "$m"; then
newtreetext="${treetext/160000 commit ${revs[$path]} $path$nl/}"
git config -f "$tmpfile" --remove-section "submodule.$m"
2023-02-07 17:15:44 +01:00
else
2023-02-20 18:33:44 +01:00
newtreetext="${treetext/${revs[$path]} $path/$cid $path}"
fi
if isnew "$m" || todrop "$m"; then
nh=$(git hash-object -w --path .gitmodules "$tmpfile")
newtreetext="${newtreetext/$gitmodules_rev .gitmodules/$nh .gitmodules}"
fi
if [ "$single" = 1 ]; then
if isnew "$m" || todrop "$m"; then
gitmodules_rev="$nh"
fi
treetext="$newtreetext"
2023-03-02 13:43:35 +01:00
# fall through
2023-02-20 18:33:44 +01:00
else
newtree=$(echo "$newtreetext" | git mktree)
msg="Update $m"
isnew "$m" && msg="Add $m"
todrop "$m" && msg="Remove $m"
2023-02-23 17:05:34 +01:00
newcid="$(git commit-tree -p "$REMOTE/$BASE_BRANCH" -m "$msg" "$newtree")"
2023-02-07 17:15:44 +01:00
commits["$m"]="$newcid"
2023-02-20 18:33:44 +01:00
cat "$tmpfile2" > "$tmpfile"
2023-03-02 13:43:35 +01:00
continue
2023-02-07 17:15:44 +01:00
fi
2023-03-02 13:43:35 +01:00
# fall through
fi
if [ -n "${pq[refs/pq/$m]}" ]; then
2023-02-23 18:12:04 +01:00
log_info "remove pq for $m"
git update-ref -d "refs/pq/$m"
2022-11-16 15:01:09 +01:00
fi
done
2023-02-20 18:33:44 +01:00
if [ "$single" = 1 ]; then
newtree="$(echo "$treetext" | git mktree)"
2023-02-23 17:05:34 +01:00
newcid="$(git commit-tree -p "$REMOTE/$BASE_BRANCH" -m "Update all" "$newtree")"
commits["all"]="$newcid"
2023-03-02 13:43:35 +01:00
elif [ -n "${pq[refs/pq/all]}" ]; then
log_info "remove pq for single commit"
git update-ref -d "refs/pq/all"
2023-02-07 17:15:44 +01:00
fi
2022-11-16 15:01:09 +01:00
for m in "${!commits[@]}"; do
2023-02-20 18:33:44 +01:00
ref="refs/pq/$m"
if [ -n "${pq[$ref]}" ]; then
cid="$(git rev-parse "$ref")"
[ "$cid" = "${commits[$m]}" ] || echo "Warning: previous commit $cid for $m" >&2
2022-11-16 15:01:09 +01:00
fi
2023-02-20 18:33:44 +01:00
git update-ref "$ref" "${commits[$m]}"
2022-11-16 15:01:09 +01:00
done