dev-libs/newt: stable 0.52.20 for ia64, bug #661012
[gentoo.git] / eclass / epatch.eclass
1 # Copyright 1999-2018 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 # @ECLASS: epatch.eclass
5 # @MAINTAINER:
6 # base-system@gentoo.org
7 # @BLURB: easy patch application functions
8 # @DESCRIPTION:
9 # An eclass providing epatch and epatch_user functions to easily apply
10 # patches to ebuilds. Mostly superseded by eapply* in EAPI 6.
11
12 if [[ -z ${_EPATCH_ECLASS} ]]; then
13
14 case ${EAPI:-0} in
15         0|1|2|3|4|5|6)
16                 ;;
17         *)
18                 die "${ECLASS}: banned in EAPI=${EAPI}; use eapply* instead";;
19 esac
20
21 inherit estack
22
23 # @VARIABLE: EPATCH_SOURCE
24 # @DESCRIPTION:
25 # Default directory to search for patches.
26 EPATCH_SOURCE="${WORKDIR}/patch"
27 # @VARIABLE: EPATCH_SUFFIX
28 # @DESCRIPTION:
29 # Default extension for patches (do not prefix the period yourself).
30 EPATCH_SUFFIX="patch.bz2"
31 # @VARIABLE: EPATCH_OPTS
32 # @DESCRIPTION:
33 # Options to pass to patch.  Meant for ebuild/package-specific tweaking
34 # such as forcing the patch level (-p#) or fuzz (-F#) factor.  Note that
35 # for single patch tweaking, you can also pass flags directly to epatch.
36 EPATCH_OPTS=""
37 # @VARIABLE: EPATCH_COMMON_OPTS
38 # @DESCRIPTION:
39 # Common options to pass to `patch`.  You probably should never need to
40 # change these.  If you do, please discuss it with base-system first to
41 # be sure.
42 # @CODE
43 #       -g0 - keep RCS, ClearCase, Perforce and SCCS happy #24571
44 #       --no-backup-if-mismatch - do not leave .orig files behind
45 #       -E - automatically remove empty files
46 # @CODE
47 EPATCH_COMMON_OPTS="-g0 -E --no-backup-if-mismatch"
48 # @VARIABLE: EPATCH_EXCLUDE
49 # @DESCRIPTION:
50 # List of patches not to apply.  Note this is only file names,
51 # and not the full path.  Globs accepted.
52 EPATCH_EXCLUDE=""
53 # @VARIABLE: EPATCH_SINGLE_MSG
54 # @DESCRIPTION:
55 # Change the printed message for a single patch.
56 EPATCH_SINGLE_MSG=""
57 # @VARIABLE: EPATCH_MULTI_MSG
58 # @DESCRIPTION:
59 # Change the printed message for multiple patches.
60 EPATCH_MULTI_MSG="Applying various patches (bugfixes/updates) ..."
61 # @VARIABLE: EPATCH_FORCE
62 # @DESCRIPTION:
63 # Only require patches to match EPATCH_SUFFIX rather than the extended
64 # arch naming style.
65 EPATCH_FORCE="no"
66 # @VARIABLE: EPATCH_USER_EXCLUDE
67 # @DEFAULT_UNSET
68 # @DESCRIPTION:
69 # List of patches not to apply.  Note this is only file names,
70 # and not the full path.  Globs accepted.
71
72 # @FUNCTION: epatch
73 # @USAGE: [options] [patches] [dirs of patches]
74 # @DESCRIPTION:
75 # epatch is designed to greatly simplify the application of patches.  It can
76 # process patch files directly, or directories of patches.  The patches may be
77 # compressed (bzip/gzip/etc...) or plain text.  You generally need not specify
78 # the -p option as epatch will automatically attempt -p0 to -p4 until things
79 # apply successfully.
80 #
81 # If you do not specify any patches/dirs, then epatch will default to the
82 # directory specified by EPATCH_SOURCE.
83 #
84 # Any options specified that start with a dash will be passed down to patch
85 # for this specific invocation.  As soon as an arg w/out a dash is found, then
86 # arg processing stops.
87 #
88 # When processing directories, epatch will apply all patches that match:
89 # @CODE
90 #       if ${EPATCH_FORCE} != "yes"
91 #               ??_${ARCH}_foo.${EPATCH_SUFFIX}
92 #       else
93 #               *.${EPATCH_SUFFIX}
94 # @CODE
95 # The leading ?? are typically numbers used to force consistent patch ordering.
96 # The arch field is used to apply patches only for the host architecture with
97 # the special value of "all" means apply for everyone.  Note that using values
98 # other than "all" is highly discouraged -- you should apply patches all the
99 # time and let architecture details be detected at configure/compile time.
100 #
101 # If EPATCH_SUFFIX is empty, then no period before it is implied when searching
102 # for patches to apply.
103 #
104 # Refer to the other EPATCH_xxx variables for more customization of behavior.
105 epatch() {
106         _epatch_draw_line() {
107                 # create a line of same length as input string
108                 [[ -z $1 ]] && set "$(printf "%65s" '')"
109                 echo "${1//?/=}"
110         }
111
112         unset P4CONFIG P4PORT P4USER # keep perforce at bay #56402
113
114         # First process options.  We localize the EPATCH_OPTS setting
115         # from above so that we can pass it on in the loop below with
116         # any additional values the user has specified.
117         local EPATCH_OPTS=( ${EPATCH_OPTS[*]} )
118         while [[ $# -gt 0 ]] ; do
119                 case $1 in
120                 -*) EPATCH_OPTS+=( "$1" ) ;;
121                 *) break ;;
122                 esac
123                 shift
124         done
125
126         # Let the rest of the code process one user arg at a time --
127         # each arg may expand into multiple patches, and each arg may
128         # need to start off with the default global EPATCH_xxx values
129         if [[ $# -gt 1 ]] ; then
130                 local m
131                 for m in "$@" ; do
132                         epatch "${m}"
133                 done
134                 return 0
135         fi
136
137         local SINGLE_PATCH="no"
138         # no args means process ${EPATCH_SOURCE}
139         [[ $# -eq 0 ]] && set -- "${EPATCH_SOURCE}"
140
141         if [[ -f $1 ]] ; then
142                 SINGLE_PATCH="yes"
143                 set -- "$1"
144                 # Use the suffix from the single patch (localize it); the code
145                 # below will find the suffix for us
146                 local EPATCH_SUFFIX=$1
147
148         elif [[ -d $1 ]] ; then
149                 # We have to force sorting to C so that the wildcard expansion is consistent #471666.
150                 evar_push_set LC_COLLATE C
151                 # Some people like to make dirs of patches w/out suffixes (vim).
152                 set -- "$1"/*${EPATCH_SUFFIX:+."${EPATCH_SUFFIX}"}
153                 evar_pop
154
155         elif [[ -f ${EPATCH_SOURCE}/$1 ]] ; then
156                 # Re-use EPATCH_SOURCE as a search dir
157                 epatch "${EPATCH_SOURCE}/$1"
158                 return $?
159
160         else
161                 # sanity check ... if it isn't a dir or file, wtf man ?
162                 [[ $# -ne 0 ]] && EPATCH_SOURCE=$1
163                 echo
164                 eerror "Cannot find \$EPATCH_SOURCE!  Value for \$EPATCH_SOURCE is:"
165                 eerror
166                 eerror "  ${EPATCH_SOURCE}"
167                 eerror "  ( ${EPATCH_SOURCE##*/} )"
168                 echo
169                 die "Cannot find \$EPATCH_SOURCE!"
170         fi
171
172         # Now that we know we're actually going to apply something, merge
173         # all of the patch options back in to a single variable for below.
174         EPATCH_OPTS="${EPATCH_COMMON_OPTS} ${EPATCH_OPTS[*]}"
175
176         local PIPE_CMD
177         case ${EPATCH_SUFFIX##*\.} in
178                 xz)      PIPE_CMD="xz -dc"    ;;
179                 lzma)    PIPE_CMD="lzma -dc"  ;;
180                 bz2)     PIPE_CMD="bzip2 -dc" ;;
181                 gz|Z|z)  PIPE_CMD="gzip -dc"  ;;
182                 ZIP|zip) PIPE_CMD="unzip -p"  ;;
183                 *)       ;;
184         esac
185
186         [[ ${SINGLE_PATCH} == "no" ]] && einfo "${EPATCH_MULTI_MSG}"
187
188         local x
189         for x in "$@" ; do
190                 # If the patch dir given contains subdirs, or our EPATCH_SUFFIX
191                 # didn't match anything, ignore continue on
192                 [[ ! -f ${x} ]] && continue
193
194                 local patchname=${x##*/}
195
196                 # Apply single patches, or forced sets of patches, or
197                 # patches with ARCH dependant names.
198                 #       ???_arch_foo.patch
199                 # Else, skip this input altogether
200                 local a=${patchname#*_} # strip the ???_
201                 a=${a%%_*}              # strip the _foo.patch
202                 if ! [[ ${SINGLE_PATCH} == "yes" || \
203                                 ${EPATCH_FORCE} == "yes" || \
204                                 ${a} == all     || \
205                                 ${a} == ${ARCH} ]]
206                 then
207                         continue
208                 fi
209
210                 # Let people filter things dynamically
211                 if [[ -n ${EPATCH_EXCLUDE}${EPATCH_USER_EXCLUDE} ]] ; then
212                         # let people use globs in the exclude
213                         eshopts_push -o noglob
214
215                         local ex
216                         for ex in ${EPATCH_EXCLUDE} ; do
217                                 if [[ ${patchname} == ${ex} ]] ; then
218                                         einfo "  Skipping ${patchname} due to EPATCH_EXCLUDE ..."
219                                         eshopts_pop
220                                         continue 2
221                                 fi
222                         done
223
224                         for ex in ${EPATCH_USER_EXCLUDE} ; do
225                                 if [[ ${patchname} == ${ex} ]] ; then
226                                         einfo "  Skipping ${patchname} due to EPATCH_USER_EXCLUDE ..."
227                                         eshopts_pop
228                                         continue 2
229                                 fi
230                         done
231
232                         eshopts_pop
233                 fi
234
235                 if [[ ${SINGLE_PATCH} == "yes" ]] ; then
236                         if [[ -n ${EPATCH_SINGLE_MSG} ]] ; then
237                                 einfo "${EPATCH_SINGLE_MSG}"
238                         else
239                                 einfo "Applying ${patchname} ..."
240                         fi
241                 else
242                         einfo "  ${patchname} ..."
243                 fi
244
245                 # Handle aliased patch command #404447 #461568
246                 local patch="patch"
247                 eval $(alias patch 2>/dev/null | sed 's:^alias ::')
248
249                 # most of the time, there will only be one run per unique name,
250                 # but if there are more, make sure we get unique log filenames
251                 local STDERR_TARGET="${T}/${patchname}.out"
252                 if [[ -e ${STDERR_TARGET} ]] ; then
253                         STDERR_TARGET="${T}/${patchname}-$$.out"
254                 fi
255
256                 printf "***** %s *****\nPWD: %s\nPATCH TOOL: %s -> %s\nVERSION INFO:\n%s\n\n" \
257                         "${patchname}" \
258                         "${PWD}" \
259                         "${patch}" \
260                         "$(type -P "${patch}")" \
261                         "$(${patch} --version)" \
262                         > "${STDERR_TARGET}"
263
264                 # Decompress the patch if need be
265                 local count=0
266                 local PATCH_TARGET
267                 if [[ -n ${PIPE_CMD} ]] ; then
268                         PATCH_TARGET="${T}/$$.patch"
269                         echo "PIPE_COMMAND:  ${PIPE_CMD} ${x} > ${PATCH_TARGET}" >> "${STDERR_TARGET}"
270
271                         if ! (${PIPE_CMD} "${x}" > "${PATCH_TARGET}") >> "${STDERR_TARGET}" 2>&1 ; then
272                                 echo
273                                 eerror "Could not extract patch!"
274                                 #die "Could not extract patch!"
275                                 count=5
276                                 break
277                         fi
278                 else
279                         PATCH_TARGET=${x}
280                 fi
281
282                 # Check for absolute paths in patches.  If sandbox is disabled,
283                 # people could (accidently) patch files in the root filesystem.
284                 # Or trigger other unpleasantries #237667.  So disallow -p0 on
285                 # such patches.
286                 local abs_paths=$(egrep -n '^[-+]{3} /' "${PATCH_TARGET}" | awk '$2 != "/dev/null" { print }')
287                 if [[ -n ${abs_paths} ]] ; then
288                         count=1
289                         printf "NOTE: skipping -p0 due to absolute paths in patch:\n%s\n" "${abs_paths}" >> "${STDERR_TARGET}"
290                 fi
291                 # Similar reason, but with relative paths.
292                 local rel_paths=$(egrep -n '^[-+]{3} [^ ]*[.][.]/' "${PATCH_TARGET}")
293                 if [[ -n ${rel_paths} ]] ; then
294                         echo
295                         eerror "Rejected Patch: ${patchname} !"
296                         eerror " ( ${PATCH_TARGET} )"
297                         eerror
298                         eerror "Your patch uses relative paths '../':"
299                         eerror "${rel_paths}"
300                         echo
301                         die "you need to fix the relative paths in patch"
302                 fi
303
304                 # Dynamically detect the correct -p# ... i'm lazy, so shoot me :/
305                 local patch_cmd
306                 while [[ ${count} -lt 5 ]] ; do
307                         patch_cmd="${patch} -p${count} ${EPATCH_OPTS}"
308
309                         # Generate some useful debug info ...
310                         (
311                         _epatch_draw_line "***** ${patchname} *****"
312                         echo
313                         echo "PATCH COMMAND:  ${patch_cmd} --dry-run -f < '${PATCH_TARGET}'"
314                         echo
315                         _epatch_draw_line "***** ${patchname} *****"
316                         ${patch_cmd} --dry-run -f < "${PATCH_TARGET}" 2>&1
317                         ret=$?
318                         echo
319                         echo "patch program exited with status ${ret}"
320                         exit ${ret}
321                         ) >> "${STDERR_TARGET}"
322
323                         if [ $? -eq 0 ] ; then
324                                 (
325                                 _epatch_draw_line "***** ${patchname} *****"
326                                 echo
327                                 echo "ACTUALLY APPLYING ${patchname} ..."
328                                 echo "PATCH COMMAND:  ${patch_cmd} < '${PATCH_TARGET}'"
329                                 echo
330                                 _epatch_draw_line "***** ${patchname} *****"
331                                 ${patch_cmd} < "${PATCH_TARGET}" 2>&1
332                                 ret=$?
333                                 echo
334                                 echo "patch program exited with status ${ret}"
335                                 exit ${ret}
336                                 ) >> "${STDERR_TARGET}"
337
338                                 if [ $? -ne 0 ] ; then
339                                         echo
340                                         eerror "A dry-run of patch command succeeded, but actually"
341                                         eerror "applying the patch failed!"
342                                         #die "Real world sux compared to the dreamworld!"
343                                         count=5
344                                 fi
345                                 break
346                         fi
347
348                         : $(( count++ ))
349                 done
350
351                 (( EPATCH_N_APPLIED_PATCHES++ ))
352
353                 # if we had to decompress the patch, delete the temp one
354                 if [[ -n ${PIPE_CMD} ]] ; then
355                         rm -f "${PATCH_TARGET}"
356                 fi
357
358                 if [[ ${count} -ge 5 ]] ; then
359                         echo
360                         eerror "Failed Patch: ${patchname} !"
361                         eerror " ( ${PATCH_TARGET} )"
362                         eerror
363                         eerror "Include in your bugreport the contents of:"
364                         eerror
365                         eerror "  ${STDERR_TARGET}"
366                         echo
367                         die "Failed Patch: ${patchname}!"
368                 fi
369
370                 # if everything worked, delete the full debug patch log
371                 rm -f "${STDERR_TARGET}"
372
373                 # then log away the exact stuff for people to review later
374                 cat <<-EOF >> "${T}/epatch.log"
375                 PATCH: ${x}
376                 CMD: ${patch_cmd}
377                 PWD: ${PWD}
378
379                 EOF
380                 eend 0
381         done
382
383         [[ ${SINGLE_PATCH} == "no" ]] && einfo "Done with patching"
384         : # everything worked
385 }
386
387 case ${EAPI:-0} in
388 0|1|2|3|4|5)
389
390 # @VARIABLE: EPATCH_USER_SOURCE
391 # @DESCRIPTION:
392 # Location for user patches, see the epatch_user function.
393 # Should be set by the user. Don't set this in ebuilds.
394 : ${EPATCH_USER_SOURCE:=${PORTAGE_CONFIGROOT%/}/etc/portage/patches}
395
396 # @FUNCTION: epatch_user
397 # @USAGE:
398 # @DESCRIPTION:
399 # Applies user-provided patches to the source tree. The patches are
400 # taken from /etc/portage/patches/<CATEGORY>/<P-PR|P|PN>[:SLOT]/, where the first
401 # of these three directories to exist will be the one to use, ignoring
402 # any more general directories which might exist as well. They must end
403 # in ".patch" to be applied.
404 #
405 # User patches are intended for quick testing of patches without ebuild
406 # modifications, as well as for permanent customizations a user might
407 # desire. Obviously, there can be no official support for arbitrarily
408 # patched ebuilds. So whenever a build log in a bug report mentions that
409 # user patches were applied, the user should be asked to reproduce the
410 # problem without these.
411 #
412 # Not all ebuilds do call this function, so placing patches in the
413 # stated directory might or might not work, depending on the package and
414 # the eclasses it inherits and uses. It is safe to call the function
415 # repeatedly, so it is always possible to add a call at the ebuild
416 # level. The first call is the time when the patches will be
417 # applied.
418 #
419 # Ideally, this function should be called after gentoo-specific patches
420 # have been applied, so that their code can be modified as well, but
421 # before calls to e.g. eautoreconf, as the user patches might affect
422 # autotool input files as well.
423 epatch_user() {
424         [[ $# -ne 0 ]] && die "epatch_user takes no options"
425
426         # Allow multiple calls to this function; ignore all but the first
427         local applied="${T}/epatch_user.log"
428         [[ -e ${applied} ]] && return 2
429
430         # don't clobber any EPATCH vars that the parent might want
431         local EPATCH_SOURCE check
432         for check in ${CATEGORY}/{${P}-${PR},${P},${PN}}{,:${SLOT%/*}}; do
433                 EPATCH_SOURCE=${EPATCH_USER_SOURCE}/${CTARGET}/${check}
434                 [[ -r ${EPATCH_SOURCE} ]] || EPATCH_SOURCE=${EPATCH_USER_SOURCE}/${CHOST}/${check}
435                 [[ -r ${EPATCH_SOURCE} ]] || EPATCH_SOURCE=${EPATCH_USER_SOURCE}/${check}
436                 if [[ -d ${EPATCH_SOURCE} ]] ; then
437                         local old_n_applied_patches=${EPATCH_N_APPLIED_PATCHES:-0}
438                         EPATCH_SOURCE=${EPATCH_SOURCE} \
439                         EPATCH_SUFFIX="patch" \
440                         EPATCH_FORCE="yes" \
441                         EPATCH_MULTI_MSG="Applying user patches from ${EPATCH_SOURCE} ..." \
442                         epatch
443                         echo "${EPATCH_SOURCE}" > "${applied}"
444                         if [[ ${old_n_applied_patches} -lt ${EPATCH_N_APPLIED_PATCHES} ]]; then
445                                 has epatch_user_death_notice ${EBUILD_DEATH_HOOKS} || \
446                                         EBUILD_DEATH_HOOKS+=" epatch_user_death_notice"
447                         fi
448                         return 0
449                 fi
450         done
451         echo "none" > "${applied}"
452         return 1
453 }
454
455 # @FUNCTION: epatch_user_death_notice
456 # @INTERNAL
457 # @DESCRIPTION:
458 # Include an explicit notice in the die message itself that user patches were
459 # applied to this build.
460 epatch_user_death_notice() {
461         ewarn "!!! User patches were applied to this build!"
462 }
463
464 esac
465
466 _EPATCH_ECLASS=1
467 fi #_EPATCH_ECLASS