xref: /OK3568_Linux_fs/buildroot/support/scripts/apply-patches.sh (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/usr/bin/env bash
2*4882a593Smuzhiyun# A little script I whipped up to make it easy to
3*4882a593Smuzhiyun# patch source trees and have sane error handling
4*4882a593Smuzhiyun# -Erik
5*4882a593Smuzhiyun#
6*4882a593Smuzhiyun# (c) 2002 Erik Andersen <andersen@codepoet.org>
7*4882a593Smuzhiyun#
8*4882a593Smuzhiyun# Parameters:
9*4882a593Smuzhiyun# - "-s", optional. Silent operation, don't print anything if there
10*4882a593Smuzhiyun# isn't any error.
11*4882a593Smuzhiyun# - the build directory, optional, default value is '.'. The place where are
12*4882a593Smuzhiyun# the package sources.
13*4882a593Smuzhiyun# - the patch directory, optional, default '../kernel-patches'. The place
14*4882a593Smuzhiyun# where are the scripts you want to apply.
15*4882a593Smuzhiyun# - other parameters are the patch name patterns, optional, default value is
16*4882a593Smuzhiyun# '*'. Pattern(s) describing the patch names you want to apply.
17*4882a593Smuzhiyun#
18*4882a593Smuzhiyun# The script will look recursively for patches from the patch directory. If a
19*4882a593Smuzhiyun# file named 'series' exists then the patches mentioned in it will be applied
20*4882a593Smuzhiyun# as plain patches, regardless of their file name. If no 'series' file exists,
21*4882a593Smuzhiyun# the script will look for file names matching pattern(s). If the name
22*4882a593Smuzhiyun# ends with '.tar.*', '.tbz2' or '.tgz', the file is considered as an archive
23*4882a593Smuzhiyun# and will be uncompressed into a directory named
24*4882a593Smuzhiyun# '.patches-name_of_the_archive-unpacked'. It's the turn of this directory to
25*4882a593Smuzhiyun# be scanned with '*' as pattern. Remember that scanning is recursive. Other
26*4882a593Smuzhiyun# files than series file and archives are considered as a patch.
27*4882a593Smuzhiyun#
28*4882a593Smuzhiyun# Once a patch is found, the script will try to apply it. If its name doesn't
29*4882a593Smuzhiyun# end with '.gz', '.bz', '.bz2', '.xz', '.zip', '.Z', '.diff*' or '.patch*',
30*4882a593Smuzhiyun# it will be skipped. If necessary, the patch will be uncompressed before being
31*4882a593Smuzhiyun# applied. The list of the patches applied is stored in '.applied_patches_list'
32*4882a593Smuzhiyun# file in the build directory.
33*4882a593Smuzhiyun
34*4882a593Smuzhiyunset -e
35*4882a593Smuzhiyun
36*4882a593Smuzhiyunsilent=
37*4882a593Smuzhiyunif [ "$1" = "-s" ] ; then
38*4882a593Smuzhiyun    # add option to be used by the patch tool
39*4882a593Smuzhiyun    silent=-s
40*4882a593Smuzhiyun    shift
41*4882a593Smuzhiyunfi
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun# Set directories from arguments, or use defaults.
44*4882a593Smuzhiyunbuilddir=${1-.}
45*4882a593Smuzhiyunpatchdir=${2-../kernel-patches}
46*4882a593Smuzhiyunshift 2
47*4882a593Smuzhiyunpatchpattern=${@-*}
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun# use a well defined sorting order
50*4882a593Smuzhiyunexport LC_COLLATE=C
51*4882a593Smuzhiyun
52*4882a593Smuzhiyunif [ ! -d "${builddir}" ] ; then
53*4882a593Smuzhiyun    echo "Aborting.  '${builddir}' is not a directory."
54*4882a593Smuzhiyun    exit 1
55*4882a593Smuzhiyunfi
56*4882a593Smuzhiyunif [ ! -d "${patchdir}" ] ; then
57*4882a593Smuzhiyun    echo "Aborting.  '${patchdir}' is not a directory."
58*4882a593Smuzhiyun    exit 1
59*4882a593Smuzhiyunfi
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun# Remove any rejects present BEFORE patching - Because if there are
62*4882a593Smuzhiyun# any, even if patches are well applied, at the end it will complain
63*4882a593Smuzhiyun# about rejects in builddir.
64*4882a593Smuzhiyunfind ${builddir}/ '(' -name '*.rej' -o -name '.*.rej' ')' -print0 | \
65*4882a593Smuzhiyun    xargs -0 -r rm -f
66*4882a593Smuzhiyun
67*4882a593Smuzhiyunfunction apply_patch {
68*4882a593Smuzhiyun    path="${1%%/}"
69*4882a593Smuzhiyun    patch="${2}"
70*4882a593Smuzhiyun    case "${path}" in
71*4882a593Smuzhiyun        /*) ;;
72*4882a593Smuzhiyun        *)  path="$PWD/${path}";;
73*4882a593Smuzhiyun    esac
74*4882a593Smuzhiyun    if [ "$3" ]; then
75*4882a593Smuzhiyun        type="series"; uncomp="cat"
76*4882a593Smuzhiyun    else
77*4882a593Smuzhiyun        case "$patch" in
78*4882a593Smuzhiyun            *.gz)
79*4882a593Smuzhiyun            type="gzip"; uncomp="gunzip -dc"; ;;
80*4882a593Smuzhiyun            *.bz)
81*4882a593Smuzhiyun            type="bzip"; uncomp="bunzip -dc"; ;;
82*4882a593Smuzhiyun            *.bz2)
83*4882a593Smuzhiyun            type="bzip2"; uncomp="bunzip2 -dc"; ;;
84*4882a593Smuzhiyun            *.xz)
85*4882a593Smuzhiyun            type="xz"; uncomp="unxz -dc"; ;;
86*4882a593Smuzhiyun            *.zip)
87*4882a593Smuzhiyun            type="zip"; uncomp="unzip -d"; ;;
88*4882a593Smuzhiyun            *.Z)
89*4882a593Smuzhiyun            type="compress"; uncomp="uncompress -c"; ;;
90*4882a593Smuzhiyun            *.diff*)
91*4882a593Smuzhiyun            type="diff"; uncomp="cat"; ;;
92*4882a593Smuzhiyun            *.patch*)
93*4882a593Smuzhiyun            type="patch"; uncomp="cat"; ;;
94*4882a593Smuzhiyun            *)
95*4882a593Smuzhiyun            echo "Unsupported file type for ${path}/${patch}, skipping";
96*4882a593Smuzhiyun            return 0
97*4882a593Smuzhiyun            ;;
98*4882a593Smuzhiyun        esac
99*4882a593Smuzhiyun    fi
100*4882a593Smuzhiyun    if [ -z "$silent" ] ; then
101*4882a593Smuzhiyun        echo ""
102*4882a593Smuzhiyun        echo "Applying $patch using ${type}: "
103*4882a593Smuzhiyun    fi
104*4882a593Smuzhiyun    if [ ! -e "${path}/$patch" ] ; then
105*4882a593Smuzhiyun        echo "Error: missing patch file ${path}/$patch"
106*4882a593Smuzhiyun        exit 1
107*4882a593Smuzhiyun    fi
108*4882a593Smuzhiyun    existing="$(grep -E "/${patch}\$" ${builddir}/.applied_patches_list || true)"
109*4882a593Smuzhiyun    if [ -n "${existing}" ]; then
110*4882a593Smuzhiyun        echo "Error: duplicate filename '${patch}'"
111*4882a593Smuzhiyun        echo "Conflicting files are:"
112*4882a593Smuzhiyun        echo "  already applied: ${existing}"
113*4882a593Smuzhiyun        echo "  to be applied  : ${path}/${patch}"
114*4882a593Smuzhiyun        exit 1
115*4882a593Smuzhiyun    fi
116*4882a593Smuzhiyun    echo "${path}/${patch}" >> ${builddir}/.applied_patches_list
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun    cd ${builddir}
119*4882a593Smuzhiyun    if [ -n "$BR2_GEN_GIT" ]; then
120*4882a593Smuzhiyun        if [ ! -d .git ]; then
121*4882a593Smuzhiyun            git init
122*4882a593Smuzhiyun            echo -e "*" >> .gitignore
123*4882a593Smuzhiyun            git add -f .gitignore *
124*4882a593Smuzhiyun            git commit --no-edit -m "init"
125*4882a593Smuzhiyun        fi
126*4882a593Smuzhiyun    fi
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun    ${uncomp} "${path}/$patch" | patch -g0 -p1 -E --no-backup-if-mismatch -d "${builddir}" -t -N $silent
129*4882a593Smuzhiyun    if [ $? != 0 ] ; then
130*4882a593Smuzhiyun        echo "Patch failed!  Please fix ${patch}!"
131*4882a593Smuzhiyun        exit 1
132*4882a593Smuzhiyun    fi
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun    if [ -n "$BR2_GEN_GIT" ]; then
135*4882a593Smuzhiyun        # Remove backup files
136*4882a593Smuzhiyun        find $builddir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \;
137*4882a593Smuzhiyun        git am "${path}/${patch}" --exclude "*" ||
138*4882a593Smuzhiyun            git commit --allow-empty --no-edit -m "${patch}"
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun        git add -f *
141*4882a593Smuzhiyun        git commit --allow-empty --amend --no-edit
142*4882a593Smuzhiyun        rm -rf .git/rebase-apply/
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun        # Wait for auto gc
145*4882a593Smuzhiyun        while [ -f .git/gc.pid ]; do sleep 1;done
146*4882a593Smuzhiyun    fi
147*4882a593Smuzhiyun}
148*4882a593Smuzhiyun
149*4882a593Smuzhiyunfunction scan_patchdir {
150*4882a593Smuzhiyun    local path=$1
151*4882a593Smuzhiyun    shift 1
152*4882a593Smuzhiyun    patches=${@-*}
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun    # If there is a series file, use it instead of using ls sort order
155*4882a593Smuzhiyun    # to apply patches. Skip line starting with a dash.
156*4882a593Smuzhiyun    if [ -e "${path}/series" ] ; then
157*4882a593Smuzhiyun        # The format of a series file accepts a second field that is
158*4882a593Smuzhiyun        # used to specify the number of directory components to strip
159*4882a593Smuzhiyun        # when applying the patch, in the form -pN (N an integer >= 0)
160*4882a593Smuzhiyun        # We assume this field to always be -p1 whether it is present
161*4882a593Smuzhiyun        # or missing.
162*4882a593Smuzhiyun        series_patches="`grep -Ev "^#" ${path}/series | cut -d ' ' -f1 2> /dev/null`"
163*4882a593Smuzhiyun        for i in $series_patches; do
164*4882a593Smuzhiyun            apply_patch "$path" "$i" series
165*4882a593Smuzhiyun        done
166*4882a593Smuzhiyun    else
167*4882a593Smuzhiyun        for i in `cd $path; ls -d $patches 2> /dev/null` ; do
168*4882a593Smuzhiyun            if [ -d "${path}/$i" ] ; then
169*4882a593Smuzhiyun                scan_patchdir "${path}/$i"
170*4882a593Smuzhiyun            elif echo "$i" | grep -q -E "\.tar(\..*)?$|\.tbz2?$|\.tgz$" ; then
171*4882a593Smuzhiyun                unpackedarchivedir="$builddir/.patches-$(basename $i)-unpacked"
172*4882a593Smuzhiyun                rm -rf "$unpackedarchivedir" 2> /dev/null
173*4882a593Smuzhiyun                mkdir "$unpackedarchivedir"
174*4882a593Smuzhiyun                tar -C "$unpackedarchivedir" -xaf "${path}/$i"
175*4882a593Smuzhiyun                scan_patchdir "$unpackedarchivedir"
176*4882a593Smuzhiyun            else
177*4882a593Smuzhiyun                apply_patch "$path" "$i"
178*4882a593Smuzhiyun            fi
179*4882a593Smuzhiyun        done
180*4882a593Smuzhiyun    fi
181*4882a593Smuzhiyun}
182*4882a593Smuzhiyun
183*4882a593Smuzhiyuntouch ${builddir}/.applied_patches_list
184*4882a593Smuzhiyunscan_patchdir "$patchdir" "$patchpattern"
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun# Check for rejects...
187*4882a593Smuzhiyunif [ "`find $builddir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ] ; then
188*4882a593Smuzhiyun    echo "Aborting.  Reject files found."
189*4882a593Smuzhiyun    exit 1
190*4882a593Smuzhiyunfi
191