# Copyright (C) 2018 SUSE LLC
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
# countkeys <key>
countkeys () {
local key=$1
case "${key,,*}" in
"cherry picked from commit" | "cherry picked for")
grep "^($key .*)$" | wc -l
;;
*)
grep -i "^$key: " | wc -l
;;
esac
}
# tag_get [options] <key>
# Options:
# -l, --last Do not error out if a tag is present more than once,
# return the last occurrence
tag_get () {
local result=$(getopt -o l --long last -n "${BASH_SOURCE[0]}:${FUNCNAME[0]}()" -- "$@")
local opt_last
if [ $? != 0 ]; then
echo "Error: getopt error" >&2
exit 1
fi
eval set -- "$result"
while true ; do
case "$1" in
-l|--last)
opt_last=1
;;
--)
shift
break
;;
*)
echo "Error: could not parse arguments" >&2
exit 1
;;
esac
shift
done
local key=$1
local header=$(cat)
local nb=$(countkeys "$key" <<< "$header")
if [ $nb -gt 1 -a -z "$opt_last" ]; then
echo "Error: key \"$key\" present more than once." > /dev/stderr
exit 1
fi
case "${key,,*}" in
subject)
awk --assign nb="$nb" '
BEGIN {
insubject = 0
}
tolower($1) ~ /subject:/ {
nb--
if (nb > 0) {
next
}
insubject = 1
split($0, array, FS, seps)
result = substr($0, 1 + length(seps[0]) + length(array[1]) + length(seps[1]))
next
}
insubject && /^[ \t]/ {
sub("[ \t]", " ")
result = result $0
next
}
insubject {
print result
exit
}
' <<< "$header"
;;
"cherry picked from commit" | "cherry picked for")
awk --assign nb="$nb" '
/^\('"$key"' .*\)$/ {
nb--
if (nb > 0) {
next
}
match($0, "^\\('"$key"' (.*)\\)$", a)
print a[1]
exit
}
' <<< "$header"
;;
*)
awk --assign nb="$nb" '
tolower($1) ~ /'"${key,,*}"':/ {
nb--
if (nb > 0) {
next
}
split($0, array, FS, seps)
print substr($0, 1 + length(seps[0]) + length(array[1]) + length(seps[1]))
exit
}
' <<< "$header"
;;
esac
}
# tag_remove [options] <key>
# Options:
# -l, --last Do not error out if a tag is present more than once,
# extract the last occurrence
tag_remove () {
local result=$(getopt -o l --long last -n "${BASH_SOURCE[0]}:${FUNCNAME[0]}()" -- "$@")
local opt_last
if [ $? != 0 ]; then
echo "Error: getopt error" >&2
exit 1
fi
eval set -- "$result"
while true ; do
case "$1" in
-l|--last)
opt_last=1
;;
--)
shift
break
;;
*)
echo "Error: could not parse arguments" >&2
exit 1
;;
esac
shift
done
local key=$1
local header=$(cat && echo ---)
local nb=$(countkeys "$key" <<< "$header")
if [ $nb -gt 1 -a -z "$opt_last" ]; then
echo "Error: key \"$key\" present more than once." > /dev/stderr
exit 1
fi
case "${key,,*}" in
subject)
echo -n "${header%---}" | awk --assign nb="$nb" '
BEGIN {
insubject = 0
}
tolower($1) ~ /subject:/ {
nb--
if (nb == 0) {
insubject = 1
next
}
}
insubject && /^ / {
next
}
insubject {
insubject = 0
}
{
print
}
'
;;
"cherry picked from commit" | "cherry picked for")
echo -n "${header%---}" | awk --assign nb="$nb" '
/^\('"$key"' .*\)$/ {
nb--
if (nb == 0) {
next
}
}
{
print
}
'
;;
*)
echo -n "${header%---}" | awk --assign nb="$nb" '
tolower($1) ~ /'"${key,,*}"':/ {
nb--
if (nb == 0) {
next
}
}
{
print
}
'
;;
esac
}
# tag_add [options] <key> <value>
# Options:
# -l, --last Do not error out if a tag is already present, add it
# after the last occurrence
tag_add () {
local result=$(getopt -o l --long last -n "${BASH_SOURCE[0]}:${FUNCNAME[0]}()" -- "$@")
local opt_last
if [ $? != 0 ]; then
echo "Error: getopt error" >&2
exit 1
fi
eval set -- "$result"
while true ; do
case "$1" in
-l|--last)
opt_last=1
;;
--)
shift
break
;;
*)
echo "Error: could not parse arguments" >&2
exit 1
;;
esac
shift
done
local key=$1
local value=$2
case "${key,,*}" in
from)
local header=$(cat && echo ---)
local nb=$(countkeys "$key" <<< "$header")
if [ $nb -gt 0 -a -z "$opt_last" ]; then
echo "Error: key \"$key\" already present." > /dev/stderr
exit 1
fi
echo -n "${header%---}" | awk --assign key="$key" --assign value="$value" --assign nb="$nb" '
BEGIN {
inserted = 0
}
NR == 1 && /^From [0-9a-f]+/ {
print
next
}
nb == 0 && !inserted {
print key ": " value
print
inserted = 1
next
}
tolower($1) ~ /'"${key,,*}"':/ {
nb--
}
{
print
}
'
;;
date | subject)
local header=$(cat && echo ---)
local nb=$(countkeys "$key" <<< "$header")
if [ $nb -gt 0 ]; then
echo "Error: key \"$key\" already present." > /dev/stderr
exit 1
fi
local -A prevkey=(["date"]="from" ["subject"]="date")
nb=$(countkeys "${prevkey[${key,,*}]}" <<< "$header")
echo -n "${header%---}" | awk --assign key="$key" --assign value="$value" --assign nb="$nb" '
{
print
}
tolower($1) ~ /'"${prevkey[${key,,*}]}"':/ {
nb--
if (nb == 0) {
print key ": " value
}
}
'
;;
patch-mainline | git-repo | git-commit | references)
local header=$(cat && echo ---)
local nb=$(countkeys "$key" <<< "$header")
if [ $nb -gt 0 -a -z "$opt_last" ]; then
echo "Error: key \"$key\" already present." > /dev/stderr
exit 1
fi
echo -n "${header%---}" | awk '
BEGIN {
added = 0
keys["Patch-mainline:"] = 1
keys["Git-repo:"] = 2
keys["Git-commit:"] = 3
keys["References:"] = 4
}
function keycmp(key1, key2) {
return keys[key1] - keys[key2]
}
$1 in keys && !added {
if (keycmp("'"$key"':", $1) < 0) {
print "'"$key"': '"$value"'"
print
added = 1
next
}
}
/^$/ && !added {
print "'"$key"': '"$value"'"
print
added = 1
next
}
{
print
}
'
;;
acked-by | signed-off-by)
local line="$key: $value"
local header=$(cat && echo ---)
echo -n "${header%---}" | _append_attribution "$line"
;;
"cherry picked from commit" | "cherry picked for")
local line
local header=$(cat && echo ---)
local nb=$(countkeys "$key" <<< "$header")
if [ $nb -gt 0 ]; then
echo "Error: key \"$key\" already present." > /dev/stderr
exit 1
fi
line="($key $value)"
echo -n "${header%---}" | _append_attribution "$line"
;;
*)
echo "Error: I don't know where to add a tag of type \"$key\"." > /dev/stderr
exit 1
esac
}
# get_attributions
get_attributions () {
awk '
tolower($1) ~ /^(acked|reviewed|signed-off)-by:$/ {
print
}
'
}
# get_attribution_names
get_attribution_names () {
get_attributions | awk '
{
split($0, array, FS, seps)
print substr($0, 1 + length(seps[0]) + length(array[1]) + length(seps[1]))
}
'
}
# _append_attribution <attribution line>
_append_attribution () {
local line=$1
awk --assign line="$line" '
BEGIN {
added = 0
empty_line_nb = 0
attribseen = 0
}
function print_attribution(attribseen, line, before_diffstat)
{
if (!attribseen) {
print ""
}
print line
if (!before_diffstat) {
print ""
}
added = 1
empty_line_nb = 0
}
function playback_empty_lines()
{
for (; empty_line_nb > 0; empty_line_nb--) {
print ""
}
}
/^$/ {
empty_line_nb++
next
}
tolower($1) ~ /^[^ ]+-by:$/ {
attribseen = 1
}
/^\(cherry picked from commit [[:xdigit:]]{6,})$/ {
attribseen = 1
}
/^\(cherry picked for .*)$/ {
attribseen = 1
}
!added && /^---$/ {
print_attribution(attribseen, line, 1)
}
# from quilt, patchfns
!added && /^(---|\*\*\*|Index:)[ \t][^ \t]|^diff -/ {
print_attribution(attribseen, line, 0)
}
{
playback_empty_lines()
print
}
END {
if (!added) {
print_attribution(attribseen, line, 1)
} else {
playback_empty_lines()
}
}
'
}
# insert_attributions <attribution lines>
# Add multiple attribution lines
insert_attributions () {
local attrs=$1
local header=$(cat && echo ---)
if [ "$(get_attributions <<< ${header%---})" ]; then
echo -n "${header%---}" | awk --assign attr="$1" '
tolower($1) ~ /^[^ ]+-by:$/ {
print attr
}
{
print
}
'
else
while read attribution; do
header=$(echo -n "${header%---}" | _append_attribution "$attribution" && echo ---)
done <<< "$attrs"
echo -n "${header%---}"
fi
}