Advertisement
richardgv

/etc/portage/env/epatch.sh

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