mirror of
https://git.FreeBSD.org/ports.git
synced 2024-11-30 01:15:52 +00:00
f916081e1c
set pipefail changes the pipeline return status from being the return status of the last command to the last non 0 exit status of any command in the pipeline. This is needed to make sure all the commands in a pipeline did actually return a non 0 status and not only the last one. PR: 250723 Exp-run by: antoine Reviewed by: bapt Approved by: bapt Differential Revision: https://reviews.freebsd.org/D27007
299 lines
7.5 KiB
Bash
299 lines
7.5 KiB
Bash
#!/bin/sh
|
|
# MAINTAINER: portmgr@FreeBSD.org
|
|
# $FreeBSD$
|
|
|
|
# This script regenerates patches. It conserves existing comments and
|
|
# file names, even if the file name does not meet any current or
|
|
# previous convention. It will keep multiple patches in the same file
|
|
# rather than splitting them into individual files.
|
|
#
|
|
# If a generated patch was not present before, it will create a file
|
|
# name where forward slashes are replaced with an underscore and
|
|
# underscores are appended by another underscore.
|
|
#
|
|
# Limitations:
|
|
# 1) If a file is modified by multiple patches, it will be regenerated
|
|
# as a single patch. That means if two multi-patch files modified
|
|
# the same source file, when regenerated, the source file's patch
|
|
# will only appear in one of patch file.
|
|
# 2) It's possible that trailing garbage at the end of a patch in a
|
|
# multipatch file might corrupt the comment (or be interpreted as
|
|
# a comment) of the following patch. (garbage in, garbage out)
|
|
#
|
|
# Reminder
|
|
# Don't forget to disable post-patch targets before regenerating patches
|
|
# if those targets modify source files (e.g. with sed). You may also
|
|
# want to disable EXTRA_PATCHES as well if that is being used.
|
|
|
|
set -o pipefail
|
|
|
|
[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_SMART_MAKEPATCH}" ] && set -x
|
|
|
|
if [ -z "${PATCHDIR}" -o -z "${PATCH_WRKSRC}" -o -z "${WRKDIR}" ]; then
|
|
echo "WRKDIR, PATCHDIR, and PATCH_WRKSRC required in environment." >&2
|
|
exit 1
|
|
fi
|
|
|
|
WORKAREA=${WRKDIR}/.makepatch-tmp
|
|
PATCHMAP=${WORKAREA}/pregen.map
|
|
COMMENTS=${WORKAREA}/comments
|
|
REGENNED=${WORKAREA}/regenerated
|
|
DESTDIR=${WORKAREA}/staged
|
|
SAVEDIR=${WORKAREA}/archived-patches
|
|
|
|
case "${STRIP_COMPONENTS}" in
|
|
[123456789]) ;;
|
|
1[0123456789]) ;;
|
|
*) STRIP_COMPONENTS=0
|
|
esac
|
|
|
|
strip_path() {
|
|
local raw_name=$1
|
|
if [ "${STRIP_COMPONENTS}" = "0" ]; then
|
|
echo ${raw_name}
|
|
else
|
|
echo ${raw_name} | awk -v sc=${STRIP_COMPONENTS} -F "/" \
|
|
'{ for (x = sc + 1; x <= NF; x++) {
|
|
slash = (x>sc+1) ? "/" : "";
|
|
printf ("%s%s", slash, $x);
|
|
}}'
|
|
fi
|
|
}
|
|
|
|
std_patch_filename() {
|
|
local sans_cwd
|
|
local raw_name
|
|
sans_cwd=$(echo $1 | sed 's|^\.\/||')
|
|
raw_name=$(strip_path ${sans_cwd})
|
|
echo "patch-$(echo ${raw_name} | sed -e 's|_|&&|g; s|/|_|g')"
|
|
}
|
|
|
|
patchdir_files_list() {
|
|
if [ -d "${PATCHDIR}" ]; then
|
|
(cd ${PATCHDIR} && \
|
|
find -s . -type f -name "patch-*" -maxdepth 1 \
|
|
2>/dev/null | sed -e 's,^\./,,; /\.orig$/d'
|
|
)
|
|
fi;
|
|
}
|
|
|
|
valid_name() {
|
|
local current_patch_name=$1
|
|
local result=$3
|
|
local first_target
|
|
local testres
|
|
local lps
|
|
first_target=$(echo $2 | sed 's|^\.\/||')
|
|
for lps in __ - + ; do
|
|
testres=patch-$(echo ${first_target} | sed -e "s|/|${lps}|g")
|
|
if [ "${testres}" = "${current_patch_name}" ]; then
|
|
result=${testres}
|
|
break
|
|
fi
|
|
done
|
|
echo ${result}
|
|
}
|
|
|
|
map_existing_patches() {
|
|
mkdir -p ${WORKAREA}
|
|
: > ${PATCHMAP}
|
|
local target
|
|
local future_name
|
|
local std_target
|
|
local P
|
|
local t
|
|
for P in ${old_patch_list}; do
|
|
target=$(cd ${PATCHDIR} && \
|
|
grep "^+++ " ${P} | awk '{print $2}'
|
|
)
|
|
# For single patches, we honor previous separators, but use
|
|
# a standard patch name if the current patch name does not
|
|
# conform. However, if two or more patches are contained in
|
|
# single file, then we do *NOT* rename the file
|
|
future_name=
|
|
for t in ${target}; do
|
|
if [ -n "${future_name}" ]; then
|
|
future_name=${P}
|
|
break;
|
|
fi
|
|
std_target=$(std_patch_filename ${t})
|
|
future_name=$(valid_name ${P} ${t} ${std_target})
|
|
done
|
|
for t in ${target}; do
|
|
std_target=$(std_patch_filename ${t})
|
|
echo "${future_name} ${std_target}" >> ${PATCHMAP}
|
|
done
|
|
done
|
|
}
|
|
|
|
extract_comment_from_patch() {
|
|
local existing_patch=${PATCHDIR}/$1
|
|
local contains
|
|
local rawname
|
|
local fname
|
|
local num
|
|
contains=$(grep "^+++ " ${existing_patch} | awk '{x++; print x}')
|
|
for num in ${contains}; do
|
|
rawname=$(grep "^+++ " ${existing_patch} | \
|
|
awk -v num=${num} '{x++; if (x==num) print $2}')
|
|
fname=$(std_patch_filename $rawname)
|
|
awk -v num=${num} '
|
|
BEGIN { done=0; x=0; hunk=0; looking=(num==1) }
|
|
{
|
|
if (!done) {
|
|
if ($1 == "@@") {
|
|
split ($2,a,",");
|
|
split ($3,b,",");
|
|
hca = a[2];
|
|
hcb = a[3];
|
|
hunk = 1;
|
|
} else if (hunk) {
|
|
first=substr($1,1,1);
|
|
if (first == "-") { hca-- }
|
|
else if (first == "+") { hcb-- }
|
|
else {hca--; hcb--}
|
|
if (hca == 0 && hcb == 0) {hunk = 0}
|
|
}
|
|
if ($1 == "---") {
|
|
x++;
|
|
if (x == num) { done = 1 }
|
|
if (x + 1 == num) { looking = 1 }
|
|
} else if (!hunk && looking) {
|
|
if ($1!="diff" && $1!="index" && $1!="+++") {
|
|
print $0
|
|
}
|
|
}
|
|
}
|
|
}' ${existing_patch} > ${COMMENTS}/${fname}
|
|
done
|
|
}
|
|
|
|
extract_comments() {
|
|
mkdir -p ${COMMENTS}
|
|
rm -f ${COMMENTS}/*
|
|
local P
|
|
for P in ${old_patch_list}; do
|
|
extract_comment_from_patch ${P}
|
|
done
|
|
}
|
|
|
|
regenerate_patches() {
|
|
mkdir -p ${REGENNED}
|
|
rm -f ${REGENNED}/*
|
|
[ ! -d "${PATCH_WRKSRC}" ] && return
|
|
|
|
local F
|
|
local NEW
|
|
local OUT
|
|
local ORIG
|
|
local new_list
|
|
new_list=$(cd "${PATCH_WRKSRC}" && \
|
|
find -s . -type f -name '*.orig' 2>/dev/null)
|
|
(cd "${PATCH_WRKSRC}" && for F in ${new_list}; do
|
|
ORIG=${F#./}
|
|
NEW=${ORIG%.orig}
|
|
cmp -s ${ORIG} ${NEW} && continue
|
|
OUT=${REGENNED}/$(std_patch_filename ${NEW})
|
|
TZ=UTC diff -udp ${ORIG} ${NEW} | sed \
|
|
-e '/^---/s|\.[0-9]* +0000$| UTC|' \
|
|
-e '/^+++/s|\([[:blank:]][-0-9:.+]*\)*$||' \
|
|
> ${OUT} || true
|
|
done)
|
|
}
|
|
|
|
get_patch_name() {
|
|
awk -v name=$1 '
|
|
{ if ($2 == name)
|
|
{
|
|
if (!done) { print $1 };
|
|
done = 1;
|
|
}
|
|
}
|
|
END { if (!done) print name }' ${PATCHMAP}
|
|
}
|
|
|
|
stage_patches() {
|
|
mkdir -p ${DESTDIR}
|
|
rm -f ${DESTDIR}/*
|
|
local P
|
|
local name
|
|
local patch_list
|
|
patch_list=$(cd ${REGENNED} && find -s . -name "patch-*" 2>/dev/null)
|
|
for P in ${patch_list}; do
|
|
P=${P#./}
|
|
name=$(get_patch_name ${P})
|
|
[ -e ${COMMENTS}/${P} ] && cat ${COMMENTS}/${P} \
|
|
>> ${DESTDIR}/${name}
|
|
if [ "${P}" = "${name}" ]; then
|
|
echo "Generated ${P}"
|
|
else
|
|
echo "Generated ${P} >> ${name} (legacy)"
|
|
fi
|
|
cat ${REGENNED}/${P} >> ${DESTDIR}/${name}
|
|
done
|
|
}
|
|
|
|
compare_common_patches() {
|
|
[ -z "${old_patch_list}" ] && return
|
|
local archive_patch_list
|
|
local P
|
|
local ppatch
|
|
local ppatch_stripped
|
|
local cpatch
|
|
local cpatch_stripped
|
|
for P in ${old_patch_list}; do
|
|
if [ -e ${DESTDIR}/${P} ]; then
|
|
ppatch=${PATCHDIR}/${P}
|
|
cpatch=${DESTDIR}/${P}
|
|
ppatch_stripped=$(mktemp -t portpatch)
|
|
cpatch_stripped=$(mktemp -t portpatch)
|
|
sed -E -e '/^--- .+ UTC$/d; s/^(@@ [^@]* @@).*/\1/' \
|
|
${ppatch} > ${ppatch_stripped}
|
|
sed -E -e '/^--- .+ UTC$/d; s/^(@@ [^@]* @@).*/\1/' \
|
|
${cpatch} > ${cpatch_stripped}
|
|
# Don't replace patches with only metadata changes
|
|
if ! cmp -s ${ppatch_stripped} ${cpatch_stripped}; then
|
|
archive_patch_list="${archive_patch_list} ${P}"
|
|
else
|
|
echo "${P} only contains metadata changes; not replacing"
|
|
rm ${cpatch}
|
|
fi
|
|
rm ${ppatch_stripped}
|
|
rm ${cpatch_stripped}
|
|
fi
|
|
done
|
|
old_patch_list=${archive_patch_list}
|
|
}
|
|
|
|
conserve_old_patches() {
|
|
mkdir -p ${SAVEDIR}
|
|
rm -f ${SAVEDIR}/*
|
|
[ -z "${old_patch_list}" ] && return
|
|
|
|
local P
|
|
for P in ${old_patch_list}; do
|
|
mv ${PATCHDIR}/${P} ${SAVEDIR}/${P}
|
|
done
|
|
echo "The previous patches have been placed here:"
|
|
echo ${SAVEDIR}
|
|
}
|
|
|
|
install_regenerated_patches() {
|
|
local testdir
|
|
testdir=$(find ${DESTDIR} -empty)
|
|
if [ -z "${testdir}" ]; then
|
|
mkdir -p ${PATCHDIR}
|
|
find ${DESTDIR} -type f -exec mv {} ${PATCHDIR}/ \;
|
|
fi
|
|
}
|
|
|
|
old_patch_list=$(patchdir_files_list)
|
|
|
|
map_existing_patches
|
|
extract_comments
|
|
regenerate_patches
|
|
stage_patches
|
|
compare_common_patches
|
|
conserve_old_patches
|
|
install_regenerated_patches
|