Gentoo Archives: gentoo-dev

From: "Gregory M. Turner" <gmt@×××××.us>
To: gentoo-dev@l.g.o
Subject: Re: [gentoo-dev] eclass error-handling post-EAPI4
Date: Sat, 20 Oct 2012 10:53:42
Message-Id: 50828281.6030101@malth.us
In Reply to: Re: [gentoo-dev] eclass error-handling post-EAPI4 by Zac Medico
1 Thanks for your reply, but I still have some concerns about this.
2
3 On 10/19/2012 8:11 AM, Zac Medico wrote:
4 > Regardless of EAPI, don't call the helpers that die in EAPI 4 unless you
5 > want the function to die when the helpers fail, and use helper || die so
6 > it behaves the same regardless of EAPI.
7
8 Took me a while, but I think I see why this is correct, now (mostly --
9 see below). The source of my confusion was a mistaken assumption that
10 die() would not respect PORTAGE_NONFATAL. But isolated-functions.sh has
11 roughly:
12
13 die()
14 {
15 [[ ${PORTAGE_NONFATAL} == 1 ]] && {
16 echo "${FUNCNAME[1]}: WARNING: $*" >&2
17 return 1
18 }
19 .
20 .
21
22 So -- correct me if I'm wrong -- this all works as follows:
23
24 o helpers always handle errors by remembering the exit code of some
25 error-prone operation, and, if that exit code is nonzero, invoking
26 __helpers_die with some description of the problem, and finally
27 returning the remembered exit code.
28
29 In EAPI[0-3], this will dump the error text to stderr and return
30 the remembered exit code.
31
32 In >=EAPI4, this will call isolated-functions.sh's die(), which will
33 swoop in and terminate everything before it has the chance to
34 go any further, effectively ensuring that __helpers_die never
35 returns -- /unless/ PORTAGE_NONFATAL is 1, in which case, it will
36 prepend "__helpers_die:" to the error message, but otherwise
37 behave as in EAPI[0-3].
38
39 o die incantations in an ebuild or eclass will either directly or
40 indirectly call die() in isolated-functions.sh, which still works
41 as described above when used in these contexts -- which is to say,
42 that die is nonfatal when PORTAGE_NONFATAL is set.
43
44 o PORTAGE_NONFATAL is only supposed to be manipulated by means of
45 the nonfatal API, which is only callable in >=EAPI4, which means
46 that unless somebody "cheated" by directly messing with the
47 variable, in EAPI[0-3], die() never returns (like "exit")
48
49 > It's okay to die in older EAPIs, as long as you're not changing the
50 > behavior of a previously existing eclass function.
51
52 ACK
53
54 > Previously existing eclass functions that only start to
55 > die in EAPI 4 are okay, since they only start to die when the ebuild
56 > developer bumps the EAPI.
57
58 ACK
59
60 If I indeed understand the facts correctly, I'm still a bit
61 uncomfortable with your advice to just use "helper || die" in eclass
62 code. It seems to me that if I follow this recipe, >=EAPI4 kinda works
63 OK, but EAPI[0-3] doesn't.
64
65 Specifically, an EAPI[0-3] ebuild author will not have any means at his
66 or her disposal to handle errors that occur in eclass utility functions.
67 The error-handling semantics of eclass utility functions would be like
68 EAPI4, except without nonfatal around to provide relief from auto-die.
69
70 EAPI[0-3] conventions encourage the habit of writing ebuild code like
71 normal bash script code, which is to say, that authors expect to be able
72 to write code like
73
74 invoke_fn || ... # handle error, probably by die()ing but maybe not
75
76 But eclasses that auto-die violate this expectation and create a
77 situation where ebuild authors must be mindful of whether a particular
78 function is a helper-function or an eclass utility function to correctly
79 anticipate whether auto-death will occur.
80
81 This seems to be by design and may not be so horrible as I make it sound
82 -- for example, it would be pretty weird to expect eclass code written
83 before EAPI4 to suddenly start working differently in EAPI[0-3].
84
85 But should we really write new eclass code to behave this way as well?
86
87 Worse, eclasses authored in the pre-EAPI4 era ubiquitously assume that
88 die() never returns, and do things like:
89
90 efoo() {
91 [[ ${EBUILD_PHASE} != "prepare" ]] &&
92 die "efoo can only be used during src_prepare"
93 .
94 .
95 # stuff that isn't safe if ${EBUILD_PHASE} != "prepare"
96 .
97 .
98 }
99
100 Since, in EAPI4, no means is provided to specify that a particular
101 invocation of die() is unconditionally terminal, (except directly
102 manipulating PORTAGE_NONFATAL, which doesn't seem to be encouraged), the
103 only non-encapsulation-breaking non-EAPI-specific solution would be to
104 re-code every presumed-terminal use of die() to look something like:
105
106 failure_prone_action
107 ret=$?
108 if [[ ${ret} != 0 ]] ; then
109 die "Error message"
110 return ${ret}
111 fi
112
113 I can imagine no reasonable way to avoid this without using aliases...
114 or perhaps some construct like:
115
116 do_or_die() {
117 diemsg="$1"
118 shift
119 "$@" || { ret=$?; die "${diemsg}"; return ${ret}; }
120 }
121
122 efoo() {
123 do_or_die "error message 1" \
124 failure_prone_action1 arg1 arg2 arg3 && \
125 safe_action1 arg1 && \
126 safe_action2 arg1 arg2 && \
127 do_or_die "error message 2" \
128 failure_prone_action2 arg1 arg2 && \
129 .
130 .
131
132 Hopefully I'm missing something here...?
133
134 -gmt

Replies

Subject Author
Re: [gentoo-dev] eclass error-handling post-EAPI4 Ciaran McCreesh <ciaran.mccreesh@××××××××××.com>
Re: [gentoo-dev] eclass error-handling post-EAPI4 Zac Medico <zmedico@g.o>