summaryrefslogtreecommitdiff
path: root/Mk
diff options
context:
space:
mode:
authorJohn Marino <marino@FreeBSD.org>2015-11-15 15:25:12 +0000
committerJohn Marino <marino@FreeBSD.org>2015-11-15 15:25:12 +0000
commit6eff596ebc02a039c1ef206a831d6d6849255c81 (patch)
treea33bf429b5d1b17137be56e35ce8fbdb41d738b3 /Mk
parent- Add new port: math/R-cran-pbkrtest (diff)
Enhance "make makepatch" to address two major deficiencies
This update to the "makepatch" target adds the following enhancements: 1) Conserves comments If the existing patch has comments, they will be transferred to the regenerated patch. 2) Supports multiple patches per file If the patch file contains concatenated patches, the makepatch target will keep these patches together. It may change the order of the patches the first time, but every time after the multi-patch will be assembled in the same order. Behavioral changes: A) The "old" patches are not overwritten, but rather archived at: ${WRKDIR}/makepatch-tmp/archived-patches B) Any patch that was not replaced or renamed is deleted by makepatch (but it is archived first, see paragraph above) C) There regeneration messages for the user will show them which patches are using "legacy" names formats. D) Makepatch will do a great job at "cleaning" git patches; it removes lines starting with "diff" and "index" in the comments section. Notes: E) Should a source file be modified by multiple patches (e.g. two separate multi-patches), a composite patch will be generated. In the above example of two multi-patches, one would get the full patch and the other no longer patch the source file. Approved by: portmgr (mat) Differential Revision: D4136
Notes
Notes: svn path=/head/; revision=401709
Diffstat (limited to 'Mk')
-rw-r--r--Mk/Scripts/smart_makepatch.sh251
-rw-r--r--Mk/bsd.port.mk40
2 files changed, 255 insertions, 36 deletions
diff --git a/Mk/Scripts/smart_makepatch.sh b/Mk/Scripts/smart_makepatch.sh
new file mode 100644
index 000000000000..1ef87b0c49ac
--- /dev/null
+++ b/Mk/Scripts/smart_makepatch.sh
@@ -0,0 +1,251 @@
+#!/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
+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=$(echo $1 | sed 's|^\.\/||')
+ local 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 * -type f -name "patch-*" -maxdepth 0 \
+ 2>/dev/null | sed -e '/\.orig$/d'
+ )
+ fi;
+}
+
+valid_name() {
+ local current_patch_name=$1
+ local first_target=$(echo $2 | sed 's|^\.\/||')
+ local result=$3
+ local testres
+ local lps
+ 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=$(grep "^+++ " ${existing_patch} | awk '{x++; print x}')
+ local rawname
+ local fname
+ local num
+ 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 ($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}/*
+ 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=$(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
+
+ 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=$(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
diff --git a/Mk/bsd.port.mk b/Mk/bsd.port.mk
index c27f12bec82e..1ed4f64b6ed9 100644
--- a/Mk/bsd.port.mk
+++ b/Mk/bsd.port.mk
@@ -1114,44 +1114,12 @@ STRIPBIN= ${STRIP_CMD}
.else
-# Look for files named "*.orig" under ${PATCH_WRKSRC} and (re-)generate
-# ${PATCHDIR}/patch-* files from them. By popular demand, we currently
-# use '_' (underscore) to replace path separators in patch file names.
-#
-# If a file name happens to contain character which is also a separator
-# replacement character, it will be doubled in the resulting patch name.
-#
-# To minimize gratuitous patch renames, newly generated patches will be
-# written under existing file names when they use any of the previously
-# common path separators ([-+_]) or legacy double underscore (__).
-
.if !target(makepatch)
-PATCH_PATH_SEPARATOR= _
makepatch:
- @${MKDIR} ${PATCHDIR}
- @(cd ${PATCH_WRKSRC}; \
- for f in `${FIND} -s . -type f -name '*.orig'`; do \
- ORIG=$${f#./}; \
- NEW=$${ORIG%.orig}; \
- cmp -s $${ORIG} $${NEW} && continue; \
- ! for _lps in `${ECHO} _ - + | ${SED} -e \
- 's|${PATCH_PATH_SEPARATOR}|__|'`; do \
- PATCH=`${ECHO} $${NEW} | ${SED} -e "s|/|$${_lps}|g"`; \
- test -f "${PATCHDIR}/patch-$${PATCH}" && break; \
- done || ${ECHO} $${_SEEN} | ${GREP} -q /$${PATCH} && { \
- PATCH=`${ECHO} $${NEW} | ${SED} -e \
- 's|${PATCH_PATH_SEPARATOR}|&&|g' -e \
- 's|/|${PATCH_PATH_SEPARATOR}|g'`; \
- _SEEN=$${_SEEN}/$${PATCH}; \
- }; \
- OUT=${PATCHDIR}/patch-$${PATCH}; \
- ${ECHO} ${DIFF} -udp $${ORIG} $${NEW} '>' $${OUT}; \
- TZ=UTC ${DIFF} -udp $${ORIG} $${NEW} | ${SED} -e \
- '/^---/s|\.[0-9]* +0000$$| UTC|' -e \
- '/^+++/s|\([[:blank:]][-0-9:.+]*\)*$$||' \
- > $${OUT} || ${TRUE}; \
- done \
- )
+ @${SETENV} WRKDIR=${WRKDIR} PATCHDIR=${PATCHDIR} \
+ PATCH_WRKSRC=${PATCH_WRKSRC} \
+ STRIP_COMPONENTS="${PATCH_STRIP:S/-p//}" \
+ ${SH} ${SCRIPTSDIR}/smart_makepatch.sh
.endif