Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 155161 | Differences between
and this patch

Collapse All | Expand All

(-)a/bin/ebuild.sh (-1 / +89 lines)
Lines 130-136 __qa_source() { Link Here
130
__qa_call() {
130
__qa_call() {
131
	local shopts=$(shopt) OLDIFS="$IFS"
131
	local shopts=$(shopt) OLDIFS="$IFS"
132
	local retval
132
	local retval
133
	"$@"
133
	__call-ebuildshell "$@"
134
	retval=$?
134
	retval=$?
135
	set +e
135
	set +e
136
	[[ $shopts != $(shopt) ]] &&
136
	[[ $shopts != $(shopt) ]] &&
Lines 537-542 if [[ -n ${QA_INTERCEPTORS} ]] ; then Link Here
537
	unset BIN_PATH BIN BODY FUNC_SRC
537
	unset BIN_PATH BIN BODY FUNC_SRC
538
fi
538
fi
539
539
540
__call-ebuildshell() {
541
	if ! has ebuildshell ${FEATURES}; then
542
		"$@"
543
		return $?
544
	fi
545
	local __ebuildshell_args=( "$@" )
546
	# These are the variables I have seen 'bash -i' maintaining the values for:
547
	local __ebuildshell_bash_i_vars="__ebuildshell_.*
548
		_ BASH_ARGC BASH_ARGV BASH_COMMAND BASH_LINENO BASH_SOURCE
549
		BASH_VERSINFO BASH_SUBSHELL BASHOPTS BASHPID COMP_WORDBREAKS
550
		DIRSTACK EUID FUNCNAME GROUPS HISTCMD LINENO PIPESTATUS PPID
551
		PWD RANDOM SECONDS SHELLOPTS UID"
552
	# Allow recursive ebuildshell, for use in multibuild.eclass and similar:
553
	local __ebuildshell_pid=${BASHPID:-$(__bashpid)}
554
	local __ebuildshell_tmpf="${T}/ebuildshell.${__ebuildshell_pid}"
555
	rm -f "${__ebuildshell_tmpf}."{ebuild,return}-{env,rovars}
556
	(
557
		(
558
			declare -p
559
			declare -fp
560
			shopt -p
561
			[[ ${BASH_VERSINFO[0]} == 3 ]] && export
562
		) |
563
		(
564
			# we need everything but the bash vars after 'env -i'
565
			2>"${__ebuildshell_tmpf}.ebuild-rovars" \
566
			"${PORTAGE_PYTHON:-/tools/haubi/gentoo/s01en24/usr/bin/python}" \
567
				"${PORTAGE_BIN_PATH}"/filter-bash-environment.py \
568
					--report-readonly-variables \
569
					--preserve-readonly-attribute \
570
					"${__ebuildshell_bash_i_vars}" \
571
				|| die "filter-bash-environment.py failed"
572
		)
573
		# The already readonly variables, without bash maintained ones:
574
		__ebuildshell_ro_ebuild_vars=$(<"${__ebuildshell_tmpf}.ebuild-rovars")
575
		cat <<-EOE
576
			PS1="EBUILD ${PN} $1 \$ "
577
			type $1
578
			# properly quote the function arguments
579
			$(declare -p __ebuildshell_args)
580
			set -- "\${__ebuildshell_args[@]}"
581
			unset __ebuildshell_args
582
			echo "WANTED: \$@"
583
			echo "or use: \"\\\$@\""
584
			trap "
585
				rm -f '${__ebuildshell_tmpf}.return-'*
586
				(
587
					(
588
						declare -p
589
						declare -fp
590
						shopt -p | grep -v 'extdebug$'
591
						$([[ ${BASH_VERSINFO[0]} == 3 ]] && echo export)
592
					) |
593
					(
594
						# We may have more readonly variables now, but we
595
						# need to filter variables that are readonly already.
596
						2>"${__ebuildshell_tmpf}.return-rovars" \
597
						'${PORTAGE_PYTHON:-/tools/haubi/gentoo/s01en24/usr/bin/python}' \
598
							'${PORTAGE_BIN_PATH}'/filter-bash-environment.py \\
599
								--report-readonly-variables \
600
								--preserve-readonly-attribute \
601
								--export-into-global-scope \
602
								'${__ebuildshell_bash_i_vars} ${__ebuildshell_ro_ebuild_vars}' \\
603
							|| die 'filter-bash-environment.py failed'
604
					)
605
				) > '${__ebuildshell_tmpf}.return-env'
606
				" EXIT
607
			shopt -u extdebug
608
			trap - DEBUG
609
			alias local=declare # for copy&paste of function body lines
610
			rm -f '${__ebuildshell_tmpf}.ebuild-'*
611
		EOE
612
	) > "${__ebuildshell_tmpf}.ebuild-env"
613
614
	env -i ${BASH} --rcfile "${__ebuildshell_tmpf}.ebuild-env" -i
615
616
	# The environment- and exit-status handling after leaving the ebuildshell
617
	# prompt is expected to be identical as without the ebuildshell prompt.
618
	local status=$?
619
	source "${__ebuildshell_tmpf}.return-env"
620
	# Portage does whitelist readonly variables. If an ebuild defines
621
	# more readonly variables, their readonly attribute is removed.
622
	# If we ever want to preserve additional readonly variables across
623
	# phases, their names are in "${__ebuildshell_tmpf}.return-rovars".
624
	rm -f "${__ebuildshell_tmpf}."{ebuild,return}-{env,rovars}
625
	return ${status}
626
}
627
540
# Subshell/helper die support (must export for the die helper).
628
# Subshell/helper die support (must export for the die helper).
541
export EBUILD_MASTER_PID=${BASHPID:-$(__bashpid)}
629
export EBUILD_MASTER_PID=${BASHPID:-$(__bashpid)}
542
trap 'exit 1' SIGTERM
630
trap 'exit 1' SIGTERM
(-)a/bin/filter-bash-environment.py (-16 / +49 lines)
Lines 14-20 func_end_re = re.compile(r'^\}$') Link Here
14
14
15
var_assign_re = re.compile(r'(^|^declare\s+-\S+\s+|^declare\s+|^export\s+)([^=\s]+)=("|\')?.*$')
15
var_assign_re = re.compile(r'(^|^declare\s+-\S+\s+|^declare\s+|^export\s+)([^=\s]+)=("|\')?.*$')
16
close_quote_re = re.compile(r'(\\"|"|\')\s*$')
16
close_quote_re = re.compile(r'(\\"|"|\')\s*$')
17
readonly_re = re.compile(r'^declare\s+-(\S*)r(\S*)\s+')
17
readonly_re = re.compile(r'^declare\s+-(\S*)r(\S*)\s+([^=\s]+)')
18
export_re = re.compile(r'^declare\s+-(\S*x\S*)\s+')
18
# declare without assignment
19
# declare without assignment
19
var_declare_re = re.compile(r'^declare(\s+-\S+)?\s+([^=\s]+)\s*$')
20
var_declare_re = re.compile(r'^declare(\s+-\S+)?\s+([^=\s]+)\s*$')
20
21
Lines 29-35 def have_end_quote(quote, line): Link Here
29
	return close_quote_match is not None and \
30
	return close_quote_match is not None and \
30
		close_quote_match.group(1) == quote
31
		close_quote_match.group(1) == quote
31
32
32
def filter_declare_readonly_opt(line):
33
def filter_declare_readonly_opt(line, options):
33
	readonly_match = readonly_re.match(line)
34
	readonly_match = readonly_re.match(line)
34
	if readonly_match is not None:
35
	if readonly_match is not None:
35
		declare_opts = ''
36
		declare_opts = ''
Lines 37-50 def filter_declare_readonly_opt(line): Link Here
37
			group = readonly_match.group(i)
38
			group = readonly_match.group(i)
38
			if group is not None:
39
			if group is not None:
39
				declare_opts += group
40
				declare_opts += group
41
		var = readonly_match.group(3)
42
		if '--report-readonly-variables' in options:
43
			sys.stderr.write(var + "\n")
44
		if '--preserve-readonly-attribute' in options:
45
			declare_opts += 'r'
40
		if declare_opts:
46
		if declare_opts:
41
			line = 'declare -%s %s' % \
47
			line = 'declare -%s %s%s' % \
42
				(declare_opts, line[readonly_match.end():])
48
				(declare_opts, var, line[readonly_match.end():])
43
		else:
49
		else:
44
			line = 'declare ' + line[readonly_match.end():]
50
			line = 'declare ' + var + line[readonly_match.end():]
45
	return line
51
	return line
46
52
47
def filter_bash_environment(pattern, file_in, file_out):
53
def add_global_export_opt(line, options):
54
	export_match = export_re.match(line)
55
	if export_match is not None:
56
		declare_opts = export_match.group(1)
57
		if 'g' not in declare_opts and '--export-into-global-scope' in options:
58
			declare_opts += 'g'
59
		line = 'declare -%s %s' % \
60
			(declare_opts, line[export_match.end():])
61
	return line
62
63
def filter_bash_environment(pattern, file_in, file_out, options):
48
	# Filter out any instances of the \1 character from variable values
64
	# Filter out any instances of the \1 character from variable values
49
	# since this character multiplies each time that the environment
65
	# since this character multiplies each time that the environment
50
	# is saved (strange bash behavior). This can eventually result in
66
	# is saved (strange bash behavior). This can eventually result in
Lines 77-83 def filter_bash_environment(pattern, file_in, file_out): Link Here
77
					multi_line_quote = quote
93
					multi_line_quote = quote
78
					multi_line_quote_filter = filter_this
94
					multi_line_quote_filter = filter_this
79
				if not filter_this:
95
				if not filter_this:
80
					line = filter_declare_readonly_opt(line)
96
					line = filter_declare_readonly_opt(line, options)
97
					line = add_global_export_opt(line, options)
81
					file_out.write(line.replace("\1", ""))
98
					file_out.write(line.replace("\1", ""))
82
				continue
99
				continue
83
			else:
100
			else:
Lines 87-93 def filter_bash_environment(pattern, file_in, file_out): Link Here
87
					filter_this = pattern.match(declare_match.group(2)) \
104
					filter_this = pattern.match(declare_match.group(2)) \
88
						is not None
105
						is not None
89
					if not filter_this:
106
					if not filter_this:
90
						line = filter_declare_readonly_opt(line)
107
						line = filter_declare_readonly_opt(line, options)
108
						line = add_global_export_opt(line, options)
91
						file_out.write(line)
109
						file_out.write(line)
92
					continue
110
					continue
93
111
Lines 124-136 if __name__ == "__main__": Link Here
124
		"while leaving bash function definitions and here-documents " + \
142
		"while leaving bash function definitions and here-documents " + \
125
		"intact. The PATTERN is a space separated list of variable names" + \
143
		"intact. The PATTERN is a space separated list of variable names" + \
126
		" and it supports python regular expression syntax."
144
		" and it supports python regular expression syntax."
127
	usage = "usage: %s PATTERN" % os.path.basename(sys.argv[0])
145
	usage = "usage: %s [-h|<options>] PATTERN" % os.path.basename(sys.argv[0])
128
	args = sys.argv[1:]
146
	args = []
129
147
	known_options = {
130
	if '-h' in args or '--help' in args:
148
		'--report-readonly-variables':
131
		sys.stdout.write(usage + "\n")
149
			"Write names of readonly variables to stderr.",
132
		sys.stdout.flush()
150
		'--preserve-readonly-attribute':
133
		sys.exit(os.EX_OK)
151
			"Preserve the '-r' flag in 'declare -r'.",
152
		'--export-into-global-scope':
153
			"Add the '-g' flag to 'declare -x'.",
154
	}
155
	options = {}
156
	for arg in sys.argv[1:]:
157
		if arg in known_options.keys():
158
			options[arg] = True
159
			continue
160
		if '-h' == arg or '--help' == arg:
161
			sys.stdout.write(usage + "\n\nKnown <options>:\n\n")
162
			for option, descr in known_options.items():
163
				sys.stdout.write("  " + option + "\t" + descr + "\n")
164
			sys.stdout.flush()
165
			sys.exit(os.EX_OK)
166
		args.append(arg)
134
167
135
	if len(args) != 1:
168
	if len(args) != 1:
136
		sys.stderr.write(usage + "\n")
169
		sys.stderr.write(usage + "\n")
Lines 154-158 if __name__ == "__main__": Link Here
154
187
155
	var_pattern = "^(%s)$" % "|".join(var_pattern)
188
	var_pattern = "^(%s)$" % "|".join(var_pattern)
156
	filter_bash_environment(
189
	filter_bash_environment(
157
		re.compile(var_pattern), file_in, file_out)
190
		re.compile(var_pattern), file_in, file_out, options)
158
	file_out.flush()
191
	file_out.flush()
(-)a/bin/save-ebuild-env.sh (-1 / +1 lines)
Lines 53-59 __save_ebuild_env() { Link Here
53
		einfo einfon ewarn eerror ebegin __eend eend KV_major \
53
		einfo einfon ewarn eerror ebegin __eend eend KV_major \
54
		KV_minor KV_micro KV_to_int get_KV has \
54
		KV_minor KV_micro KV_to_int get_KV has \
55
		__has_phase_defined_up_to \
55
		__has_phase_defined_up_to \
56
		hasv hasq __qa_source __qa_call \
56
		hasv hasq __qa_source __qa_call __call-ebuildshell \
57
		addread addwrite adddeny addpredict __sb_append_var \
57
		addread addwrite adddeny addpredict __sb_append_var \
58
		use usev useq has_version portageq \
58
		use usev useq has_version portageq \
59
		best_version use_with use_enable register_die_hook \
59
		best_version use_with use_enable register_die_hook \
(-)a/man/make.conf.5 (+6 lines)
Lines 382-387 exist). Also see the related \fIunmerge\-backup\fR feature. Link Here
382
Use locks to ensure that unsandboxed ebuild phases never execute
382
Use locks to ensure that unsandboxed ebuild phases never execute
383
concurrently. Also see \fIparallel\-install\fR.
383
concurrently. Also see \fIparallel\-install\fR.
384
.TP
384
.TP
385
.B ebuildshell
386
Drop into an interactive shell for each phase function, meant for
387
debugging.  Because the shell would normally be used to execute the
388
phase function, commands like src_unpack or epatch are available in the
389
interactive shell.  Use `die` to terminate the merge.
390
.TP
385
.B fail\-clean
391
.B fail\-clean
386
Clean up temporary files after a build failure. This is particularly useful
392
Clean up temporary files after a build failure. This is particularly useful
387
if you have \fBPORTAGE_TMPDIR\fR on tmpfs. If this feature is enabled, you
393
if you have \fBPORTAGE_TMPDIR\fR on tmpfs. If this feature is enabled, you
(-)a/pym/_emerge/AbstractEbuildProcess.py (+1 lines)
Lines 161-166 class AbstractEbuildProcess(SpawnProcess): Link Here
161
			self.fd_pipes = {}
161
			self.fd_pipes = {}
162
		null_fd = None
162
		null_fd = None
163
		if 0 not in self.fd_pipes and \
163
		if 0 not in self.fd_pipes and \
164
			"ebuildshell" not in self.settings.features and \
164
			self.phase not in self._phases_interactive_whitelist and \
165
			self.phase not in self._phases_interactive_whitelist and \
165
			"interactive" not in self.settings.get("PROPERTIES", "").split():
166
			"interactive" not in self.settings.get("PROPERTIES", "").split():
166
			null_fd = os.open('/dev/null', os.O_RDONLY)
167
			null_fd = os.open('/dev/null', os.O_RDONLY)
(-)a/pym/portage/const.py (-1 / +1 lines)
Lines 142-147 SUPPORTED_FEATURES = frozenset([ Link Here
142
	"distlocks",
142
	"distlocks",
143
	"downgrade-backup",
143
	"downgrade-backup",
144
	"ebuild-locks",
144
	"ebuild-locks",
145
	"ebuildshell",
145
	"fail-clean",
146
	"fail-clean",
146
	"fakeroot",
147
	"fakeroot",
147
	"fixlafiles",
148
	"fixlafiles",
148
- 

Return to bug 155161