meson.eclass: Don't mix host *FLAGS with build *FLAGS
[gentoo.git] / eclass / check-reqs.eclass
1 # Copyright 1999-2018 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 # @ECLASS-VARIABLE: CHECKREQS_MEMORY
43 # @DEFAULT_UNSET
44 # @DESCRIPTION:
45 # How much RAM is needed? Eg.: CHECKREQS_MEMORY=15M
46
47 # @ECLASS-VARIABLE:  CHECKREQS_DISK_BUILD
48 # @DEFAULT_UNSET
49 # @DESCRIPTION:
50 # How much diskspace is needed to build the package? Eg.: CHECKREQS_DISK_BUILD=2T
51
52 # @ECLASS-VARIABLE: CHECKREQS_DISK_USR
53 # @DEFAULT_UNSET
54 # @DESCRIPTION:
55 # How much space in /usr is needed to install the package? Eg.: CHECKREQS_DISK_USR=15G
56
57 # @ECLASS-VARIABLE: CHECKREQS_DISK_VAR
58 # @DEFAULT_UNSET
59 # @DESCRIPTION:
60 # How much space is needed in /var? Eg.: CHECKREQS_DISK_VAR=3000M
61
62 EXPORT_FUNCTIONS pkg_setup
63 case "${EAPI:-0}" in
64         0|1|2|3) ;;
65         4|5|6) EXPORT_FUNCTIONS pkg_pretend ;;
66         *) die "EAPI=${EAPI} is not supported" ;;
67 esac
68
69 # Obsolete function executing all the checks and printing out results
70 check_reqs() {
71         eerror "Package calling old ${FUNCNAME} function."
72         eerror "It should call check-reqs_pkg_pretend and check-reqs_pkg_setup."
73         die "${FUNCNAME} is banned"
74 }
75
76 # @FUNCTION: check-reqs_pkg_setup
77 # @DESCRIPTION:
78 # Exported function running the resources checks in pkg_setup phase.
79 # It should be run in both phases to ensure condition changes between
80 # pkg_pretend and pkg_setup won't affect the build.
81 check-reqs_pkg_setup() {
82         debug-print-function ${FUNCNAME} "$@"
83
84         check-reqs_prepare
85         check-reqs_run
86         check-reqs_output
87 }
88
89 # @FUNCTION: check-reqs_pkg_pretend
90 # @DESCRIPTION:
91 # Exported function running the resources checks in pkg_pretend phase.
92 check-reqs_pkg_pretend() {
93         debug-print-function ${FUNCNAME} "$@"
94
95         check-reqs_pkg_setup "$@"
96 }
97
98 # @FUNCTION: check-reqs_prepare
99 # @INTERNAL
100 # @DESCRIPTION:
101 # Internal function that checks the variables that should be defined.
102 check-reqs_prepare() {
103         debug-print-function ${FUNCNAME} "$@"
104
105         if [[ -z ${CHECKREQS_MEMORY} &&
106                         -z ${CHECKREQS_DISK_BUILD} &&
107                         -z ${CHECKREQS_DISK_USR} &&
108                         -z ${CHECKREQS_DISK_VAR} ]]; then
109                 eerror "Set some check-reqs eclass variables if you want to use it."
110                 eerror "If you are user and see this message file a bug against the package."
111                 die "${FUNCNAME}: check-reqs eclass called but not actualy used!"
112         fi
113 }
114
115 # @FUNCTION: check-reqs_run
116 # @INTERNAL
117 # @DESCRIPTION:
118 # Internal function that runs the check based on variable settings.
119 check-reqs_run() {
120         debug-print-function ${FUNCNAME} "$@"
121
122         # some people are *censored*
123         unset CHECKREQS_FAILED
124
125         [[ ${EAPI:-0} == [0123] ]] && local MERGE_TYPE=""
126
127         # use != in test, because MERGE_TYPE only exists in EAPI 4 and later
128         if [[ ${MERGE_TYPE} != binary ]]; then
129                 [[ -n ${CHECKREQS_MEMORY} ]] && \
130                         check-reqs_memory \
131                                 ${CHECKREQS_MEMORY}
132
133                 [[ -n ${CHECKREQS_DISK_BUILD} ]] && \
134                         check-reqs_disk \
135                                 "${T}" \
136                                 "${CHECKREQS_DISK_BUILD}"
137         fi
138
139         if [[ ${MERGE_TYPE} != buildonly ]]; then
140                 [[ -n ${CHECKREQS_DISK_USR} ]] && \
141                         check-reqs_disk \
142                                 "${EROOT}/usr" \
143                                 "${CHECKREQS_DISK_USR}"
144
145                 [[ -n ${CHECKREQS_DISK_VAR} ]] && \
146                         check-reqs_disk \
147                                 "${EROOT}/var" \
148                                 "${CHECKREQS_DISK_VAR}"
149         fi
150 }
151
152 # @FUNCTION: check-reqs_get_kibibytes
153 # @INTERNAL
154 # @DESCRIPTION:
155 # Internal function that returns number in KiB.
156 # Returns 1024**2 for 1G or 1024**3 for 1T.
157 check-reqs_get_kibibytes() {
158         debug-print-function ${FUNCNAME} "$@"
159
160         [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
161
162         local unit=${1:(-1)}
163         local size=${1%[GMT]}
164
165         case ${unit} in
166                 M) echo $((1024 * size)) ;;
167                 G) echo $((1024 * 1024 * size)) ;;
168                 T) echo $((1024 * 1024 * 1024 * size)) ;;
169                 *)
170                         die "${FUNCNAME}: Unknown unit: ${unit}"
171                 ;;
172         esac
173 }
174
175 # @FUNCTION: check-reqs_get_number
176 # @INTERNAL
177 # @DESCRIPTION:
178 # Internal function that returns the numerical value without the unit.
179 # Returns "1" for "1G" or "150" for "150T".
180 check-reqs_get_number() {
181         debug-print-function ${FUNCNAME} "$@"
182
183         [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
184
185         local size=${1%[GMT]}
186         [[ ${size} == ${1} ]] && die "${FUNCNAME}: Missing unit: ${1}"
187
188         echo ${size}
189 }
190
191 # @FUNCTION: check-reqs_get_unit
192 # @INTERNAL
193 # @DESCRIPTION:
194 # Internal function that returns the unit without the numerical value.
195 # Returns "GiB" for "1G" or "TiB" for "150T".
196 check-reqs_get_unit() {
197         debug-print-function ${FUNCNAME} "$@"
198
199         [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
200
201         local unit=${1:(-1)}
202
203         case ${unit} in
204                 M) echo "MiB" ;;
205                 G) echo "GiB" ;;
206                 T) echo "TiB" ;;
207                 *)
208                         die "${FUNCNAME}: Unknown unit: ${unit}"
209                 ;;
210         esac
211 }
212
213 # @FUNCTION: check-reqs_output
214 # @INTERNAL
215 # @DESCRIPTION:
216 # Internal function that prints the warning and dies if required based on
217 # the test results.
218 check-reqs_output() {
219         debug-print-function ${FUNCNAME} "$@"
220
221         local msg="ewarn"
222
223         [[ ${EBUILD_PHASE} == "pretend" && -z ${I_KNOW_WHAT_I_AM_DOING} ]] && msg="eerror"
224         if [[ -n ${CHECKREQS_FAILED} ]]; then
225                 ${msg}
226                 ${msg} "Space constraints set in the ebuild were not met!"
227                 ${msg} "The build will most probably fail, you should enhance the space"
228                 ${msg} "as per failed tests."
229                 ${msg}
230
231                 [[ ${EBUILD_PHASE} == "pretend" && -z ${I_KNOW_WHAT_I_AM_DOING} ]] && \
232                         die "Build requirements not met!"
233         fi
234 }
235
236 # @FUNCTION: check-reqs_memory
237 # @INTERNAL
238 # @DESCRIPTION:
239 # Internal function that checks size of RAM.
240 check-reqs_memory() {
241         debug-print-function ${FUNCNAME} "$@"
242
243         [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
244
245         local size=${1}
246         local actual_memory
247
248         check-reqs_start_phase \
249                 ${size} \
250                 "RAM"
251
252         if [[ -r /proc/meminfo ]] ; then
253                 actual_memory=$(awk '/MemTotal/ { print $2 }' /proc/meminfo)
254         else
255                 actual_memory=$(sysctl hw.physmem 2>/dev/null )
256                 [[ "$?" == "0" ]] &&
257                         actual_memory=$(echo $actual_memory | sed -e 's/^[^:=]*[:=]//' )
258         fi
259         if [[ -n ${actual_memory} ]] ; then
260                 if [[ ${actual_memory} -lt $(check-reqs_get_kibibytes ${size}) ]] ; then
261                         eend 1
262                         check-reqs_unsatisfied \
263                                 ${size} \
264                                 "RAM"
265                 else
266                         eend 0
267                 fi
268         else
269                 eend 1
270                 ewarn "Couldn't determine amount of memory, skipping..."
271         fi
272 }
273
274 # @FUNCTION: check-reqs_disk
275 # @INTERNAL
276 # @DESCRIPTION:
277 # Internal function that checks space on the harddrive.
278 check-reqs_disk() {
279         debug-print-function ${FUNCNAME} "$@"
280
281         [[ -z ${2} ]] && die "Usage: ${FUNCNAME} [path] [size]"
282
283         local path=${1}
284         local size=${2}
285         local space_kbi
286
287         check-reqs_start_phase \
288                 ${size} \
289                 "disk space at \"${path}\""
290
291         space_kbi=$(df -Pk "${1}" 2>/dev/null | awk 'FNR == 2 {print $4}')
292
293         if [[ $? == 0 && -n ${space_kbi} ]] ; then
294                 if [[ ${space_kbi} -lt $(check-reqs_get_kibibytes ${size}) ]] ; then
295                         eend 1
296                         check-reqs_unsatisfied \
297                                 ${size} \
298                                 "disk space at \"${path}\""
299                 else
300                         eend 0
301                 fi
302         else
303                 eend 1
304                 ewarn "Couldn't determine disk space, skipping..."
305         fi
306 }
307
308 # @FUNCTION: check-reqs_start_phase
309 # @INTERNAL
310 # @DESCRIPTION:
311 # Internal function that inform about started check
312 check-reqs_start_phase() {
313         debug-print-function ${FUNCNAME} "$@"
314
315         [[ -z ${2} ]] && die "Usage: ${FUNCNAME} [size] [location]"
316
317         local size=${1}
318         local location=${2}
319         local sizeunit="$(check-reqs_get_number ${size}) $(check-reqs_get_unit ${size})"
320
321         ebegin "Checking for at least ${sizeunit} ${location}"
322 }
323
324 # @FUNCTION: check-reqs_unsatisfied
325 # @INTERNAL
326 # @DESCRIPTION:
327 # Internal function that inform about check result.
328 # It has different output between pretend and setup phase,
329 # where in pretend phase it is fatal.
330 check-reqs_unsatisfied() {
331         debug-print-function ${FUNCNAME} "$@"
332
333         [[ -z ${2} ]] && die "Usage: ${FUNCNAME} [size] [location]"
334
335         local msg="ewarn"
336         local size=${1}
337         local location=${2}
338         local sizeunit="$(check-reqs_get_number ${size}) $(check-reqs_get_unit ${size})"
339
340         [[ ${EBUILD_PHASE} == "pretend" && -z ${I_KNOW_WHAT_I_AM_DOING} ]] && msg="eerror"
341         ${msg} "There is NOT at least ${sizeunit} ${location}"
342
343         # @ECLASS-VARIABLE: CHECKREQS_FAILED
344         # @DESCRIPTION:
345         # @INTERNAL
346         # If set the checks failed and eclass should abort the build.
347         # Internal, do not set yourself.
348         CHECKREQS_FAILED="true"
349 }
350
351 _CHECK_REQS_ECLASS_=1
352 fi