apply-patches.sh 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. set -e
  34. silent=
  35. if [ "$1" = "-s" ] ; then
  36. # add option to be used by the patch tool
  37. silent=-s
  38. shift
  39. fi
  40. # Set directories from arguments, or use defaults.
  41. builddir=${1-.}
  42. patchdir=${2-../kernel-patches}
  43. shift 2
  44. patchpattern=${@-*}
  45. # use a well defined sorting order
  46. export LC_COLLATE=C
  47. if [ ! -d "${builddir}" ] ; then
  48. echo "Aborting. '${builddir}' is not a directory."
  49. exit 1
  50. fi
  51. if [ ! -d "${patchdir}" ] ; then
  52. echo "Aborting. '${patchdir}' is not a directory."
  53. exit 1
  54. fi
  55. # Remove any rejects present BEFORE patching - Because if there are
  56. # any, even if patches are well applied, at the end it will complain
  57. # about rejects in builddir.
  58. find ${builddir}/ '(' -name '*.rej' -o -name '.*.rej' ')' -print0 | \
  59. xargs -0 -r rm -f
  60. function apply_patch {
  61. path="${1%%/}"
  62. patch="${2}"
  63. case "${path}" in
  64. /*) ;;
  65. *) path="$PWD/${path}";;
  66. esac
  67. if [ "$3" ]; then
  68. type="series"; uncomp="cat"
  69. else
  70. case "$patch" in
  71. *.gz)
  72. type="gzip"; uncomp="gunzip -dc"; ;;
  73. *.bz)
  74. type="bzip"; uncomp="bunzip -dc"; ;;
  75. *.bz2)
  76. type="bzip2"; uncomp="bunzip2 -dc"; ;;
  77. *.xz)
  78. type="xz"; uncomp="unxz -dc"; ;;
  79. *.zip)
  80. type="zip"; uncomp="unzip -d"; ;;
  81. *.Z)
  82. type="compress"; uncomp="uncompress -c"; ;;
  83. *.diff*)
  84. type="diff"; uncomp="cat"; ;;
  85. *.patch*)
  86. type="patch"; uncomp="cat"; ;;
  87. *)
  88. echo "Unsupported file type for ${path}/${patch}, skipping";
  89. return 0
  90. ;;
  91. esac
  92. fi
  93. if [ -z "$silent" ] ; then
  94. echo ""
  95. echo "Applying $patch using ${type}: "
  96. fi
  97. if [ ! -e "${path}/$patch" ] ; then
  98. echo "Error: missing patch file ${path}/$patch"
  99. exit 1
  100. fi
  101. existing="$(grep -E "/${patch}\$" ${builddir}/.applied_patches_list || true)"
  102. if [ -n "${existing}" ]; then
  103. echo "Error: duplicate filename '${patch}'"
  104. echo "Conflicting files are:"
  105. echo " already applied: ${existing}"
  106. echo " to be applied : ${path}/${patch}"
  107. exit 1
  108. fi
  109. if grep -q "^rename from" ${path}/${patch} && \
  110. grep -q "^rename to" ${path}/${patch} ; then
  111. echo "Error: patch contains some renames, not supported by old patch versions"
  112. exit 1
  113. fi
  114. echo "${path}/${patch}" >> ${builddir}/.applied_patches_list
  115. ${uncomp} "${path}/$patch" | patch -g0 -p1 -E --no-backup-if-mismatch -d "${builddir}" -t -N $silent
  116. if [ $? != 0 ] ; then
  117. echo "Patch failed! Please fix ${patch}!"
  118. exit 1
  119. fi
  120. }
  121. function scan_patchdir {
  122. local path=$1
  123. shift 1
  124. patches=${@-*}
  125. # If there is a series file, use it instead of using ls sort order
  126. # to apply patches. Skip line starting with a dash.
  127. if [ -e "${path}/series" ] ; then
  128. # The format of a series file accepts a second field that is
  129. # used to specify the number of directory components to strip
  130. # when applying the patch, in the form -pN (N an integer >= 0)
  131. # We assume this field to always be -p1 whether it is present
  132. # or missing.
  133. series_patches="`grep -Ev "^#" ${path}/series | cut -d ' ' -f1 2> /dev/null`"
  134. for i in $series_patches; do
  135. apply_patch "$path" "$i" series
  136. done
  137. else
  138. for i in `cd $path; ls -d $patches 2> /dev/null` ; do
  139. if [ -d "${path}/$i" ] ; then
  140. scan_patchdir "${path}/$i"
  141. elif echo "$i" | grep -q -E "\.tar(\..*)?$|\.tbz2?$|\.tgz$" ; then
  142. unpackedarchivedir="$builddir/.patches-$(basename $i)-unpacked"
  143. rm -rf "$unpackedarchivedir" 2> /dev/null
  144. mkdir "$unpackedarchivedir"
  145. tar -C "$unpackedarchivedir" -xaf "${path}/$i"
  146. scan_patchdir "$unpackedarchivedir"
  147. else
  148. apply_patch "$path" "$i"
  149. fi
  150. done
  151. fi
  152. }
  153. touch ${builddir}/.applied_patches_list
  154. scan_patchdir "$patchdir" "$patchpattern"
  155. # Check for rejects...
  156. if [ "`find $builddir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ] ; then
  157. echo "Aborting. Reject files found."
  158. exit 1
  159. fi