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 / +130 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 HISTFILE LINENO
551
		PIPESTATUS PPID 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
			# properly quote the function arguments
577
			$(declare -p __ebuildshell_args)
578
			set -- "\${__ebuildshell_args[@]}"
579
			unset __ebuildshell_args
580
			# be informative about what to do
581
			PS1="EBUILD ${PN} $1 \$ "
582
			type $1
583
			echo "WANTED: \$@"
584
			echo "or use: \"\\\$@\""
585
			# use bash history, but not the 'user's real one
586
			HISTFILE=~/.bash_history
587
			# for copy&paste function body lines containing: !
588
			set +H
589
			# Support the 'local' keyword outside any shell function
590
			# for copy&paste of function body lines: Remember these
591
			# "local" variable names for filtering from return-env.
592
			__ebuildshell_local_vars=
593
			__ebuildshell_local() {
594
				local __ebuildshell_local_attr=
595
				while [[ \${1} == -* ]]; do
596
					__ebuildshell_local_attr+=" \${1}"
597
					shift
598
				done
599
				__ebuildshell_local_vars+=" \${1%%=*} "
600
				# Need to declare into the global shell namespace,
601
				# as we are in some shell function here apparently.
602
				declare -g \${__ebuildshell_local_attr} "\$@"
603
			}
604
			# within some function, BASH_LINENO is set, and we use real 'local'
605
			alias local='\$( (( \${#BASH_LINENO} > 0 )) && echo local || echo __ebuildshell_local)'
606
			# at exit, dump the current environment
607
			trap "
608
				unalias local
609
				unset -f __ebuildshell_local
610
				rm -f '${__ebuildshell_tmpf}.return-'*
611
				(
612
					(
613
						declare -p
614
						declare -fp
615
						shopt -p | grep -v 'extdebug$'
616
						$([[ ${BASH_VERSINFO[0]} == 3 ]] && echo export)
617
					) |
618
					(
619
						# We may have more readonly variables now, but we
620
						# need to filter variables that are readonly already.
621
						2>'${__ebuildshell_tmpf}.return-rovars' \\
622
						'${PORTAGE_PYTHON:-/tools/haubi/gentoo/s01en24/usr/bin/python}' \\
623
							'${PORTAGE_BIN_PATH}'/filter-bash-environment.py \\
624
								--report-readonly-variables \\
625
								--preserve-readonly-attribute \\
626
								'${__ebuildshell_bash_i_vars}
627
								 ${__ebuildshell_ro_ebuild_vars}
628
								 '\" \${__ebuildshell_local_vars}\" \\
629
							|| die 'filter-bash-environment.py failed'
630
					)
631
				) > '${__ebuildshell_tmpf}.return-env'
632
				" EXIT
633
			# this is a debugging shell already
634
			shopt -u extdebug
635
			trap - DEBUG
636
			# can do some cleanup already
637
			rm -f '${__ebuildshell_tmpf}.ebuild-'*
638
		EOE
639
	) > "${__ebuildshell_tmpf}.ebuild-env"
640
641
	# pre-fill the history with "$@"
642
	echo '"$@"' >> ~/.bash_history
643
644
	env -i ${BASH} --rcfile "${__ebuildshell_tmpf}.ebuild-env" -i
645
646
	# The environment- and exit-status handling after leaving the ebuildshell
647
	# prompt is expected to be identical as without the ebuildshell prompt.
648
	local __ebuildshell_status=$?
649
650
	# Defining a variable without using the the local keyword makes this
651
	# variable visible to the 'global' shell namespace.  But 'declare -p'
652
	# does not show the -g flag, so we need to add that one for all
653
	# variables that have been visible to the EXIT trap above.
654
	local __ebuildshell_orig_expand_aliases=$(shopt -p expand_aliases)
655
	alias declare='declare -g'
656
	shopt -s expand_aliases
657
	source "${__ebuildshell_tmpf}.return-env"
658
	unalias declare
659
	${__ebuildshell_orig_expand_aliases}
660
	# Portage does whitelist readonly variables. If an ebuild defines
661
	# more readonly variables, their readonly attribute is removed.
662
	# If we ever want to preserve additional readonly variables across
663
	# phases, their names are in "${__ebuildshell_tmpf}.return-rovars".
664
	rm -f "${__ebuildshell_tmpf}."{ebuild,return}-{env,rovars}
665
666
	return ${__ebuildshell_status}
667
}
668
540
# Subshell/helper die support (must export for the die helper).
669
# Subshell/helper die support (must export for the die helper).
541
export EBUILD_MASTER_PID=${BASHPID:-$(__bashpid)}
670
export EBUILD_MASTER_PID=${BASHPID:-$(__bashpid)}
542
trap 'exit 1' SIGTERM
671
trap 'exit 1' SIGTERM
(-)a/bin/filter-bash-environment.py (-16 / +34 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
# declare without assignment
18
# declare without assignment
19
var_declare_re = re.compile(r'^declare(\s+-\S+)?\s+([^=\s]+)\s*$')
19
var_declare_re = re.compile(r'^declare(\s+-\S+)?\s+([^=\s]+)\s*$')
20
20
Lines 29-35 def have_end_quote(quote, line): Link Here
29
	return close_quote_match is not None and \
29
	return close_quote_match is not None and \
30
		close_quote_match.group(1) == quote
30
		close_quote_match.group(1) == quote
31
31
32
def filter_declare_readonly_opt(line):
32
def filter_declare_readonly_opt(line, options):
33
	readonly_match = readonly_re.match(line)
33
	readonly_match = readonly_re.match(line)
34
	if readonly_match is not None:
34
	if readonly_match is not None:
35
		declare_opts = ''
35
		declare_opts = ''
Lines 37-50 def filter_declare_readonly_opt(line): Link Here
37
			group = readonly_match.group(i)
37
			group = readonly_match.group(i)
38
			if group is not None:
38
			if group is not None:
39
				declare_opts += group
39
				declare_opts += group
40
		var = readonly_match.group(3)
41
		if '--report-readonly-variables' in options:
42
			sys.stderr.write(var + "\n")
43
		if '--preserve-readonly-attribute' in options:
44
			declare_opts += 'r'
40
		if declare_opts:
45
		if declare_opts:
41
			line = 'declare -%s %s' % \
46
			line = 'declare -%s %s%s' % \
42
				(declare_opts, line[readonly_match.end():])
47
				(declare_opts, var, line[readonly_match.end():])
43
		else:
48
		else:
44
			line = 'declare ' + line[readonly_match.end():]
49
			line = 'declare ' + var + line[readonly_match.end():]
45
	return line
50
	return line
46
51
47
def filter_bash_environment(pattern, file_in, file_out):
52
def filter_bash_environment(pattern, file_in, file_out, options):
48
	# Filter out any instances of the \1 character from variable values
53
	# Filter out any instances of the \1 character from variable values
49
	# since this character multiplies each time that the environment
54
	# since this character multiplies each time that the environment
50
	# is saved (strange bash behavior). This can eventually result in
55
	# 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
82
					multi_line_quote = quote
78
					multi_line_quote_filter = filter_this
83
					multi_line_quote_filter = filter_this
79
				if not filter_this:
84
				if not filter_this:
80
					line = filter_declare_readonly_opt(line)
85
					line = filter_declare_readonly_opt(line, options)
81
					file_out.write(line.replace("\1", ""))
86
					file_out.write(line.replace("\1", ""))
82
				continue
87
				continue
83
			else:
88
			else:
Lines 87-93 def filter_bash_environment(pattern, file_in, file_out): Link Here
87
					filter_this = pattern.match(declare_match.group(2)) \
92
					filter_this = pattern.match(declare_match.group(2)) \
88
						is not None
93
						is not None
89
					if not filter_this:
94
					if not filter_this:
90
						line = filter_declare_readonly_opt(line)
95
						line = filter_declare_readonly_opt(line, options)
91
						file_out.write(line)
96
						file_out.write(line)
92
					continue
97
					continue
93
98
Lines 124-136 if __name__ == "__main__": Link Here
124
		"while leaving bash function definitions and here-documents " + \
129
		"while leaving bash function definitions and here-documents " + \
125
		"intact. The PATTERN is a space separated list of variable names" + \
130
		"intact. The PATTERN is a space separated list of variable names" + \
126
		" and it supports python regular expression syntax."
131
		" and it supports python regular expression syntax."
127
	usage = "usage: %s PATTERN" % os.path.basename(sys.argv[0])
132
	usage = "usage: %s [-h|<options>] PATTERN" % os.path.basename(sys.argv[0])
128
	args = sys.argv[1:]
133
	args = []
129
134
	known_options = {
130
	if '-h' in args or '--help' in args:
135
		'--report-readonly-variables':
131
		sys.stdout.write(usage + "\n")
136
			"Write names of readonly variables to stderr.",
132
		sys.stdout.flush()
137
		'--preserve-readonly-attribute':
133
		sys.exit(os.EX_OK)
138
			"Preserve the '-r' flag in 'declare -r'.",
139
	}
140
	options = {}
141
	for arg in sys.argv[1:]:
142
		if arg in known_options.keys():
143
			options[arg] = True
144
			continue
145
		if '-h' == arg or '--help' == arg:
146
			sys.stdout.write(usage + "\n\nKnown <options>:\n\n")
147
			for option, descr in known_options.items():
148
				sys.stdout.write("  " + option + "\t" + descr + "\n")
149
			sys.stdout.flush()
150
			sys.exit(os.EX_OK)
151
		args.append(arg)
134
152
135
	if len(args) != 1:
153
	if len(args) != 1:
136
		sys.stderr.write(usage + "\n")
154
		sys.stderr.write(usage + "\n")
Lines 154-158 if __name__ == "__main__": Link Here
154
172
155
	var_pattern = "^(%s)$" % "|".join(var_pattern)
173
	var_pattern = "^(%s)$" % "|".join(var_pattern)
156
	filter_bash_environment(
174
	filter_bash_environment(
157
		re.compile(var_pattern), file_in, file_out)
175
		re.compile(var_pattern), file_in, file_out, options)
158
	file_out.flush()
176
	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