Changeset View
Changeset View
Standalone View
Standalone View
Mk/Scripts/smart_makepatch.sh
- This file was added.
Property | Old Value | New Value |
---|---|---|
svn:eol-style | null | native \ No newline at end of property |
svn:keywords | null | FreeBSD=%H \ No newline at end of property |
svn:mime-type | null | text/plain \ No newline at end of property |
#!/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. | |||||
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 | |||||
mat: While since rP400846 **no** port should ever write any files in `WRKDIR` and everything should… | |||||
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() { | |||||
raw_name=$1 | |||||
if [ "${STRIP_COMPONENTS}" = "0" ]; then | |||||
Not Done Inline ActionsCan you mark variables with local please? bdrewery: Can you mark variables with local please? | |||||
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() { | |||||
raw_name=$(strip_path $1) | |||||
echo patch-$(echo ${raw_name} | sed -e 's|_|&&|g; s|/|_|g') | |||||
} | |||||
patchdir_files_list() { | |||||
if [ -d "${PATCHDIR}" ]; then | |||||
(cd ${PATCHDIR} && \ | |||||
find * -type f -name "patch-*" -maxdepth 0 \ | |||||
2>/dev/null | sed -e '/\.orig$/d' | |||||
) | |||||
Not Done Inline Actionsout of curiosity, are there ports with subdirectories in PATCHDIR ? (questioning the -maxdepth) mat: out of curiosity, are there ports with subdirectories in `PATCHDIR` ? (questioning the `… | |||||
fi; | |||||
} | |||||
valid_name() { | |||||
current_patch_name=$1 | |||||
first_target=$2 | |||||
result=$3 | |||||
for lps in __ - + ; do | |||||
testres=patch-$(echo ${first_target} | sed -e "s|/|${lps}|g") | |||||
if [ "${testres}" = "${current_patch_name}" ]; then | |||||
result=${testres} | |||||
fi | |||||
done | |||||
echo ${result} | |||||
} | |||||
map_existing_patches() { | |||||
mkdir -p ${WORKAREA} | |||||
: > ${PATCHMAP} | |||||
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() { | |||||
existing_patch=${PATCHDIR}/$1 | |||||
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}') | |||||
Not Done Inline Actionsif this is supposed to be a tabulation (can't tell with phabric) maybe it should be escaped. mat: if this is supposed to be a tabulation (can't tell with phabric) maybe it should be escaped. | |||||
fname=$(std_patch_filename $rawname) | |||||
awk -v num=${num} '\ | |||||
BEGIN { done=0; x=0; hunk=0; looking=(num==1) } \ | |||||
{ \ | |||||
if (!done) { \ | |||||
if ($1 == "@@") { \ | |||||
split ($3,a,","); \ | |||||
hc = a[2]; \ | |||||
hunk = 1; | |||||
} else if (hunk) { \ | |||||
first=substr($1,1,1); \ | |||||
if (first == "-") { hc++ } else { hc-- } \ | |||||
if (hc == 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}/* | |||||
for P in ${old_patch_list}; do | |||||
extract_comment_from_patch ${P} | |||||
done | |||||
} | |||||
regenerate_patches() { | |||||
mkdir -p ${REGENNED} | |||||
rm -f ${REGENNED}/* | |||||
new_list= | |||||
[ ! -d "${PATCH_WRKSRC}" ] && return | |||||
new_list=$(cd ${PATCH_WRKSRC} && \ | |||||
find -s * -type f -name '*.orig' 2>/dev/null) | |||||
Not Done Inline Actionsmaybe rm -rf ${COMMENTS} then mkdir -p ${COMMENTS} ? it feels strange this way around. (same for all other interations of mkdir/rm) mat: maybe `rm -rf ${COMMENTS}` then `mkdir -p ${COMMENTS}` ? it feels strange this way around. | |||||
(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}/* | |||||
patch_list=$(cd ${REGENNED} && find * -name "patch-*" 2>/dev/null) | |||||
for P in ${patch_list}; do | |||||
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 | |||||
} | |||||
conserve_old_patches() { | |||||
mkdir -p ${SAVEDIR} | |||||
rm -f ${SAVEDIR}/* | |||||
[ -z "${old_patch_list}" ] && return | |||||
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() { | |||||
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 | |||||
conserve_old_patches | |||||
install_regenerated_patches |
While since rP400846 no port should ever write any files in WRKDIR and everything should be done in WRKSRC (and other subdirectories in WRKDIR in case of multiple distfiles) it might be safer to make it a hidden directory.