#!/bin/bash
# vim: sw=4:sts=4:et
fetch_cache()
{
local CACHE_URL=$1
local CACHE_FILE=$2
local EXPIRE=$3
if [[ $(find "$CACHE_FILE" -mtime -${EXPIRE:-7} -print 2>/dev/null) \
&& -s "$CACHE_FILE" ]]; then
echo $CACHE_FILE
return
fi
curl "$CACHE_URL" -o "$CACHE_FILE" >/dev/null 2>&1 && echo $CACHE_FILE
}
fetch_branches()
{
local CACHED_BRANCHES="/tmp/$USER-branches.conf"
local URL="https://kerncvs.suse.de/branches.conf"
branches=$CACHED_BRANCHES
fetch_cache $URL $CACHED_BRANCHES
}
fetch_cve2bugzilla()
{
local CACHED_CVE2BSC="/tmp/$USER-cve2bugzilla"
local URL="https://gitlab.suse.de/security/cve-database/-/raw/master/data/cve2bugzilla"
fetch_cache $URL $CACHED_CVE2BSC 1
}
cve2bugzilla()
{
local CVE2BUGZILLA=$(fetch_cve2bugzilla)
local CVE=$1
local NR_TO_REPORT=1
# The first bsc should be the actual report others are product specific (e.g. LP)
for bsc in $(grep $CVE $CVE2BUGZILLA | cut -d: -f2 | head -n $NR_TO_REPORT)
do
echo -n "bsc#$bsc"
done
}
fetch_cve2cvss()
{
local CACHED_CVE2CVSS="/tmp/$USER-cve2cvss"
local URL="http://ftp.suse.com/pub/projects/security/yaml/suse-cvss-scores.yaml"
fetch_cache $URL $CACHED_CVE2CVSS 1
}
cve2cvss()
{
local CVE2CVSS=$(fetch_cve2cvss)
local CVE=$1
local cvss="$(grep $CVE -A3 $CVE2CVSS | grep score:)"
echo ${cvss##*:}
}
current_branch()
{
git branch --show-current
}
print_merge_branches()
{
local branches_conf="$1"
local branch="$2"
local merge_branch=
[ -z "$branches_conf" ] && fail "megre_branches: No branches_conf provided"
[ -z "$branch" ] && fail "merge_branches: No branch provided"
for word in $(grep -w "^$branch:" "$branches_conf") ; do
if [ "${word#merge:}" != "$word" ] ; then
merge_branch="${word#merge:}"
merge_branch="${merge_branch#-}"
[ -z "$merge_branch" ] && fail "print_merge_branges: non supported syntax"
echo "$merge_branch"
fi
done
}
for_each_build_branch()
{
local grep_ignore_cve="|cve"
while [ -n "$1" -a "o${1%%-*}" == "o" ] ; do
case "$1" in
-c)
# Do not ignore cve branches
grep_ignore_cve=
;;
*)
fail "for_each_build_branch: Unknown parameter: $1"
;;
esac
shift
done
local branches_conf="$1"
local fn="$2"
shift 2
local args="$@"
grep -w build "$branches_conf" | grep -v -E "^(master|vanilla|linux-next$grep_ignore_cve)" | \
while read line ; do
line=${line%%\#*}
branch=${line%%:*}
# empty line or comment
if [ -z "$branch" ] ; then
continue
fi
$fn $branch $args || break
done
}
fail()
{
echo $* >&2
exit 1
}
branch_base_ver()
{
local branch="origin/$1"
git show-ref --verify --quiet "refs/remotes/${branch}" || fail "$branch invalid branch"
local base_ver="v$(git grep SRCVERSION $branch -- rpm/config.sh | sed 's@.*=@@')"
echo $base_ver
}
sha_get_upstream_git_fixes()
{
local sha=$1
local upstream_git=${2:-$LINUX_GIT}
[ -z "$sha" ] && fail "No commit provided"
[ -z "$upstream_git" ] && fail "No upstream git tree"
git --git-dir="$upstream_git/.git" show $sha | grep -i "^[[:space:]]*fixes:" | awk '{print $2}'
}
sha_merged_in_upstream_tag()
{
local sha=$1
local base=$2
local upstream_git=${3:-$LINUX_GIT}
[ -z "$sha" ] && fail "sha_merged_in_upstream_tag: No sha provided"
[ -z "$base" ] && fail "sha_merged_in_upstream_tag: No base provided"
[ -z "$upstream_git" ] && fail "sha_merged_in_upstream_tag: No upstream git tree"
git --git-dir="$LINUX_GIT/.git" merge-base --is-ancestor "$sha" "$base"
}
sha_in_upstream()
{
local sha=$1
local upstream_git=${3:-$LINUX_GIT}
[ -z "$sha" ] && fail "sha_in_upstream: No sha provided"
[ -z "$upstream_git" ] && fail "sha_in_upstream: No upstream git tree"
sha_merged_in_upstream_tag $sha origin/HEAD $upstream_git 2>/dev/null
}
sha_has_git_fixes()
{
local sha="$1"
local base="$2"
local upstream_git=${3:-$LINUX_GIT}
[ -z "$sha" ] && fail "sha_affected_by_git_fixes: No sha provided"
[ -z "$base" ] && fail "sha_affected_by_git_fixes: No tag provided"
[ -z "$upstream_git" ] && fail "sha_affected_by_git_fixes: No upstream_git provided"
# Check git fixes when the bug was introduced
local git_fixes="$(sha_get_upstream_git_fixes $sha)"
test -n "$git_fixes"
}
affected_by_git_fixes()
{
local branch="$1"
local base="$2"
shift 2
local git_fixes="$@"
[ -z "$branch" ] && fail "affected_by_git_fixes: No branch provided"
[ -z "$base" ] && fail "affected_by_git_fixes: No tag provided"
[ -z "$git_fixes" ] && fail "affected_by_git_fixes: No git fixes provided"
# Check git fixes when the bug was introduced
local git_fix=
local affected_by=
for git_fix in $git_fixes ; do
local needs_fix=
# Is it merged in the upstream base kernel?
if sha_merged_in_upstream_tag "$git_fix" "$base" ; then
needs_fix=1
fi
# Do we have it backported?
if sha_merged_in_suse_tree "$git_fix" "$branch" ; then
needs_fix=1
fi
if [ -n "$needs_fix" ] ; then
if [ -z "$affected_by" ] ; then
affected_by="$git_fix"
else
affected_by="$affected_by $git_fix"
fi
fi
done
if [ -n "$affected_by" ] ; then
echo "Fixes: $affected_by"
fi
}
sha_to_patch_in_branch()
{
local sha="$1"
local branch="$2"
[ -z "$sha" ] && fail "sha_to_patch_in_branch: No sha provided"
[ -z "$branch" ] && fail "sha_to_patch_in_branch: No branch provided"
branch_file=$(git --no-pager grep -l -i "^git-commit[[:space:]]*:[[:space:]]*$sha" "origin/$branch")
echo "${branch_file#origin/$branch:}"
}
sha_to_patch()
{
local sha="$1"
[ -z "$sha" ] && fail "sha_to_patch: No sha provided"
git --no-pager grep -l -i "^git-commit[[:space:]]*:[[:space:]]*$sha"
}
sha_merged_in_suse_tree()
{
local sha="$1"
local branch="$2"
[ -z "$sha" ] && fail "sha_merged_in_suse_tree: No sha provided"
[ -z "$branch" ] && fail "sha_merged_in_suse_tree: No branch provided"
local patch=$(sha_to_patch_in_branch "$sha" "$branch")
test -n "$patch"
}
references_to_patches_in_branch()
{
local branch="$1"
shift
local references="$@"
[ -z "$branch" ] && fail "references_to_patches_in_branch: No branch provided"
[ -z "$references" ] && fail "references_to_patches_in_branch: No references provided"
local pattern_prefix="^references[[:space:]]*:[[:space:]]*"
local pattern=
for ref in $references ; do
[ -n "$pattern" ] && pattern="$pattern|"
pattern="$pattern$pattern_prefix$ref"
done
branch_files=$(git --no-pager grep -l -E -i "$pattern" "origin/$branch")
for branch_file in $branch_files ; do
echo "${branch_file#origin/$branch:}"
done
}
patch_has_reference()
{
local ref="$1"
local patch="$2"
[ -z "$patch" ] && fail "No patch provided"
[ -z "$ref" ] && fail "No reference provided"
grep -q -i "^references:.*$ref" "$patch"
}
patch_has_reference_in_branch()
{
local patch="$1"
local ref="$2"
local branch="$3"
[ -z "$patch" ] && fail "patch_has_reference_in_branch: No patch provided"
[ -z "$ref" ] && fail "patch_has_reference_in_branch: No reference provided"
[ -z "$branch" ] && fail "patch_has_reference_in_branch: No branch provided"
git --no-pager grep -w -q -i "^references:.*$ref" "origin/$branch" -- "$patch"
}
sha_has_reference_in_branch()
{
local sha="$1"
local ref="$2"
local branch="$3"
local patch=
[ -z "$sha" ] && fail "sha_has_reference_in_branch: No sha provided"
[ -z "$ref" ] && fail "sha_has_reference_in_branch: No reference provided"
[ -z "$branch" ] && fail "sha_has_reference_in_branch: No branch provided"
patch=$(sha_to_patch_in_branch "$sha" "$branch")
if [ -n "$patch" ] ; then
patch_has_reference_in_branch "$patch" "$ref" "$branch"
else
# no patch, no refence needed
true
fi
}
patch_add_reference()
{
local ref=$1
local patch=$2
[ -z "$patch" ] && fail "No patch provided"
[ -z "$ref" ] && fail "No reference provided"
if ! patch_has_reference "$ref" "$patch" ; then
local references=$(grep -i "^references:" $patch | sed -e 's/^[Rr]eferences:[[:space:]]//')
references="$references $ref"
patch-tag --delete "references" "$patch"
patch-tag --add "References=$references" "$patch"
change_to_commit=1
fi
if ! patch_has_reference "$ref" "$patch" ; then
fail "Failed to add reference '$ref' into $patch"
fi
}
current_branch_state()
{
local state_line
status_line=$(git status | grep "Your branch")
[ -z "$status_line" ] && fail "Can't get status of the current branch"
if (echo "$status_line" | grep -q "up to date") ; then
echo "up to date"
elif (echo "$status_line" | grep -q "ahead") ; then
echo "ahead"
elif (echo "$status_line" | grep -q "behind.*fast-forwarded") ; then
echo "behind-ff"
elif (echo "$status_line" | grep -q "have diverged") ; then
echo "diverged"
else
echo "unknown"
fi
}
push_list_name()
{
local type=$1
[ -z "$type" ] && fail "push_list_name: called with no type"
echo "push-list.$type"
}
push_list_has_branch()
{
local type=$1
local branch=$2
local file=
[ -z "$type" ] && fail "push_list_has_branch: called with no type"
[ -z "$branch" ] && fail "push_list_has_branch: called with no branch"
file=$(push_list_name $type)
if [ -e "$file" ] ; then
grep -q "^branch\$" "$file"
else
false
fi
}
push_list_add_branch()
{
local type="$1"
local branch="$2"
local file=
[ -z "$type" ] && fail "push_list_update: called with no type"
[ -z "$branch" ] && fail "push_list_has_branch: called with no branch"
if ! $(push_list_has_branch $type $branch) ; then
file=$(push_list_name $type)
echo "$branch" >> "$file"
fi
}
queue_push()
{
local branch_state=
branch_state=$(current_branch_state)
case "$branch_state" in
"up to date")
// nope
;;
ahead)
push_list_add_branch "ready" $(current_branch)
;;
*)
push_list_add_branch "manual" $(current_branch)
;;
esac
}
push_list_msg()
{
local type="$1"
local msg="$2"
local file=
[ -z "$type" ] && fail "push_list_msg: called with no type"
[ -z "$msg" ] && fail "push_list_msg: called with no message"
file=$(push_list_name "$type")
if ! grep -q "^$msg$" "$file" ; then
echo "$msg" >> "$file"
fi
}
log_fail()
{
local msg="$1"
[ -z "$msg" ] && fail "log_failure: called with no message"
push_list_msg "failure" "$msg"
fail "$msg"
}