diff options
author | Phil Sutter <phil@nwl.cc> | 2016-03-26 13:20:28 +0100 |
---|---|---|
committer | Waldemar Brodkorb <wbx@uclibc-ng.org> | 2016-03-27 18:52:53 +0200 |
commit | b088c254e6ecca80c557c5500aae47a7307c51b3 (patch) | |
tree | f3e1800bfd3fae229063dec6fb6571e7771676a4 | |
parent | 89d74be7e8cd61409c96dab0cc58c5f79dfe8588 (diff) |
reimplement package patching and update-patches logic
This works by using git as backend for all the dirty work. This means
that patches are not just applied, but committed separately on top of the
base sources (which are put into an initial commit). A final empty commit
marks the end of the applied patch series, which allows to have multiple
sets of patches to apply on top of each other. So a git history might
look like this:
- OpenADK patch marker: 0000
(this is the initial commit, containing the unpatched sources)
- patch 1 of series 1
- patch 2 of series 1
- patch 3 of series 1
- OpenADK patch marker: 0001
- patch 1 of series 2
- patch 2 of series 2
- OpenADK patch marker: 0002
In addition to the separating empty commits, for every patch series
metadata files are added (which are used for update-patches):
__patchfiles__: A list of the patches' file names
__patchdir__: The directory containing the applied patches
Since patches might have to be unzipped first and in order to allow
calling git-am just once for each patch series, the patches (along with
above metadata files) are cached in dedicated directories:
.git/patch_tmp/NNNN (where NNNN is the series number with leading zeroes
[so shell globbing returns them in the right order]).
In case update-patches is called later, update_patches.sh works it's way
reverse through the git history, searching for commits named 'OpenADK
patch marker: NNNN'. For each one it finds, it uses the metadata info to
first remove all source patch files, then export the history in between
using git-format-patch.
To change patches or add new ones, the user has to use git-rebase in
order to get things where they need to be for update_patches.sh to put
stuff at the right place. For an example, here is how to change patch 3
of series 1 in the sample history above:
- make desired code changes
- commit them, ideally using --fixup option
- call 'git rebase -i --autosquash <hash of OpenADK patch marker: 0000>'
Using --fixup and --autosquash is convenient, since it automatically
edits the rebase todo as intended. It's optional though, editing the todo
manually will do just fine as well.
Signed-off-by: Phil Sutter <phil@nwl.cc>
-rw-r--r-- | mk/buildhlp.mk | 4 | ||||
-rw-r--r-- | mk/vars.mk | 4 | ||||
-rw-r--r-- | scripts/patch_git.sh | 105 | ||||
-rw-r--r-- | scripts/update-patches-git | 31 | ||||
-rw-r--r-- | target/config/Config.in.adk | 12 |
5 files changed, 156 insertions, 0 deletions
diff --git a/mk/buildhlp.mk b/mk/buildhlp.mk index 0b6979ab2..c2aeb3800 100644 --- a/mk/buildhlp.mk +++ b/mk/buildhlp.mk @@ -97,6 +97,9 @@ ${WRKDIST}/.prepared: ${WRKDIST}/.extract_done endif update-patches host-update-patches: +ifneq (${ADK_UPDATE_PATCHES_GIT},) + PATH='${HOST_PATH}' ${BASH} $(SCRIPT_DIR)/update-patches-git "${WRKDIST}" +else @test ! -d ${WRKDIR}.orig || rm -rf ${WRKDIR}.orig @test ! -d ${WRKDIR}.orig ifeq ($(strip ${_IN_PACKAGE})$(strip ${_IN_CVTC}),1) @@ -115,5 +118,6 @@ endif PATH=$(call shellescape,${HOST_PATH}) \ $(call shellexport,DIFF_IGNOREFILES) \ mksh ${ADK_TOPDIR}/scripts/update-patches2 +endif .PHONY: update-patches host-update-patches diff --git a/mk/vars.mk b/mk/vars.mk index 91587382e..20f7698d9 100644 --- a/mk/vars.mk +++ b/mk/vars.mk @@ -282,7 +282,11 @@ endif HOST_CPPFLAGS:= -I$(STAGING_HOST_DIR)/usr/include HOST_LDFLAGS:= -L$(STAGING_HOST_DIR)/usr/lib -Wl,-rpath -Wl,${STAGING_HOST_DIR}/usr/lib +ifneq (${ADK_UPDATE_PATCHES_GIT},) +PATCH= PATH='${HOST_PATH}' ${BASH} $(SCRIPT_DIR)/patch_git.sh +else PATCH= PATH='${HOST_PATH}' ${BASH} $(SCRIPT_DIR)/patch.sh +endif PATCHP0= PATH='${HOST_PATH}' patch -p0 ifeq ($(ADK_STATIC_TOOLCHAIN),y) diff --git a/scripts/patch_git.sh b/scripts/patch_git.sh new file mode 100644 index 000000000..36a2d6af8 --- /dev/null +++ b/scripts/patch_git.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +# +# Patch sources using git-am, aligning things to use git-format-patch for +# update-patches. +# +# (c) 2016 Phil Sutter <phil@nwl.cc> +# +# Based on the classic patch.sh, written by: +# +# (c) 2006, 2007 Thorsten Glaser <tg@freewrt.org> +# (c) 2002 Erik Andersen <andersen@codepoet.org> + +[[ -n $BASH_VERSION ]] && shopt -s extglob + +# Set directories from arguments, or use defaults. +targetdir=${1-.} +patchdir=${2-../patches} +patchpattern=${3-*} + +if [ ! -d "${targetdir}" ] ; then + echo "Aborting. '${targetdir}' is not a directory." + exit 1 +fi +if [ ! -d "${patchdir}" ] ; then + echo "Aborting. '${patchdir}' is not a directory." + exit 0 +fi + +wd=$(pwd) + +cd "${targetdir}" +if [ ! -d .git ]; then + # drop leftover .gitignores in non-git sources, they + # might prevent us from patching 'temporary' files + # which are still present in the tarball. + find . -name .gitignore -delete + git init + git add . + git commit -a --allow-empty \ + --author="OpenADK <wbx@openadk.org>" \ + -m "OpenADK patch marker: 0000" +fi +[ -e .git/rebase-apply ] && \ + git am --abort + +i=1 +patch_tmp=$(printf ".git/patch_tmp/%04d" $i) +while [ -d $patch_tmp ]; do + let "i++" + patch_tmp=$(printf ".git/patch_tmp/%04d" $i) +done +mkdir -p $patch_tmp +patch_series=$(printf "%04d" $i) + +cd $wd +cd $patchdir +for i in $(eval echo ${patchpattern}); do + test -e "$i" || continue + i=$patchdir/$i + cd $wd + case $i in + *.gz) + type="gzip"; uncomp="gunzip -dc"; ;; + *.bz) + type="bzip"; uncomp="bunzip -dc"; ;; + *.bz2) + type="bzip2"; uncomp="bunzip2 -dc"; ;; + *.zip) + type="zip"; uncomp="unzip -d"; ;; + *.Z) + type="compress"; uncomp="uncompress -c"; ;; + *) + type="plaintext"; uncomp="cat"; ;; + esac + [ -d "${i}" ] && echo "Ignoring subdirectory ${i}" && continue + echo "$(basename $i)" >>${targetdir}/${patch_tmp}/__patchfiles__ + fake_hdr="" + patchname="$(basename -s .gz -s .bz -s .bz2 -s .zip -s .Z -s .patch $i)" + if ! grep -q '^Subject: ' ${i}; then + fake_hdr="From: OpenADK <wbx@openadk.org>\nSubject: [PATCH] ${patchname#[0-9]*-}\n\n" + fi + { echo -en $fake_hdr; ${uncomp} ${i}; } >${targetdir}/${patch_tmp}/${patchname}.patch + cd $patchdir +done + +# no patches to apply? bail out +[ -e ${targetdir}/${patch_tmp}/__patchfiles__ ] || { + rmdir ${targetdir}/${patch_tmp} + exit 0 +} + +# provide backwards compatibility to old style using 'patch' program +# XXX: this is unsafe and should be dropped at some point +am_opts="-C1" + +realpath $patchdir >${targetdir}/${patch_tmp}/__patchdir__ +cd ${targetdir} +git am $am_opts ${patch_tmp}/*.patch +if [ $? != 0 ] ; then + echo "git-am failed! Please fix patches!" + exit 1 +fi +git commit -a --allow-empty \ + --author="OpenADK <wbx@openadk.org>" \ + -m "OpenADK patch marker: $patch_series" diff --git a/scripts/update-patches-git b/scripts/update-patches-git new file mode 100644 index 000000000..8337fa847 --- /dev/null +++ b/scripts/update-patches-git @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# +# Update patches using git-format-patch from a source tree prepared by +# patch_git.sh. +# +# (c) 2016 Phil Sutter <phil@nwl.cc> + +wrkdist=$1 +wd=$(pwd) + +cd "$wrkdist" +top="" +top_series="" +git log --grep="^OpenADK patch marker:" --oneline | while read hash subject; do + [ -n "$top" ] || { + top=$hash + top_series="${subject#OpenADK patch marker: }" + continue + } + bottom=$hash + bottom_series="${subject#OpenADK patch marker: }" + + patchdir=$(<.git/patch_tmp/${top_series}/__patchdir__) + while read patchfile; do + rm ${patchdir}/$patchfile + done < .git/patch_tmp/${top_series}/__patchfiles__ + git format-patch -N -o "$patchdir" ${bottom}..${top} + + top=$bottom + top_series=$bottom_series +done diff --git a/target/config/Config.in.adk b/target/config/Config.in.adk index a70752bab..ec6d2b0fa 100644 --- a/target/config/Config.in.adk +++ b/target/config/Config.in.adk @@ -43,6 +43,18 @@ config ADK_DISABLE_CHECKSUM help Disable checksum checks of downloads. +choice +prompt "Backend for patching and update-patches" +default ADK_UPDATE_PATCHES_CLASSIC + +config ADK_UPDATE_PATCHES_CLASSIC + bool "Classic" + +config ADK_UPDATE_PATCHES_GIT + bool "Git" + +endchoice + config ADK_DISABLE_KERNEL_PATCHES bool "Disable global kernel patches" depends on ADK_TARGET_OS_LINUX |