eutils.eclass: make_desktop_entry, replace unnecessary extglob
[gentoo.git] / eclass / eutils.eclass
1 # Copyright 1999-2017 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 # @ECLASS: eutils.eclass
5 # @MAINTAINER:
6 # base-system@gentoo.org
7 # @BLURB: many extra (but common) functions that are used in ebuilds
8 # @DESCRIPTION:
9 # The eutils eclass contains a suite of functions that complement
10 # the ones that ebuild.sh already contain.  The idea is that the functions
11 # are not required in all ebuilds but enough utilize them to have a common
12 # home rather than having multiple ebuilds implementing the same thing.
13 #
14 # Due to the nature of this eclass, some functions may have maintainers
15 # different from the overall eclass!
16
17 if [[ -z ${_EUTILS_ECLASS} ]]; then
18 _EUTILS_ECLASS=1
19
20 # implicitly inherited (now split) eclasses
21 case ${EAPI:-0} in
22 0|1|2|3|4|5|6)
23         # note: we want to remove epunt-cxx retroactively for #566424
24         inherit epatch epunt-cxx estack ltprune multilib toolchain-funcs
25         ;;
26 esac
27
28 # @FUNCTION: eqawarn
29 # @USAGE: [message]
30 # @DESCRIPTION:
31 # Proxy to ewarn for package managers that don't provide eqawarn and use the PM
32 # implementation if available. Reuses PORTAGE_ELOG_CLASSES as set by the dev
33 # profile.
34 if ! declare -F eqawarn >/dev/null ; then
35         eqawarn() {
36                 has qa ${PORTAGE_ELOG_CLASSES} && ewarn "$@"
37                 :
38         }
39 fi
40
41 # @FUNCTION: ecvs_clean
42 # @USAGE: [list of dirs]
43 # @DESCRIPTION:
44 # Remove CVS directories recursiveley.  Useful when a source tarball contains
45 # internal CVS directories.  Defaults to $PWD.
46 ecvs_clean() {
47         [[ $# -eq 0 ]] && set -- .
48         find "$@" -type d -name 'CVS' -prune -print0 | xargs -0 rm -rf
49         find "$@" -type f -name '.cvs*' -print0 | xargs -0 rm -rf
50 }
51
52 # @FUNCTION: esvn_clean
53 # @USAGE: [list of dirs]
54 # @DESCRIPTION:
55 # Remove .svn directories recursiveley.  Useful when a source tarball contains
56 # internal Subversion directories.  Defaults to $PWD.
57 esvn_clean() {
58         [[ $# -eq 0 ]] && set -- .
59         find "$@" -type d -name '.svn' -prune -print0 | xargs -0 rm -rf
60 }
61
62 # @FUNCTION: egit_clean
63 # @USAGE: [list of dirs]
64 # @DESCRIPTION:
65 # Remove .git* directories/files recursiveley.  Useful when a source tarball
66 # contains internal Git directories.  Defaults to $PWD.
67 egit_clean() {
68         [[ $# -eq 0 ]] && set -- .
69         find "$@" -type d -name '.git*' -prune -print0 | xargs -0 rm -rf
70 }
71
72 # @FUNCTION: emktemp
73 # @USAGE: [temp dir]
74 # @DESCRIPTION:
75 # Cheap replacement for when debianutils (and thus mktemp)
76 # does not exist on the users system.
77 emktemp() {
78         local exe="touch"
79         [[ $1 == -d ]] && exe="mkdir" && shift
80         local topdir=$1
81
82         if [[ -z ${topdir} ]] ; then
83                 [[ -z ${T} ]] \
84                         && topdir="/tmp" \
85                         || topdir=${T}
86         fi
87
88         if ! type -P mktemp > /dev/null ; then
89                 # system lacks `mktemp` so we have to fake it
90                 local tmp=/
91                 while [[ -e ${tmp} ]] ; do
92                         tmp=${topdir}/tmp.${RANDOM}.${RANDOM}.${RANDOM}
93                 done
94                 ${exe} "${tmp}" || ${exe} -p "${tmp}"
95                 echo "${tmp}"
96         else
97                 # the args here will give slightly wierd names on BSD,
98                 # but should produce a usable file on all userlands
99                 if [[ ${exe} == "touch" ]] ; then
100                         TMPDIR="${topdir}" mktemp -t tmp.XXXXXXXXXX
101                 else
102                         TMPDIR="${topdir}" mktemp -dt tmp.XXXXXXXXXX
103                 fi
104         fi
105 }
106
107 # @FUNCTION: edos2unix
108 # @USAGE: <file> [more files ...]
109 # @DESCRIPTION:
110 # A handy replacement for dos2unix, recode, fixdos, etc...  This allows you
111 # to remove all of these text utilities from DEPEND variables because this
112 # is a script based solution.  Just give it a list of files to convert and
113 # they will all be changed from the DOS CRLF format to the UNIX LF format.
114 edos2unix() {
115         [[ $# -eq 0 ]] && return 0
116         sed -i 's/\r$//' -- "$@" || die
117 }
118
119 # @FUNCTION: make_desktop_entry
120 # @USAGE: make_desktop_entry(<command>, [name], [icon], [type], [fields])
121 # @DESCRIPTION:
122 # Make a .desktop file.
123 #
124 # @CODE
125 # binary:   what command does the app run with ?
126 # name:     the name that will show up in the menu
127 # icon:     the icon to use in the menu entry
128 #           this can be relative (to /usr/share/pixmaps) or
129 #           a full path to an icon
130 # type:     what kind of application is this?
131 #           for categories:
132 #           https://specifications.freedesktop.org/menu-spec/latest/apa.html
133 #           if unset, function tries to guess from package's category
134 # fields:       extra fields to append to the desktop file; a printf string
135 # @CODE
136 make_desktop_entry() {
137         [[ -z $1 ]] && die "make_desktop_entry: You must specify the executable"
138
139         local exec=${1}
140         local name=${2:-${PN}}
141         local icon=${3:-${PN}}
142         local type=${4}
143         local fields=${5}
144
145         if [[ -z ${type} ]] ; then
146                 local catmaj=${CATEGORY%%-*}
147                 local catmin=${CATEGORY##*-}
148                 case ${catmaj} in
149                         app)
150                                 case ${catmin} in
151                                         accessibility) type="Utility;Accessibility";;
152                                         admin)         type=System;;
153                                         antivirus)     type=System;;
154                                         arch)          type="Utility;Archiving";;
155                                         backup)        type="Utility;Archiving";;
156                                         cdr)           type="AudioVideo;DiscBurning";;
157                                         dicts)         type="Office;Dictionary";;
158                                         doc)           type=Documentation;;
159                                         editors)       type="Utility;TextEditor";;
160                                         emacs)         type="Development;TextEditor";;
161                                         emulation)     type="System;Emulator";;
162                                         laptop)        type="Settings;HardwareSettings";;
163                                         office)        type=Office;;
164                                         pda)           type="Office;PDA";;
165                                         vim)           type="Development;TextEditor";;
166                                         xemacs)        type="Development;TextEditor";;
167                                 esac
168                                 ;;
169
170                         dev)
171                                 type="Development"
172                                 ;;
173
174                         games)
175                                 case ${catmin} in
176                                         action|fps) type=ActionGame;;
177                                         arcade)     type=ArcadeGame;;
178                                         board)      type=BoardGame;;
179                                         emulation)  type=Emulator;;
180                                         kids)       type=KidsGame;;
181                                         puzzle)     type=LogicGame;;
182                                         roguelike)  type=RolePlaying;;
183                                         rpg)        type=RolePlaying;;
184                                         simulation) type=Simulation;;
185                                         sports)     type=SportsGame;;
186                                         strategy)   type=StrategyGame;;
187                                 esac
188                                 type="Game;${type}"
189                                 ;;
190
191                         gnome)
192                                 type="Gnome;GTK"
193                                 ;;
194
195                         kde)
196                                 type="KDE;Qt"
197                                 ;;
198
199                         mail)
200                                 type="Network;Email"
201                                 ;;
202
203                         media)
204                                 case ${catmin} in
205                                         gfx)
206                                                 type=Graphics
207                                                 ;;
208                                         *)
209                                                 case ${catmin} in
210                                                         radio) type=Tuner;;
211                                                         sound) type=Audio;;
212                                                         tv)    type=TV;;
213                                                         video) type=Video;;
214                                                 esac
215                                                 type="AudioVideo;${type}"
216                                                 ;;
217                                 esac
218                                 ;;
219
220                         net)
221                                 case ${catmin} in
222                                         dialup) type=Dialup;;
223                                         ftp)    type=FileTransfer;;
224                                         im)     type=InstantMessaging;;
225                                         irc)    type=IRCClient;;
226                                         mail)   type=Email;;
227                                         news)   type=News;;
228                                         nntp)   type=News;;
229                                         p2p)    type=FileTransfer;;
230                                         voip)   type=Telephony;;
231                                 esac
232                                 type="Network;${type}"
233                                 ;;
234
235                         sci)
236                                 case ${catmin} in
237                                         astro*)  type=Astronomy;;
238                                         bio*)    type=Biology;;
239                                         calc*)   type=Calculator;;
240                                         chem*)   type=Chemistry;;
241                                         elec*)   type=Electronics;;
242                                         geo*)    type=Geology;;
243                                         math*)   type=Math;;
244                                         physics) type=Physics;;
245                                         visual*) type=DataVisualization;;
246                                 esac
247                                 type="Education;Science;${type}"
248                                 ;;
249
250                         sys)
251                                 type="System"
252                                 ;;
253
254                         www)
255                                 case ${catmin} in
256                                         client) type=WebBrowser;;
257                                 esac
258                                 type="Network;${type}"
259                                 ;;
260
261                         *)
262                                 type=
263                                 ;;
264                 esac
265         fi
266         local slot=${SLOT%/*}
267         if [[ ${slot} == "0" ]] ; then
268                 local desktop_name="${PN}"
269         else
270                 local desktop_name="${PN}-${slot}"
271         fi
272         local desktop="${T}/$(echo ${exec} | sed 's:[[:space:]/:]:_:g')-${desktop_name}.desktop"
273         #local desktop=${T}/${exec%% *:-${desktop_name}}.desktop
274
275         # Don't append another ";" when a valid category value is provided.
276         type=${type%;}${type:+;}
277
278         if [[ -n ${icon} && ${icon} != /* ]] && [[ ${icon} == *.xpm || ${icon} == *.png || ${icon} == *.svg ]]; then
279                 ewarn "As described in the Icon Theme Specification, icon file extensions are not"
280                 ewarn "allowed in .desktop files if the value is not an absolute path."
281                 icon=${icon%.*}
282         fi
283
284         cat <<-EOF > "${desktop}"
285         [Desktop Entry]
286         Name=${name}
287         Type=Application
288         Comment=${DESCRIPTION}
289         Exec=${exec}
290         TryExec=${exec%% *}
291         Icon=${icon}
292         Categories=${type}
293         EOF
294
295         if [[ ${fields:-=} != *=* ]] ; then
296                 # 5th arg used to be value to Path=
297                 ewarn "make_desktop_entry: update your 5th arg to read Path=${fields}"
298                 fields="Path=${fields}"
299         fi
300         [[ -n ${fields} ]] && printf '%b\n' "${fields}" >> "${desktop}"
301
302         (
303                 # wrap the env here so that the 'insinto' call
304                 # doesn't corrupt the env of the caller
305                 insinto /usr/share/applications
306                 doins "${desktop}"
307         ) || die "installing desktop file failed"
308 }
309
310 # @FUNCTION: _eutils_eprefix_init
311 # @INTERNAL
312 # @DESCRIPTION:
313 # Initialized prefix variables for EAPI<3.
314 _eutils_eprefix_init() {
315         has "${EAPI:-0}" 0 1 2 && : ${ED:=${D}} ${EPREFIX:=} ${EROOT:=${ROOT}}
316 }
317
318 # @FUNCTION: validate_desktop_entries
319 # @USAGE: [directories]
320 # @DESCRIPTION:
321 # Validate desktop entries using desktop-file-utils
322 validate_desktop_entries() {
323         eqawarn "validate_desktop_entries is deprecated and should be not be used."
324         eqawarn ".desktop file validation is done implicitly by Portage now."
325
326         _eutils_eprefix_init
327         if [[ -x "${EPREFIX}"/usr/bin/desktop-file-validate ]] ; then
328                 einfo "Checking desktop entry validity"
329                 local directories=""
330                 for d in /usr/share/applications $@ ; do
331                         [[ -d ${ED}${d} ]] && directories="${directories} ${ED}${d}"
332                 done
333                 if [[ -n ${directories} ]] ; then
334                         for FILE in $(find ${directories} -name "*\.desktop" \
335                                                         -not -path '*.hidden*' | sort -u 2>/dev/null)
336                         do
337                                 local temp=$(desktop-file-validate ${FILE} | grep -v "warning:" | \
338                                                                 sed -e "s|error: ||" -e "s|${FILE}:|--|g" )
339                                 [[ -n $temp ]] && elog ${temp/--/${FILE/${ED}/}:}
340                         done
341                 fi
342                 echo ""
343         else
344                 einfo "Passing desktop entry validity check. Install dev-util/desktop-file-utils, if you want to help to improve Gentoo."
345         fi
346 }
347
348 # @FUNCTION: make_session_desktop
349 # @USAGE: <title> <command> [command args...]
350 # @DESCRIPTION:
351 # Make a GDM/KDM Session file.  The title is the file to execute to start the
352 # Window Manager.  The command is the name of the Window Manager.
353 #
354 # You can set the name of the file via the ${wm} variable.
355 make_session_desktop() {
356         [[ -z $1 ]] && eerror "$0: You must specify the title" && return 1
357         [[ -z $2 ]] && eerror "$0: You must specify the command" && return 1
358
359         local title=$1
360         local command=$2
361         local desktop=${T}/${wm:-${PN}}.desktop
362         shift 2
363
364         cat <<-EOF > "${desktop}"
365         [Desktop Entry]
366         Name=${title}
367         Comment=This session logs you into ${title}
368         Exec=${command} $*
369         TryExec=${command}
370         Type=XSession
371         EOF
372
373         (
374         # wrap the env here so that the 'insinto' call
375         # doesn't corrupt the env of the caller
376         insinto /usr/share/xsessions
377         doins "${desktop}"
378         )
379 }
380
381 # @FUNCTION: domenu
382 # @USAGE: <menus>
383 # @DESCRIPTION:
384 # Install the list of .desktop menu files into the appropriate directory
385 # (/usr/share/applications).
386 domenu() {
387         (
388         # wrap the env here so that the 'insinto' call
389         # doesn't corrupt the env of the caller
390         local i j ret=0
391         insinto /usr/share/applications
392         for i in "$@" ; do
393                 if [[ -f ${i} ]] ; then
394                         doins "${i}"
395                         ((ret+=$?))
396                 elif [[ -d ${i} ]] ; then
397                         for j in "${i}"/*.desktop ; do
398                                 doins "${j}"
399                                 ((ret+=$?))
400                         done
401                 else
402                         ((++ret))
403                 fi
404         done
405         exit ${ret}
406         )
407 }
408
409 # @FUNCTION: newmenu
410 # @USAGE: <menu> <newname>
411 # @DESCRIPTION:
412 # Like all other new* functions, install the specified menu as newname.
413 newmenu() {
414         (
415         # wrap the env here so that the 'insinto' call
416         # doesn't corrupt the env of the caller
417         insinto /usr/share/applications
418         newins "$@"
419         )
420 }
421
422 # @FUNCTION: _iconins
423 # @INTERNAL
424 # @DESCRIPTION:
425 # function for use in doicon and newicon
426 _iconins() {
427         (
428         # wrap the env here so that the 'insinto' call
429         # doesn't corrupt the env of the caller
430         local funcname=$1; shift
431         local size dir
432         local context=apps
433         local theme=hicolor
434
435         while [[ $# -gt 0 ]] ; do
436                 case $1 in
437                 -s|--size)
438                         if [[ ${2%%x*}x${2%%x*} == "$2" ]] ; then
439                                 size=${2%%x*}
440                         else
441                                 size=${2}
442                         fi
443                         case ${size} in
444                         16|22|24|32|36|48|64|72|96|128|192|256|512)
445                                 size=${size}x${size};;
446                         scalable)
447                                 ;;
448                         *)
449                                 eerror "${size} is an unsupported icon size!"
450                                 exit 1;;
451                         esac
452                         shift 2;;
453                 -t|--theme)
454                         theme=${2}
455                         shift 2;;
456                 -c|--context)
457                         context=${2}
458                         shift 2;;
459                 *)
460                         if [[ -z ${size} ]] ; then
461                                 insinto /usr/share/pixmaps
462                         else
463                                 insinto /usr/share/icons/${theme}/${size}/${context}
464                         fi
465
466                         if [[ ${funcname} == doicon ]] ; then
467                                 if [[ -f $1 ]] ; then
468                                         doins "${1}"
469                                 elif [[ -d $1 ]] ; then
470                                         shopt -s nullglob
471                                         doins "${1}"/*.{png,svg}
472                                         shopt -u nullglob
473                                 else
474                                         eerror "${1} is not a valid file/directory!"
475                                         exit 1
476                                 fi
477                         else
478                                 break
479                         fi
480                         shift 1;;
481                 esac
482         done
483         if [[ ${funcname} == newicon ]] ; then
484                 newins "$@"
485         fi
486         ) || die
487 }
488
489 # @FUNCTION: doicon
490 # @USAGE: [options] <icons>
491 # @DESCRIPTION:
492 # Install icon into the icon directory /usr/share/icons or into
493 # /usr/share/pixmaps if "--size" is not set.
494 # This is useful in conjunction with creating desktop/menu files.
495 #
496 # @CODE
497 #  options:
498 #  -s, --size
499 #    !!! must specify to install into /usr/share/icons/... !!!
500 #    size of the icon, like 48 or 48x48
501 #    supported icon sizes are:
502 #    16 22 24 32 36 48 64 72 96 128 192 256 512 scalable
503 #  -c, --context
504 #    defaults to "apps"
505 #  -t, --theme
506 #    defaults to "hicolor"
507 #
508 # icons: list of icons
509 #
510 # example 1: doicon foobar.png fuqbar.svg suckbar.png
511 # results in: insinto /usr/share/pixmaps
512 #             doins foobar.png fuqbar.svg suckbar.png
513 #
514 # example 2: doicon -s 48 foobar.png fuqbar.png blobbar.png
515 # results in: insinto /usr/share/icons/hicolor/48x48/apps
516 #             doins foobar.png fuqbar.png blobbar.png
517 # @CODE
518 doicon() {
519         _iconins ${FUNCNAME} "$@"
520 }
521
522 # @FUNCTION: newicon
523 # @USAGE: [options] <icon> <newname>
524 # @DESCRIPTION:
525 # Like doicon, install the specified icon as newname.
526 #
527 # @CODE
528 # example 1: newicon foobar.png NEWNAME.png
529 # results in: insinto /usr/share/pixmaps
530 #             newins foobar.png NEWNAME.png
531 #
532 # example 2: newicon -s 48 foobar.png NEWNAME.png
533 # results in: insinto /usr/share/icons/hicolor/48x48/apps
534 #             newins foobar.png NEWNAME.png
535 # @CODE
536 newicon() {
537         _iconins ${FUNCNAME} "$@"
538 }
539
540 # @FUNCTION: strip-linguas
541 # @USAGE: [<allow LINGUAS>|<-i|-u> <directories of .po files>]
542 # @DESCRIPTION:
543 # Make sure that LINGUAS only contains languages that
544 # a package can support.  The first form allows you to
545 # specify a list of LINGUAS.  The -i builds a list of po
546 # files found in all the directories and uses the
547 # intersection of the lists.  The -u builds a list of po
548 # files found in all the directories and uses the union
549 # of the lists.
550 strip-linguas() {
551         local ls newls nols
552         if [[ $1 == "-i" ]] || [[ $1 == "-u" ]] ; then
553                 local op=$1; shift
554                 ls=$(find "$1" -name '*.po' -exec basename {} .po ';'); shift
555                 local d f
556                 for d in "$@" ; do
557                         if [[ ${op} == "-u" ]] ; then
558                                 newls=${ls}
559                         else
560                                 newls=""
561                         fi
562                         for f in $(find "$d" -name '*.po' -exec basename {} .po ';') ; do
563                                 if [[ ${op} == "-i" ]] ; then
564                                         has ${f} ${ls} && newls="${newls} ${f}"
565                                 else
566                                         has ${f} ${ls} || newls="${newls} ${f}"
567                                 fi
568                         done
569                         ls=${newls}
570                 done
571         else
572                 ls="$@"
573         fi
574
575         nols=""
576         newls=""
577         for f in ${LINGUAS} ; do
578                 if has ${f} ${ls} ; then
579                         newls="${newls} ${f}"
580                 else
581                         nols="${nols} ${f}"
582                 fi
583         done
584         [[ -n ${nols} ]] \
585                 && einfo "Sorry, but ${PN} does not support the LINGUAS:" ${nols}
586         export LINGUAS=${newls:1}
587 }
588
589 # @FUNCTION: preserve_old_lib
590 # @USAGE: <libs to preserve> [more libs]
591 # @DESCRIPTION:
592 # These functions are useful when a lib in your package changes ABI SONAME.
593 # An example might be from libogg.so.0 to libogg.so.1.  Removing libogg.so.0
594 # would break packages that link against it.  Most people get around this
595 # by using the portage SLOT mechanism, but that is not always a relevant
596 # solution, so instead you can call this from pkg_preinst.  See also the
597 # preserve_old_lib_notify function.
598 preserve_old_lib() {
599         _eutils_eprefix_init
600         if [[ ${EBUILD_PHASE} != "preinst" ]] ; then
601                 eerror "preserve_old_lib() must be called from pkg_preinst() only"
602                 die "Invalid preserve_old_lib() usage"
603         fi
604         [[ -z $1 ]] && die "Usage: preserve_old_lib <library to preserve> [more libraries to preserve]"
605
606         # let portage worry about it
607         has preserve-libs ${FEATURES} && return 0
608
609         local lib dir
610         for lib in "$@" ; do
611                 [[ -e ${EROOT}/${lib} ]] || continue
612                 dir=${lib%/*}
613                 dodir ${dir} || die "dodir ${dir} failed"
614                 cp "${EROOT}"/${lib} "${ED}"/${lib} || die "cp ${lib} failed"
615                 touch "${ED}"/${lib}
616         done
617 }
618
619 # @FUNCTION: preserve_old_lib_notify
620 # @USAGE: <libs to notify> [more libs]
621 # @DESCRIPTION:
622 # Spit helpful messages about the libraries preserved by preserve_old_lib.
623 preserve_old_lib_notify() {
624         if [[ ${EBUILD_PHASE} != "postinst" ]] ; then
625                 eerror "preserve_old_lib_notify() must be called from pkg_postinst() only"
626                 die "Invalid preserve_old_lib_notify() usage"
627         fi
628
629         # let portage worry about it
630         has preserve-libs ${FEATURES} && return 0
631
632         _eutils_eprefix_init
633
634         local lib notice=0
635         for lib in "$@" ; do
636                 [[ -e ${EROOT}/${lib} ]] || continue
637                 if [[ ${notice} -eq 0 ]] ; then
638                         notice=1
639                         ewarn "Old versions of installed libraries were detected on your system."
640                         ewarn "In order to avoid breaking packages that depend on these old libs,"
641                         ewarn "the libraries are not being removed.  You need to run revdep-rebuild"
642                         ewarn "in order to remove these old dependencies.  If you do not have this"
643                         ewarn "helper program, simply emerge the 'gentoolkit' package."
644                         ewarn
645                 fi
646                 ewarn "  # revdep-rebuild --library '${lib}' && rm '${lib}'"
647         done
648 }
649
650 # @FUNCTION: built_with_use
651 # @USAGE: [--hidden] [--missing <action>] [-a|-o] <DEPEND ATOM> <List of USE flags>
652 # @DESCRIPTION:
653 #
654 # Deprecated: Use EAPI 2 use deps in DEPEND|RDEPEND and with has_version calls.
655 #
656 # A temporary hack until portage properly supports DEPENDing on USE
657 # flags being enabled in packages.  This will check to see if the specified
658 # DEPEND atom was built with the specified list of USE flags.  The
659 # --missing option controls the behavior if called on a package that does
660 # not actually support the defined USE flags (aka listed in IUSE).
661 # The default is to abort (call die).  The -a and -o flags control
662 # the requirements of the USE flags.  They correspond to "and" and "or"
663 # logic.  So the -a flag means all listed USE flags must be enabled
664 # while the -o flag means at least one of the listed IUSE flags must be
665 # enabled.  The --hidden option is really for internal use only as it
666 # means the USE flag we're checking is hidden expanded, so it won't be found
667 # in IUSE like normal USE flags.
668 #
669 # Remember that this function isn't terribly intelligent so order of optional
670 # flags matter.
671 built_with_use() {
672         _eutils_eprefix_init
673         local hidden="no"
674         if [[ $1 == "--hidden" ]] ; then
675                 hidden="yes"
676                 shift
677         fi
678
679         local missing_action="die"
680         if [[ $1 == "--missing" ]] ; then
681                 missing_action=$2
682                 shift ; shift
683                 case ${missing_action} in
684                         true|false|die) ;;
685                         *) die "unknown action '${missing_action}'";;
686                 esac
687         fi
688
689         local opt=$1
690         [[ ${opt:0:1} = "-" ]] && shift || opt="-a"
691
692         local PKG=$(best_version $1)
693         [[ -z ${PKG} ]] && die "Unable to resolve $1 to an installed package"
694         shift
695
696         local USEFILE=${EROOT}/var/db/pkg/${PKG}/USE
697         local IUSEFILE=${EROOT}/var/db/pkg/${PKG}/IUSE
698
699         # if the IUSE file doesn't exist, the read will error out, we need to handle
700         # this gracefully
701         if [[ ! -e ${USEFILE} ]] || [[ ! -e ${IUSEFILE} && ${hidden} == "no" ]] ; then
702                 case ${missing_action} in
703                         true)   return 0;;
704                         false)  return 1;;
705                         die)    die "Unable to determine what USE flags $PKG was built with";;
706                 esac
707         fi
708
709         if [[ ${hidden} == "no" ]] ; then
710                 local IUSE_BUILT=( $(<"${IUSEFILE}") )
711                 # Don't check USE_EXPAND #147237
712                 local expand
713                 for expand in $(echo ${USE_EXPAND} | tr '[:upper:]' '[:lower:]') ; do
714                         if [[ $1 == ${expand}_* ]] ; then
715                                 expand=""
716                                 break
717                         fi
718                 done
719                 if [[ -n ${expand} ]] ; then
720                         if ! has $1 ${IUSE_BUILT[@]#[-+]} ; then
721                                 case ${missing_action} in
722                                         true)  return 0;;
723                                         false) return 1;;
724                                         die)   die "$PKG does not actually support the $1 USE flag!";;
725                                 esac
726                         fi
727                 fi
728         fi
729
730         local USE_BUILT=$(<${USEFILE})
731         while [[ $# -gt 0 ]] ; do
732                 if [[ ${opt} = "-o" ]] ; then
733                         has $1 ${USE_BUILT} && return 0
734                 else
735                         has $1 ${USE_BUILT} || return 1
736                 fi
737                 shift
738         done
739         [[ ${opt} = "-a" ]]
740 }
741
742 # @FUNCTION: make_wrapper
743 # @USAGE: <wrapper> <target> [chdir] [libpaths] [installpath]
744 # @DESCRIPTION:
745 # Create a shell wrapper script named wrapper in installpath
746 # (defaults to the bindir) to execute target (default of wrapper) by
747 # first optionally setting LD_LIBRARY_PATH to the colon-delimited
748 # libpaths followed by optionally changing directory to chdir.
749 make_wrapper() {
750         _eutils_eprefix_init
751         local wrapper=$1 bin=$2 chdir=$3 libdir=$4 path=$5
752         local tmpwrapper=$(emktemp)
753
754         (
755         echo '#!/bin/sh'
756         [[ -n ${chdir} ]] && printf 'cd "%s"\n' "${EPREFIX}${chdir}"
757         if [[ -n ${libdir} ]] ; then
758                 local var
759                 if [[ ${CHOST} == *-darwin* ]] ; then
760                         var=DYLD_LIBRARY_PATH
761                 else
762                         var=LD_LIBRARY_PATH
763                 fi
764                 cat <<-EOF
765                         if [ "\${${var}+set}" = "set" ] ; then
766                                 export ${var}="\${${var}}:${EPREFIX}${libdir}"
767                         else
768                                 export ${var}="${EPREFIX}${libdir}"
769                         fi
770                 EOF
771         fi
772         # We don't want to quote ${bin} so that people can pass complex
773         # things as ${bin} ... "./someprog --args"
774         printf 'exec %s "$@"\n' "${bin/#\//${EPREFIX}/}"
775         ) > "${tmpwrapper}"
776         chmod go+rx "${tmpwrapper}"
777
778         if [[ -n ${path} ]] ; then
779                 (
780                 exeinto "${path}"
781                 newexe "${tmpwrapper}" "${wrapper}"
782                 ) || die
783         else
784                 newbin "${tmpwrapper}" "${wrapper}" || die
785         fi
786 }
787
788 # @FUNCTION: path_exists
789 # @USAGE: [-a|-o] <paths>
790 # @DESCRIPTION:
791 # Check if the specified paths exist.  Works for all types of paths
792 # (files/dirs/etc...).  The -a and -o flags control the requirements
793 # of the paths.  They correspond to "and" and "or" logic.  So the -a
794 # flag means all the paths must exist while the -o flag means at least
795 # one of the paths must exist.  The default behavior is "and".  If no
796 # paths are specified, then the return value is "false".
797 path_exists() {
798         local opt=$1
799         [[ ${opt} == -[ao] ]] && shift || opt="-a"
800
801         # no paths -> return false
802         # same behavior as: [[ -e "" ]]
803         [[ $# -eq 0 ]] && return 1
804
805         local p r=0
806         for p in "$@" ; do
807                 [[ -e ${p} ]]
808                 : $(( r += $? ))
809         done
810
811         case ${opt} in
812                 -a) return $(( r != 0 )) ;;
813                 -o) return $(( r == $# )) ;;
814         esac
815 }
816
817 # @FUNCTION: use_if_iuse
818 # @USAGE: <flag>
819 # @DESCRIPTION:
820 # Return true if the given flag is in USE and IUSE.
821 #
822 # Note that this function should not be used in the global scope.
823 use_if_iuse() {
824         in_iuse $1 || return 1
825         use $1
826 }
827
828 # @FUNCTION: optfeature
829 # @USAGE: <short description> <package atom to match> [other atoms]
830 # @DESCRIPTION:
831 # Print out a message suggesting an optional package (or packages) which
832 # provide the described functionality
833 #
834 # The following snippet would suggest app-misc/foo for optional foo support,
835 # app-misc/bar or app-misc/baz[bar] for optional bar support
836 # and either both app-misc/a and app-misc/b or app-misc/c for alphabet support.
837 # @CODE
838 #       optfeature "foo support" app-misc/foo
839 #       optfeature "bar support" app-misc/bar app-misc/baz[bar]
840 #       optfeature "alphabet support" "app-misc/a app-misc/b" app-misc/c
841 # @CODE
842 optfeature() {
843         debug-print-function ${FUNCNAME} "$@"
844         local i j msg
845         local desc=$1
846         local flag=0
847         shift
848         for i; do
849                 for j in ${i}; do
850                         if has_version "${j}"; then
851                                 flag=1
852                         else
853                                 flag=0
854                                 break
855                         fi
856                 done
857                 if [[ ${flag} -eq 1 ]]; then
858                         break
859                 fi
860         done
861         if [[ ${flag} -eq 0 ]]; then
862                 for i; do
863                         msg=" "
864                         for j in ${i}; do
865                                 msg+=" ${j} and"
866                         done
867                         msg="${msg:0: -4} for ${desc}"
868                         elog "${msg}"
869                 done
870         fi
871 }
872
873 check_license() {
874         die "you no longer need this as portage supports ACCEPT_LICENSE itself"
875 }
876
877 case ${EAPI:-0} in
878 0|1|2)
879
880 # @FUNCTION: epause
881 # @USAGE: [seconds]
882 # @DESCRIPTION:
883 # Sleep for the specified number of seconds (default of 5 seconds).  Useful when
884 # printing a message the user should probably be reading and often used in
885 # conjunction with the ebeep function.  If the EPAUSE_IGNORE env var is set,
886 # don't wait at all. Defined in EAPIs 0 1 and 2.
887 epause() {
888         [[ -z ${EPAUSE_IGNORE} ]] && sleep ${1:-5}
889 }
890
891 # @FUNCTION: ebeep
892 # @USAGE: [number of beeps]
893 # @DESCRIPTION:
894 # Issue the specified number of beeps (default of 5 beeps).  Useful when
895 # printing a message the user should probably be reading and often used in
896 # conjunction with the epause function.  If the EBEEP_IGNORE env var is set,
897 # don't beep at all. Defined in EAPIs 0 1 and 2.
898 ebeep() {
899         local n
900         if [[ -z ${EBEEP_IGNORE} ]] ; then
901                 for ((n=1 ; n <= ${1:-5} ; n++)) ; do
902                         echo -ne "\a"
903                         sleep 0.1 &>/dev/null ; sleep 0,1 &>/dev/null
904                         echo -ne "\a"
905                         sleep 1
906                 done
907         fi
908 }
909
910 ;;
911 *)
912
913 ebeep() {
914         ewarn "QA Notice: ebeep is not defined in EAPI=${EAPI}, please file a bug at https://bugs.gentoo.org"
915 }
916
917 epause() {
918         ewarn "QA Notice: epause is not defined in EAPI=${EAPI}, please file a bug at https://bugs.gentoo.org"
919 }
920
921 ;;
922 esac
923
924 case ${EAPI:-0} in
925 0|1|2|3|4)
926
927 # @FUNCTION: usex
928 # @USAGE: <USE flag> [true output] [false output] [true suffix] [false suffix]
929 # @DESCRIPTION:
930 # Proxy to declare usex for package managers or EAPIs that do not provide it
931 # and use the package manager implementation when available (i.e. EAPI >= 5).
932 # If USE flag is set, echo [true output][true suffix] (defaults to "yes"),
933 # otherwise echo [false output][false suffix] (defaults to "no").
934 usex() { use "$1" && echo "${2-yes}$4" || echo "${3-no}$5" ; } #382963
935
936 ;;
937 esac
938
939 case ${EAPI:-0} in
940 0|1|2|3|4|5)
941
942 # @FUNCTION: einstalldocs
943 # @DESCRIPTION:
944 # Install documentation using DOCS and HTML_DOCS.
945 #
946 # If DOCS is declared and non-empty, all files listed in it are
947 # installed. The files must exist, otherwise the function will fail.
948 # In EAPI 4 and subsequent EAPIs DOCS may specify directories as well,
949 # in other EAPIs using directories is unsupported.
950 #
951 # If DOCS is not declared, the files matching patterns given
952 # in the default EAPI implementation of src_install will be installed.
953 # If this is undesired, DOCS can be set to empty value to prevent any
954 # documentation from being installed.
955 #
956 # If HTML_DOCS is declared and non-empty, all files and/or directories
957 # listed in it are installed as HTML docs (using dohtml).
958 #
959 # Both DOCS and HTML_DOCS can either be an array or a whitespace-
960 # separated list. Whenever directories are allowed, '<directory>/.' may
961 # be specified in order to install all files within the directory
962 # without creating a sub-directory in docdir.
963 #
964 # Passing additional options to dodoc and dohtml is not supported.
965 # If you needed such a thing, you need to call those helpers explicitly.
966 einstalldocs() {
967         debug-print-function ${FUNCNAME} "${@}"
968
969         local dodoc_opts=-r
970         has ${EAPI} 0 1 2 3 && dodoc_opts=
971
972         if ! declare -p DOCS &>/dev/null ; then
973                 local d
974                 for d in README* ChangeLog AUTHORS NEWS TODO CHANGES \
975                                 THANKS BUGS FAQ CREDITS CHANGELOG ; do
976                         if [[ -s ${d} ]] ; then
977                                 dodoc "${d}" || die
978                         fi
979                 done
980         elif [[ $(declare -p DOCS) == "declare -a"* ]] ; then
981                 if [[ ${DOCS[@]} ]] ; then
982                         dodoc ${dodoc_opts} "${DOCS[@]}" || die
983                 fi
984         else
985                 if [[ ${DOCS} ]] ; then
986                         dodoc ${dodoc_opts} ${DOCS} || die
987                 fi
988         fi
989
990         if [[ $(declare -p HTML_DOCS 2>/dev/null) == "declare -a"* ]] ; then
991                 if [[ ${HTML_DOCS[@]} ]] ; then
992                         dohtml -r "${HTML_DOCS[@]}" || die
993                 fi
994         else
995                 if [[ ${HTML_DOCS} ]] ; then
996                         dohtml -r ${HTML_DOCS} || die
997                 fi
998         fi
999
1000         return 0
1001 }
1002
1003 # @FUNCTION: in_iuse
1004 # @USAGE: <flag>
1005 # @DESCRIPTION:
1006 # Determines whether the given flag is in IUSE. Strips IUSE default prefixes
1007 # as necessary.
1008 #
1009 # Note that this function should not be used in the global scope.
1010 in_iuse() {
1011         debug-print-function ${FUNCNAME} "${@}"
1012         [[ ${#} -eq 1 ]] || die "Invalid args to ${FUNCNAME}()"
1013
1014         local flag=${1}
1015         local liuse=( ${IUSE} )
1016
1017         has "${flag}" "${liuse[@]#[+-]}"
1018 }
1019
1020 ;;
1021 esac
1022
1023 fi