1 # Copyright 2004-2019 Gentoo Authors
2 # Distributed under the terms of the GNU General Public License v2
4 # @ECLASS: check-reqs.eclass
6 # QA Team <qa@gentoo.org>
8 # Bo Ørsted Andresen <zlin@gentoo.org>
9 # Original Author: Ciaran McCreesh <ciaranm@gentoo.org>
10 # @SUPPORTED_EAPIS: 4 5 6 7
11 # @BLURB: Provides a uniform way of handling ebuild which have very high build requirements
13 # This eclass provides a uniform way of handling ebuilds which have very high
14 # build requirements in terms of memory or disk space. It provides a function
15 # which should usually be called during pkg_setup().
17 # The chosen action only happens when the system's resources are detected
18 # correctly and only if they are below the threshold specified by the package.
21 # # need this much memory (does *not* check swap)
22 # CHECKREQS_MEMORY="256M"
24 # # need this much temporary build space
25 # CHECKREQS_DISK_BUILD="2G"
27 # # install will need this much space in /usr
28 # CHECKREQS_DISK_USR="1G"
30 # # install will need this much space in /var
31 # CHECKREQS_DISK_VAR="1024M"
35 # If you don't specify a value for, say, CHECKREQS_MEMORY, then the test is not
38 # These checks should probably mostly work on non-Linux, and they should
39 # probably degrade gracefully if they don't. Probably.
41 if [[ ! ${_CHECK_REQS_ECLASS_} ]]; then
43 # @ECLASS-VARIABLE: CHECKREQS_MEMORY
46 # How much RAM is needed? Eg.: CHECKREQS_MEMORY=15M
48 # @ECLASS-VARIABLE: CHECKREQS_DISK_BUILD
51 # How much diskspace is needed to build the package? Eg.: CHECKREQS_DISK_BUILD=2T
53 # @ECLASS-VARIABLE: CHECKREQS_DISK_USR
56 # How much space in /usr is needed to install the package? Eg.: CHECKREQS_DISK_USR=15G
58 # @ECLASS-VARIABLE: CHECKREQS_DISK_VAR
61 # How much space is needed in /var? Eg.: CHECKREQS_DISK_VAR=3000M
65 *) die "${ECLASS}: EAPI=${EAPI:-0} is not supported" ;;
68 EXPORT_FUNCTIONS pkg_pretend pkg_setup
70 # Obsolete function executing all the checks and printing out results
72 eerror "Package calling old ${FUNCNAME} function."
73 eerror "It should call check-reqs_pkg_pretend and check-reqs_pkg_setup."
74 die "${FUNCNAME} is banned"
77 # @FUNCTION: check-reqs_pkg_setup
79 # Exported function running the resources checks in pkg_setup phase.
80 # It should be run in both phases to ensure condition changes between
81 # pkg_pretend and pkg_setup won't affect the build.
82 check-reqs_pkg_setup() {
83 debug-print-function ${FUNCNAME} "$@"
90 # @FUNCTION: check-reqs_pkg_pretend
92 # Exported function running the resources checks in pkg_pretend phase.
93 check-reqs_pkg_pretend() {
94 debug-print-function ${FUNCNAME} "$@"
96 check-reqs_pkg_setup "$@"
99 # @FUNCTION: check-reqs_prepare
102 # Internal function that checks the variables that should be defined.
103 check-reqs_prepare() {
104 debug-print-function ${FUNCNAME} "$@"
106 if [[ -z ${CHECKREQS_MEMORY} &&
107 -z ${CHECKREQS_DISK_BUILD} &&
108 -z ${CHECKREQS_DISK_USR} &&
109 -z ${CHECKREQS_DISK_VAR} ]]; then
110 eerror "Set some check-reqs eclass variables if you want to use it."
111 eerror "If you are user and see this message file a bug against the package."
112 die "${FUNCNAME}: check-reqs eclass called but not actualy used!"
116 # @FUNCTION: check-reqs_run
119 # Internal function that runs the check based on variable settings.
121 debug-print-function ${FUNCNAME} "$@"
123 # some people are *censored*
124 unset CHECKREQS_FAILED
126 if [[ ${MERGE_TYPE} != binary ]]; then
127 [[ -n ${CHECKREQS_MEMORY} ]] && \
131 [[ -n ${CHECKREQS_DISK_BUILD} ]] && \
134 "${CHECKREQS_DISK_BUILD}"
137 if [[ ${MERGE_TYPE} != buildonly ]]; then
138 [[ -n ${CHECKREQS_DISK_USR} ]] && \
141 "${CHECKREQS_DISK_USR}"
143 [[ -n ${CHECKREQS_DISK_VAR} ]] && \
146 "${CHECKREQS_DISK_VAR}"
150 # @FUNCTION: check-reqs_get_kibibytes
153 # Internal function that returns number in KiB.
154 # Returns 1024**2 for 1G or 1024**3 for 1T.
155 check-reqs_get_kibibytes() {
156 debug-print-function ${FUNCNAME} "$@"
158 [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
161 local size=${1%[GMT]}
164 M) echo $((1024 * size)) ;;
165 G) echo $((1024 * 1024 * size)) ;;
166 T) echo $((1024 * 1024 * 1024 * size)) ;;
168 die "${FUNCNAME}: Unknown unit: ${unit}"
173 # @FUNCTION: check-reqs_get_number
176 # Internal function that returns the numerical value without the unit.
177 # Returns "1" for "1G" or "150" for "150T".
178 check-reqs_get_number() {
179 debug-print-function ${FUNCNAME} "$@"
181 [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
183 local size=${1%[GMT]}
184 [[ ${size} == ${1} ]] && die "${FUNCNAME}: Missing unit: ${1}"
189 # @FUNCTION: check-reqs_get_unit
192 # Internal function that returns the unit without the numerical value.
193 # Returns "GiB" for "1G" or "TiB" for "150T".
194 check-reqs_get_unit() {
195 debug-print-function ${FUNCNAME} "$@"
197 [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
206 die "${FUNCNAME}: Unknown unit: ${unit}"
211 # @FUNCTION: check-reqs_output
214 # Internal function that prints the warning and dies if required based on
216 check-reqs_output() {
217 debug-print-function ${FUNCNAME} "$@"
221 [[ ${EBUILD_PHASE} == "pretend" && -z ${I_KNOW_WHAT_I_AM_DOING} ]] && msg="eerror"
222 if [[ -n ${CHECKREQS_FAILED} ]]; then
224 ${msg} "Space constraints set in the ebuild were not met!"
225 ${msg} "The build will most probably fail, you should enhance the space"
226 ${msg} "as per failed tests."
229 [[ ${EBUILD_PHASE} == "pretend" && -z ${I_KNOW_WHAT_I_AM_DOING} ]] && \
230 die "Build requirements not met!"
234 # @FUNCTION: check-reqs_memory
237 # Internal function that checks size of RAM.
238 check-reqs_memory() {
239 debug-print-function ${FUNCNAME} "$@"
241 [[ -z ${1} ]] && die "Usage: ${FUNCNAME} [size]"
247 check-reqs_start_phase \
251 if [[ -r /proc/meminfo ]] ; then
252 actual_memory=$(awk '/MemTotal/ { print $2 }' /proc/meminfo)
253 actual_swap=$(awk '/SwapTotal/ { print $2 }' /proc/meminfo)
255 actual_memory=$(sysctl hw.physmem 2>/dev/null)
256 [[ $? -eq 0 ]] && actual_memory=$(echo "${actual_memory}" \
257 | sed -e 's/^[^:=]*[:=][[:space:]]*//')
258 actual_swap=$(sysctl vm.swap_total 2>/dev/null)
259 [[ $? -eq 0 ]] && actual_swap=$(echo "${actual_swap}" \
260 | sed -e 's/^[^:=]*[:=][[:space:]]*//')
262 if [[ -n ${actual_memory} ]] ; then
263 if [[ ${actual_memory} -ge $(check-reqs_get_kibibytes ${size}) ]] ; then
265 elif [[ -n ${actual_swap} && $((${actual_memory} + ${actual_swap})) \
266 -ge $(check-reqs_get_kibibytes ${size}) ]] ; then
267 ewarn "Amount of main memory is insufficient, but amount"
268 ewarn "of main memory combined with swap is sufficient."
269 ewarn "Build process may make computer very slow!"
273 check-reqs_unsatisfied \
279 ewarn "Couldn't determine amount of memory, skipping..."
283 # @FUNCTION: check-reqs_disk
286 # Internal function that checks space on the harddrive.
288 debug-print-function ${FUNCNAME} "$@"
290 [[ -z ${2} ]] && die "Usage: ${FUNCNAME} [path] [size]"
296 check-reqs_start_phase \
298 "disk space at \"${path}\""
300 space_kbi=$(df -Pk "${1}" 2>/dev/null | awk 'FNR == 2 {print $4}')
302 if [[ $? == 0 && -n ${space_kbi} ]] ; then
303 if [[ ${space_kbi} -lt $(check-reqs_get_kibibytes ${size}) ]] ; then
305 check-reqs_unsatisfied \
307 "disk space at \"${path}\""
313 ewarn "Couldn't determine disk space, skipping..."
317 # @FUNCTION: check-reqs_start_phase
320 # Internal function that inform about started check
321 check-reqs_start_phase() {
322 debug-print-function ${FUNCNAME} "$@"
324 [[ -z ${2} ]] && die "Usage: ${FUNCNAME} [size] [location]"
328 local sizeunit="$(check-reqs_get_number ${size}) $(check-reqs_get_unit ${size})"
330 ebegin "Checking for at least ${sizeunit} ${location}"
333 # @FUNCTION: check-reqs_unsatisfied
336 # Internal function that inform about check result.
337 # It has different output between pretend and setup phase,
338 # where in pretend phase it is fatal.
339 check-reqs_unsatisfied() {
340 debug-print-function ${FUNCNAME} "$@"
342 [[ -z ${2} ]] && die "Usage: ${FUNCNAME} [size] [location]"
347 local sizeunit="$(check-reqs_get_number ${size}) $(check-reqs_get_unit ${size})"
349 [[ ${EBUILD_PHASE} == "pretend" && -z ${I_KNOW_WHAT_I_AM_DOING} ]] && msg="eerror"
350 ${msg} "There is NOT at least ${sizeunit} ${location}"
352 # @ECLASS-VARIABLE: CHECKREQS_FAILED
355 # If set the checks failed and eclass should abort the build.
356 # Internal, do not set yourself.
357 CHECKREQS_FAILED="true"
360 _CHECK_REQS_ECLASS_=1