kde5.eclass: Cleanup obsolete blocker
[gentoo.git] / eclass / check-reqs.eclass
1 # Copyright 1999-2017 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 # @ECLASS: check-reqs.eclass
5 # @MAINTAINER:
6 # QA Team <qa@gentoo.org>
7 # @AUTHOR:
8 # Bo Ørsted Andresen <zlin@gentoo.org>
9 # Original Author: Ciaran McCreesh <ciaranm@gentoo.org>
10 # @BLURB: Provides a uniform way of handling ebuild which have very high build requirements
11 # @DESCRIPTION:
12 # This eclass provides a uniform way of handling ebuilds which have very high
13 # build requirements in terms of memory or disk space. It provides a function
14 # which should usually be called during pkg_setup().
15 #
16 # The chosen action only happens when the system's resources are detected
17 # correctly and only if they are below the threshold specified by the package.
18 #
19 # @CODE
20 # # need this much memory (does *not* check swap)
21 # CHECKREQS_MEMORY="256M"
22 #
23 # # need this much temporary build space
24 # CHECKREQS_DISK_BUILD="2G"
25 #
26 # # install will need this much space in /usr
27 # CHECKREQS_DISK_USR="1G"
28 #
29 # # install will need this much space in /var
30 # CHECKREQS_DISK_VAR="1024M"
31 #
32 # @CODE
33 #
34 # If you don't specify a value for, say, CHECKREQS_MEMORY, then the test is not
35 # carried out.
36 #
37 # These checks should probably mostly work on non-Linux, and they should
38 # probably degrade gracefully if they don't. Probably.
39
40 if [[ ! ${_CHECK_REQS_ECLASS_} ]]; then
41
42 inherit eutils
43
44 # @ECLASS-VARIABLE: CHECKREQS_MEMORY
45 # @DEFAULT_UNSET
46 # @DESCRIPTION:
47 # How much RAM is needed? Eg.: CHECKREQS_MEMORY=15M
48
49 # @ECLASS-VARIABLE:  CHECKREQS_DISK_BUILD
50 # @DEFAULT_UNSET
51 # @DESCRIPTION:
52 # How much diskspace is needed to build the package? Eg.: CHECKREQS_DISK_BUILD=2T
53
54 # @ECLASS-VARIABLE: CHECKREQS_DISK_USR
55 # @DEFAULT_UNSET
56 # @DESCRIPTION:
57 # How much space in /usr is needed to install the package? Eg.: CHECKREQS_DISK_USR=15G
58
59 # @ECLASS-VARIABLE: CHECKREQS_DISK_VAR
60 # @DEFAULT_UNSET
61 # @DESCRIPTION:
62 # How much space is needed in /var? Eg.: CHECKREQS_DISK_VAR=3000M
63
64 EXPORT_FUNCTIONS pkg_setup
65 case "${EAPI:-0}" in
66         0|1|2|3) ;;
67         4|5|6) EXPORT_FUNCTIONS pkg_pretend ;;
68         *) die "EAPI=${EAPI} is not supported" ;;
69 esac
70
71 # @FUNCTION: check_reqs
72 # @DESCRIPTION:
73 # Obsolete function executing all the checks and printing out results
74 check_reqs() {
75         debug-print-function ${FUNCNAME} "$@"
76
77         [[ ${EAPI:-0} == [012345] ]] || die "${FUNCNAME} is banned in EAPI > 5"
78
79         echo
80         eqawarn "Package calling old ${FUNCNAME} function."
81         eqawarn "Please file a bug against the package."
82         eqawarn "It should call check-reqs_pkg_pretend and check-reqs_pkg_setup"
83         eqawarn "and possibly use EAPI=4 or later."
84         echo
85
86         check-reqs_pkg_setup "$@"
87 }
88
89 # @FUNCTION: check-reqs_pkg_setup
90 # @DESCRIPTION:
91 # Exported function running the resources checks in pkg_setup phase.
92 # It should be run in both phases to ensure condition changes between
93 # pkg_pretend and pkg_setup won't affect the build.
94 check-reqs_pkg_setup() {
95         debug-print-function ${FUNCNAME} "$@"
96
97         check-reqs_prepare
98         check-reqs_run
99         check-reqs_output
100 }
101
102 # @FUNCTION: check-reqs_pkg_pretend
103 # @DESCRIPTION:
104 # Exported function running the resources checks in pkg_pretend phase.
105 check-reqs_pkg_pretend() {
106         debug-print-function ${FUNCNAME} "$@"
107
108         check-reqs_pkg_setup "$@"
109 }
110
111 # @FUNCTION: check-reqs_prepare
112 # @INTERNAL
113 # @DESCRIPTION:
114 # Internal function that checks the variables that should be defined.
115 check-reqs_prepare() {
116         debug-print-function ${FUNCNAME} "$@"
117
118         if [[ -z ${CHECKREQS_MEMORY} &&
119                         -z ${CHECKREQS_DISK_BUILD} &&
120                         -z ${CHECKREQS_DISK_USR} &&
121                         -z ${CHECKREQS_DISK_VAR} ]]; then
122                 eerror "Set some check-reqs eclass variables if you want to use it."
123                 eerror "If you are user and see this message file a bug against the package."
124                 die "${FUNCNAME}: check-reqs eclass called but not actualy used!"
125         fi
126 }
127
128 # @FUNCTION: check-reqs_run
129 # @INTERNAL
130 # @DESCRIPTION:
131 # Internal function that runs the check based on variable settings.
132 check-reqs_run() {
133         debug-print-function ${FUNCNAME} "$@"
134
135         # some people are *censored*
136         unset CHECKREQS_FAILED
137
138         [[ ${EAPI:-0} == [0123] ]] && local MERGE_TYPE=""
139
140         # use != in test, because MERGE_TYPE only exists in EAPI 4 and later
141         if [[ ${MERGE_TYPE} != binary ]]; then
142                 [[ -n ${CHECKREQS_MEMORY} ]] && \
143                         check-reqs_memory \
144                                 ${CHECKREQS_MEMORY}
145
146                 [[ -n ${CHECKREQS_DISK_BUILD} ]] && \
147                         check-reqs_disk \
148                                 "${T}" \
149                                 "${CHECKREQS_DISK_BUILD}"
150         fi
151
152         if [[ ${MERGE_TYPE} != buildonly ]]; then
153                 [[ -n ${CHECKREQS_DISK_USR} ]] && \
154                         check-reqs_disk \
155                                 "${EROOT}/usr" \
156                                 "${CHECKREQS_DISK_USR}"
157
158                 [[ -n ${CHECKREQS_DISK_VAR} ]] && \
159                         check-reqs_disk \
160                                 "${EROOT}/var" \
161                                 "${CHECKREQS_DISK_VAR}"
162         fi
163 }
164
165 # @FUNCTION: check-reqs_get_kibibytes
166 # @INTERNAL
167 # @DESCRIPTION:
168 # Internal function that returns number in KiB.
169 # Returns 1024**2 for 1G or 1024**3 for 1T.
170 check-reqs_get_kibibytes() {
171         debug-print-function ${FUNCNAME} "$@"
172
173         [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
174
175         local unit=${1:(-1)}
176         local size=${1%[GMT]}
177
178         case ${unit} in
179                 G) echo $((1024 * 1024 * size)) ;;
180                 M) echo $((1024 * size)) ;;
181                 T) echo $((1024 * 1024 * 1024 * size)) ;;
182                 [0-9]) echo $((1024 * size)) ;;
183                 *)
184                         die "${FUNCNAME}: Unknown unit: ${unit}"
185                 ;;
186         esac
187 }
188
189 # @FUNCTION: check-reqs_get_number
190 # @INTERNAL
191 # @DESCRIPTION:
192 # Internal function that returns the numerical value without the unit.
193 # Returns "1" for "1G" or "150" for "150T".
194 check-reqs_get_number() {
195         debug-print-function ${FUNCNAME} "$@"
196
197         [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
198
199         local unit=${1:(-1)}
200         local size=${1%[GMT]}
201         local msg=eerror
202         [[ ${EAPI:-0} == [012345] ]] && msg=eqawarn
203
204         # Check for unset units and warn about them.
205         # Backcompat.
206         if [[ ${size} == ${1} ]]; then
207                 ${msg} "Package does not specify unit for the size check"
208                 ${msg} "File bug against the package. It should specify the unit."
209         fi
210
211         echo ${size}
212 }
213
214 # @FUNCTION: check-reqs_get_unit
215 # @INTERNAL
216 # @DESCRIPTION:
217 # Internal function that returns the unit without the numerical value.
218 # Returns "GiB" for "1G" or "TiB" for "150T".
219 check-reqs_get_unit() {
220         debug-print-function ${FUNCNAME} "$@"
221
222         [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
223
224         local unit=${1:(-1)}
225
226         case ${unit} in
227                 G) echo "GiB" ;;
228                 [M0-9]) echo "MiB" ;;
229                 T) echo "TiB" ;;
230                 *)
231                         die "${FUNCNAME}: Unknown unit: ${unit}"
232                 ;;
233         esac
234 }
235
236 # @FUNCTION: check-reqs_output
237 # @INTERNAL
238 # @DESCRIPTION:
239 # Internal function that prints the warning and dies if required based on
240 # the test results.
241 check-reqs_output() {
242         debug-print-function ${FUNCNAME} "$@"
243
244         local msg="ewarn"
245
246         [[ ${EBUILD_PHASE} == "pretend" && -z ${I_KNOW_WHAT_I_AM_DOING} ]] && msg="eerror"
247         if [[ -n ${CHECKREQS_FAILED} ]]; then
248                 ${msg}
249                 ${msg} "Space constraints set in the ebuild were not met!"
250                 ${msg} "The build will most probably fail, you should enhance the space"
251                 ${msg} "as per failed tests."
252                 ${msg}
253
254                 [[ ${EBUILD_PHASE} == "pretend" && -z ${I_KNOW_WHAT_I_AM_DOING} ]] && \
255                         die "Build requirements not met!"
256         fi
257 }
258
259 # @FUNCTION: check-reqs_memory
260 # @INTERNAL
261 # @DESCRIPTION:
262 # Internal function that checks size of RAM.
263 check-reqs_memory() {
264         debug-print-function ${FUNCNAME} "$@"
265
266         [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
267
268         local size=${1}
269         local actual_memory
270
271         check-reqs_start_phase \
272                 ${size} \
273                 "RAM"
274
275         if [[ -r /proc/meminfo ]] ; then
276                 actual_memory=$(awk '/MemTotal/ { print $2 }' /proc/meminfo)
277         else
278                 actual_memory=$(sysctl hw.physmem 2>/dev/null )
279                 [[ "$?" == "0" ]] &&
280                         actual_memory=$(echo $actual_memory | sed -e 's/^[^:=]*[:=]//' )
281         fi
282         if [[ -n ${actual_memory} ]] ; then
283                 if [[ ${actual_memory} -lt $(check-reqs_get_kibibytes ${size}) ]] ; then
284                         eend 1
285                         check-reqs_unsatisfied \
286                                 ${size} \
287                                 "RAM"
288                 else
289                         eend 0
290                 fi
291         else
292                 eend 1
293                 ewarn "Couldn't determine amount of memory, skipping..."
294         fi
295 }
296
297 # @FUNCTION: check-reqs_disk
298 # @INTERNAL
299 # @DESCRIPTION:
300 # Internal function that checks space on the harddrive.
301 check-reqs_disk() {
302         debug-print-function ${FUNCNAME} "$@"
303
304         [[ -z ${2} ]] && die "Usage: ${FUNCNAME} [path] [size]"
305
306         local path=${1}
307         local size=${2}
308         local space_kbi
309
310         check-reqs_start_phase \
311                 ${size} \
312                 "disk space at \"${path}\""
313
314         space_kbi=$(df -Pk "${1}" 2>/dev/null | awk 'FNR == 2 {print $4}')
315
316         if [[ $? == 0 && -n ${space_kbi} ]] ; then
317                 if [[ ${space_kbi} -lt $(check-reqs_get_kibibytes ${size}) ]] ; then
318                         eend 1
319                         check-reqs_unsatisfied \
320                                 ${size} \
321                                 "disk space at \"${path}\""
322                 else
323                         eend 0
324                 fi
325         else
326                 eend 1
327                 ewarn "Couldn't determine disk space, skipping..."
328         fi
329 }
330
331 # @FUNCTION: check-reqs_start_phase
332 # @INTERNAL
333 # @DESCRIPTION:
334 # Internal function that inform about started check
335 check-reqs_start_phase() {
336         debug-print-function ${FUNCNAME} "$@"
337
338         [[ -z ${2} ]] && die "Usage: ${FUNCNAME} [size] [location]"
339
340         local size=${1}
341         local location=${2}
342         local sizeunit="$(check-reqs_get_number ${size}) $(check-reqs_get_unit ${size})"
343
344         ebegin "Checking for at least ${sizeunit} ${location}"
345 }
346
347 # @FUNCTION: check-reqs_unsatisfied
348 # @INTERNAL
349 # @DESCRIPTION:
350 # Internal function that inform about check result.
351 # It has different output between pretend and setup phase,
352 # where in pretend phase it is fatal.
353 check-reqs_unsatisfied() {
354         debug-print-function ${FUNCNAME} "$@"
355
356         [[ -z ${2} ]] && die "Usage: ${FUNCNAME} [size] [location]"
357
358         local msg="ewarn"
359         local size=${1}
360         local location=${2}
361         local sizeunit="$(check-reqs_get_number ${size}) $(check-reqs_get_unit ${size})"
362
363         [[ ${EBUILD_PHASE} == "pretend" && -z ${I_KNOW_WHAT_I_AM_DOING} ]] && msg="eerror"
364         ${msg} "There is NOT at least ${sizeunit} ${location}"
365
366         # @ECLASS-VARIABLE: CHECKREQS_FAILED
367         # @DESCRIPTION:
368         # @INTERNAL
369         # If set the checks failed and eclass should abort the build.
370         # Internal, do not set yourself.
371         CHECKREQS_FAILED="true"
372 }
373
374 _CHECK_REQS_ECLASS_=1
375 fi