summaryrefslogtreecommitdiff
blob: 26b5f8de784b648d3db3e1074282c48d9f5b8b33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# Copyright 1999-2008 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo-x86/eclass/check-reqs.eclass,v 1.7 2010/08/22 21:18:03 halcy0n Exp $

# @ECLASS: check-reqs.eclass
# @MAINTAINER:
# Bo Ørsted Andresen <zlin@gentoo.org>
# 
# Original Author: Ciaran McCreesh <ciaranm@gentoo.org>
# @BLURB: Provides a uniform way of handling ebuild which have very high build requirements
# @DESCRIPTION:
# This eclass provides a uniform way of handling ebuilds which have very high
# build requirements in terms of memory or disk space. It provides a function
# which should usually be called during pkg_setup().
#
# From a user perspective, the variable CHECKREQS_ACTION can be set to:
#    * "warn" (default), which will display a warning and wait for 15s
#    * "error", which will make the ebuild error out
#    * "ignore", which will not take any action
#
# The chosen action only happens when the system's resources are detected
# correctly and only if they are below the threshold specified by the package.
#
# For ebuild authors: only use this eclass if you reaaalllllly have stupidly
# high build requirements. At an absolute minimum, you shouldn't be using this
# unless the ebuild needs >256MBytes RAM or >1GByte temporary or install space.
# The code should look something like:
#
# @CODE
# pkg_setup() {
#     # values in MBytes
#
#     # need this much memory (does *not* check swap)
#     CHECKREQS_MEMORY="256"
#
#     # need this much temporary build space
#     CHECKREQS_DISK_BUILD="2048"
#
#     # install will need this much space in /usr
#     CHECKREQS_DISK_USR="1024"
#
#     # install will need this much space in /var
#     CHECKREQS_DISK_VAR="1024"
#
#     # go!
#     check_reqs
# }
# @CODE
#
# Alternatively, the check_reqs_conditional function can be used to carry out
# alternate actions (e.g. using a much slower but far less memory intensive
# build option that gives the same end result).
#
# You should *not* override the user's CHECKREQS_ACTION setting, nor should you
# attempt to provide a value if it is unset. Note that the environment variables
# are used rather than parameters for a few reasons:
#   * easier to do if use blah ; then things
#   * we might add in additional requirements things later
# If you don't specify a value for, say, CHECKREQS_MEMORY, then the test is not
# carried out.
#
# These checks should probably mostly work on non-Linux, and they should
# probably degrade gracefully if they don't. Probably.

inherit eutils

# @ECLASS-VARIABLE: CHECKREQS_MEMORY
# @DESCRIPTION:
# How much RAM is needed in MB?

# @ECLASS-VARIABLE:  CHECKREQS_DISK_BUILD
# @DESCRIPTION:
# How much diskspace is needed to build the package? In MB

# @ECLASS-VARIABLE: CHECKREQS_DISK_USR
# @DESCRIPTION:
# How much space in /usr is needed to install the package? In MB

# @ECLASS-VARIABLE: CHECKREQS_DISK_VAR
# @DESCRIPTION:
# How much space is needed in /var? In MB

# @FUNCTION: check_reqs
# @DESCRIPTION:
# Checks the requirements given in the specific variables. If not reached,
# either prints a warning or dies.
check_reqs() {
	[[ -n "${1}" ]] && die "Usage: check_reqs"

	export CHECKREQS_NEED_SLEEP="" CHECKREQS_NEED_DIE=""
	if [[ "$CHECKREQS_ACTION" != "ignore" ]] ; then
		[[ -n "$CHECKREQS_MEMORY" ]] && check_build_memory
		[[ -n "$CHECKREQS_DISK_BUILD" ]] && check_build_disk \
			"${T}" "${CHECKREQS_DISK_BUILD}"
		[[ -n "$CHECKREQS_DISK_USR" ]] && check_build_disk \
			"${ROOT}/usr" "${CHECKREQS_DISK_USR}"
		[[ -n "$CHECKREQS_DISK_VAR" ]] && check_build_disk \
			"${ROOT}/var" "${CHECKREQS_DISK_VAR}"
	fi

	if [[ -n "${CHECKREQS_NEED_SLEEP}" ]] ; then
		echo
		ewarn "Bad things may happen! You may abort the build by pressing ctrl+c in"
		ewarn "the next 15 seconds."
		ewarn " "
		einfo "To make this kind of warning a fatal error, add a line to /etc/make.conf"
		einfo "setting CHECKREQS_ACTION=\"error\". To skip build requirements checking,"
		einfo "set CHECKREQS_ACTION=\"ignore\"."
		epause 15
	fi

	if [[ -n "${CHECKREQS_NEED_DIE}" ]] ; then
		eerror "Bailing out as specified by CHECKREQS_ACTION"
		die "Build requirements not met"
	fi
}

# @FUNCTION: check_reqs_conditional
# @RETURN: True if requirements check passed, else False
# @DESCRIPTION:
# Checks the requirements given in the specific variables
check_reqs_conditional() {
	[[ -n "${1}" ]] && die "Usage: check_reqs"

	export CHECKREQS_NEED_SLEEP="" CHECKREQS_NEED_DIE=""
	if [[ "$CHECKREQS_ACTION" != "ignore" ]] ; then
		[[ -n "$CHECKREQS_MEMORY" ]] && check_build_memory
		[[ -n "$CHECKREQS_DISK_BUILD" ]] && check_build_disk \
			"${T}" "${CHECKREQS_DISK_BUILD}"
		[[ -n "$CHECKREQS_DISK_USR" ]] && check_build_disk \
			"${ROOT}/usr" "${CHECKREQS_DISK_USR}"
		[[ -n "$CHECKREQS_DISK_VAR" ]] && check_build_disk \
			"${ROOT}/var" "${CHECKREQS_DISK_VAR}"
	fi

	[[ -z "${CHECKREQS_NEED_SLEEP}" && -z "${CHECKREQS_NEED_DIE}" ]]
}

# internal use only!
check_build_memory() {
	[[ -n "${1}" ]] && die "Usage: check_build_memory"
	check_build_msg_begin "${CHECKREQS_MEMORY}" "MBytes" "RAM"
	if [[ -r /proc/meminfo ]] ; then
		actual_memory=$(sed -n -e '/MemTotal:/s/^[^:]*: *\([0-9]\+\) kB/\1/p' \
			/proc/meminfo)
	else
		actual_memory=$(sysctl hw.physmem 2>/dev/null )
		[[ "$?" == "0" ]] &&
			actual_memory=$(echo $actual_memory | sed -e 's/^[^:=]*[:=]//' )
	fi
	if [[ -n "${actual_memory}" ]] ; then
		if [[ ${actual_memory} -lt $((1024 * ${CHECKREQS_MEMORY})) ]] ; then
			eend 1
			check_build_msg_ick "${CHECKREQS_MEMORY}" "MBytes" "RAM"
		else
			eend 0
		fi
	else
		eend 1
		ewarn "Couldn't determine amount of memory, skipping ..."
	fi
}

# internal use only!
check_build_disk() {
	[[ -z "${2}" ]] && die "Usage: check_build_disk where name needed"
	check_build_msg_begin "${2}" "MBytes" \
			"disk space at ${1}"
	actual_space=$(df -Pm ${1} 2>/dev/null | sed -n \
			'$s/\(\S\+\s\+\)\{3\}\([0-9]\+\).*/\2/p' 2>/dev/null )
	if [[ "$?" == "0" && -n "${actual_space}" ]] ; then
		if [[ ${actual_space} -lt ${2} ]] ; then
			eend 1
			check_build_msg_ick "${2}" "MBytes" \
					"disk space at ${1}"
		else
			eend 0
		fi
	else
		eend 1
		ewarn "Couldn't figure out disk space, skipping ..."
	fi
}

# internal use only!
check_build_msg_begin() {
	ebegin "Checking for at least ${1}${2} ${3}"
}

# internal use only!
check_build_msg_skip() {
	ewarn "Skipping check for at least ${1}${2} ${3}"
}

# internal use only!
check_build_msg_ick() {
	if [[ "${CHECKREQS_ACTION}" == "error" ]] ; then
		eerror "Don't have at least ${1}${2} ${3}"
		echo
		export CHECKREQS_NEED_DIE="yes"
	else
		ewarn "Don't have at least ${1}${2} ${3}"
		echo
		export CHECKREQS_NEED_SLEEP="yes"
	fi
}