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