Gentoo Archives: gentoo-commits

From: "Fabian Groffen (grobian)" <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r10879 - in main/branches/prefix/pym: _emerge portage
Date: Tue, 01 Jul 2008 17:09:21
Message-Id: E1KDjLu-0006WJ-Tn@stork.gentoo.org
1 Author: grobian
2 Date: 2008-07-01 17:09:13 +0000 (Tue, 01 Jul 2008)
3 New Revision: 10879
4
5 Modified:
6 main/branches/prefix/pym/_emerge/__init__.py
7 main/branches/prefix/pym/portage/__init__.py
8 Log:
9 Merged from trunk 10843:10853
10
11 | 10844 | Handle invalid atoms inside depgraph._add_pkg_deps(), to |
12 | zmedico | avoid an unhandled InvalidAtom exception from dep_expand() |
13 | | when matching against the vardb. |
14
15 | 10845 | Split out a _spawn_misc_sh() function from spawnebuild(). |
16 | zmedico | |
17
18 | 10846 | Split out a _post_src_install_uid_fix() function from |
19 | zmedico | spawnebuild(). |
20
21 | 10847 | Split out a _check_build_log() function from spawnebuild(). |
22 | zmedico | |
23
24 | 10848 | In EbuildBuild.execute(), call doebuild() separately for |
25 | zmedico | each phase since it will be easier to add asynchronous |
26 | | support to doebuild() if it's called this way. |
27
28 | 10849 | * Add "fd_pipes" and "returnpid" parameters to doebuild() |
29 | zmedico | and pass these into spawn calls, enabling ebuild processes |
30 | | to execute asynchronously. * Add a EbuildPhase class that's |
31 | | derived from the pty logging code inside portage.spawn(). * |
32 | | Integrate post-phase code from spawnebuild() into |
33 | | EbuildBuild.execute() so that it still gets called even |
34 | | though doebuild() calls execute asynchronously. |
35
36 | 10850 | Add EMERGE_FROM to the blacklisted vars in the config |
37 | zmedico | constructor. |
38
39 | 10851 | Centralize select.poll() event handling in |
40 | zmedico | MergeTask._schedule(). This will allow the parent process to |
41 | | handle output of multiple child processes running in |
42 | | parllel. |
43
44 | 10852 | * Tweak conditionals in doebuild() to fix emerge --fetch |
45 | zmedico | breakage reported by Arfrever. * Change a couple EMERGE_FROM |
46 | | conditionals to use the "returnpid" parameter instead. |
47
48 | 10853 | Rename the MergeTask class to Scheduler. |
49 | zmedico | |
50
51
52 Modified: main/branches/prefix/pym/_emerge/__init__.py
53 ===================================================================
54 --- main/branches/prefix/pym/_emerge/__init__.py 2008-07-01 16:59:40 UTC (rev 10878)
55 +++ main/branches/prefix/pym/_emerge/__init__.py 2008-07-01 17:09:13 UTC (rev 10879)
56 @@ -20,6 +20,8 @@
57 except KeyboardInterrupt:
58 sys.exit(1)
59
60 +import array
61 +import select
62 import gc
63 import os, stat
64 import platform
65 @@ -1554,8 +1556,10 @@
66 """
67 TODO: Support asynchronous execution, to implement parallel builds.
68 """
69 - __slots__ = ("pkg", "settings")
70 + __slots__ = ("pkg", "register", "schedule", "settings", "unregister")
71
72 + _phases = ("setup", "unpack", "compile", "test", "install")
73 +
74 def _get_hash_key(self):
75 hash_key = getattr(self, "_hash_key", None)
76 if hash_key is None:
77 @@ -1566,19 +1570,171 @@
78 root_config = self.pkg.root_config
79 portdb = root_config.trees["porttree"].dbapi
80 ebuild_path = portdb.findname(self.pkg.cpv)
81 - debug = self.settings.get("PORTAGE_DEBUG") == "1"
82 + settings = self.settings
83 + debug = settings.get("PORTAGE_DEBUG") == "1"
84 + cleanup = 1
85
86 retval = portage.doebuild(ebuild_path, "clean",
87 - root_config.root, self.settings, debug, cleanup=1,
88 + root_config.root, settings, debug, cleanup=cleanup,
89 mydbapi=portdb, tree="porttree")
90 if retval != os.EX_OK:
91 return retval
92
93 - retval = portage.doebuild(ebuild_path, "install",
94 - root_config.root, self.settings, debug,
95 - mydbapi=portdb, tree="porttree")
96 - return retval
97 + # This initializes PORTAGE_LOG_FILE.
98 + portage.prepare_build_dirs(root_config.root, settings, cleanup)
99
100 + fd_pipes = {
101 + 0 : sys.stdin.fileno(),
102 + 1 : sys.stdout.fileno(),
103 + 2 : sys.stderr.fileno(),
104 + }
105 +
106 + for mydo in self._phases:
107 + ebuild_phase = EbuildPhase(fd_pipes=fd_pipes,
108 + pkg=self.pkg, phase=mydo, register=self.register,
109 + settings=settings, unregister=self.unregister)
110 + ebuild_phase.start()
111 + self.schedule()
112 + retval = ebuild_phase.wait()
113 +
114 + portage._post_phase_userpriv_perms(settings)
115 + if mydo == "install":
116 + portage._check_build_log(settings)
117 + if retval == os.EX_OK:
118 + retval = portage._post_src_install_checks(settings)
119 +
120 + if retval != os.EX_OK:
121 + return retval
122 +
123 + return os.EX_OK
124 +
125 +class EbuildPhase(SlotObject):
126 +
127 + __slots__ = ("fd_pipes", "phase", "pkg",
128 + "register", "settings", "unregister",
129 + "pid", "returncode", "files")
130 +
131 + _file_names = ("log", "stdout", "ebuild")
132 + _files_dict = slot_dict_class(_file_names)
133 + _bufsize = 4096
134 +
135 + def start(self):
136 + root_config = self.pkg.root_config
137 + portdb = root_config.trees["porttree"].dbapi
138 + ebuild_path = portdb.findname(self.pkg.cpv)
139 + settings = self.settings
140 + debug = settings.get("PORTAGE_DEBUG") == "1"
141 + logfile = settings.get("PORTAGE_LOG_FILE")
142 + master_fd = None
143 + slave_fd = None
144 + fd_pipes = self.fd_pipes.copy()
145 +
146 + # flush any pending output
147 + for fd in fd_pipes.itervalues():
148 + if fd == sys.stdout.fileno():
149 + sys.stdout.flush()
150 + if fd == sys.stderr.fileno():
151 + sys.stderr.flush()
152 +
153 + fd_pipes_orig = None
154 + self.files = self._files_dict()
155 + files = self.files
156 + got_pty = False
157 +
158 + portage._doebuild_exit_status_unlink(
159 + settings.get("EBUILD_EXIT_STATUS_FILE"))
160 +
161 + if logfile:
162 + if portage._disable_openpty:
163 + master_fd, slave_fd = os.pipe()
164 + else:
165 + from pty import openpty
166 + try:
167 + master_fd, slave_fd = openpty()
168 + got_pty = True
169 + except EnvironmentError, e:
170 + portage._disable_openpty = True
171 + portage.writemsg("openpty failed: '%s'\n" % str(e),
172 + noiselevel=-1)
173 + del e
174 + master_fd, slave_fd = os.pipe()
175 +
176 + if got_pty:
177 + # Disable post-processing of output since otherwise weird
178 + # things like \n -> \r\n transformations may occur.
179 + import termios
180 + mode = termios.tcgetattr(slave_fd)
181 + mode[1] &= ~termios.OPOST
182 + termios.tcsetattr(slave_fd, termios.TCSANOW, mode)
183 +
184 + import fcntl
185 + fcntl.fcntl(master_fd, fcntl.F_SETFL,
186 + fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
187 +
188 + fd_pipes.setdefault(0, sys.stdin.fileno())
189 + fd_pipes_orig = fd_pipes.copy()
190 + if got_pty and os.isatty(fd_pipes_orig[1]):
191 + from portage.output import get_term_size, set_term_size
192 + rows, columns = get_term_size()
193 + set_term_size(rows, columns, slave_fd)
194 + fd_pipes[0] = fd_pipes_orig[0]
195 + fd_pipes[1] = slave_fd
196 + fd_pipes[2] = slave_fd
197 +
198 + retval = portage.doebuild(ebuild_path, self.phase,
199 + root_config.root, settings, debug,
200 + mydbapi=portdb, tree="porttree",
201 + fd_pipes=fd_pipes, returnpid=True)
202 +
203 + self.pid = retval[0]
204 +
205 + if logfile:
206 + os.close(slave_fd)
207 + files["log"] = open(logfile, 'a')
208 + files["stdout"] = os.fdopen(os.dup(fd_pipes_orig[1]), 'w')
209 + files["ebuild"] = os.fdopen(master_fd, 'r')
210 + self.register(files["ebuild"].fileno(),
211 + select.POLLIN, self._output_handler)
212 +
213 + def _output_handler(self, fd, event):
214 + files = self.files
215 + buf = array.array('B')
216 + try:
217 + buf.fromfile(files["ebuild"], self._bufsize)
218 + except EOFError:
219 + pass
220 + if buf:
221 + buf.tofile(files["stdout"])
222 + files["stdout"].flush()
223 + buf.tofile(files["log"])
224 + files["log"].flush()
225 + else:
226 + self.unregister(files["ebuild"].fileno())
227 + for f in files.values():
228 + f.close()
229 +
230 + def wait(self):
231 + pid = self.pid
232 + retval = os.waitpid(pid, 0)[1]
233 + portage.process.spawned_pids.remove(pid)
234 + if retval != os.EX_OK:
235 + if retval & 0xff:
236 + retval = (retval & 0xff) << 8
237 + else:
238 + retval = retval >> 8
239 +
240 + msg = portage._doebuild_exit_status_check(
241 + self.phase, self.settings)
242 + if msg:
243 + retval = 1
244 + from textwrap import wrap
245 + from portage.elog.messages import eerror
246 + for l in wrap(msg, 72):
247 + eerror(l, phase=self.phase, key=self.pkg.cpv)
248 +
249 + self.returncode = retval
250 + return self.returncode
251 +
252 class EbuildBinpkg(Task):
253 """
254 This assumes that src_install() has successfully completed.
255 @@ -2776,6 +2932,13 @@
256 if debug:
257 print "Candidates:", selected_atoms
258 for atom in selected_atoms:
259 + if isinstance(atom, basestring) \
260 + and not portage.isvalidatom(atom):
261 + show_invalid_depstring_notice(
262 + pkg, dep_string, str(atom))
263 + if not pkg.installed:
264 + return 0
265 + continue
266 blocker = atom.startswith("!")
267 if blocker:
268 atom = atom[1:]
269 @@ -6198,7 +6361,7 @@
270 (self.blocks - self.blocks_satisfied))
271 return "".join(myoutput)
272
273 -class MergeTask(object):
274 +class Scheduler(object):
275
276 _opts_ignore_blockers = \
277 frozenset(["--buildpkgonly",
278 @@ -6224,6 +6387,8 @@
279 clone=trees[root]["vartree"].settings)
280 self.curval = 0
281 self._spawned_pids = []
282 + self._poll_event_handlers = {}
283 + self._poll = select.poll()
284
285 class _pkg_failure(portage.exception.PortageException):
286 """
287 @@ -6388,6 +6553,19 @@
288 pass
289 spawned_pids.remove(pid)
290
291 + def _register(self, f, eventmask, handler):
292 + self._poll_event_handlers[f] = handler
293 + self._poll.register(f, eventmask)
294 +
295 + def _unregister(self, f):
296 + self._poll.unregister(f)
297 + del self._poll_event_handlers[f]
298 +
299 + def _schedule(self):
300 + while self._poll_event_handlers:
301 + for f, event in self._poll.poll():
302 + self._poll_event_handlers[f](f, event)
303 +
304 def _merge(self):
305 mylist = self._mergelist
306 favorites = self._favorites
307 @@ -6626,7 +6804,9 @@
308 (mergecount, len(mymergelist), pkg_key)
309 emergelog(xterm_titles, msg, short_msg=short_msg)
310
311 - build = EbuildBuild(pkg=pkg, settings=pkgsettings)
312 + build = EbuildBuild(pkg=pkg, register=self._register,
313 + schedule=self._schedule, settings=pkgsettings,
314 + unregister=self._unregister)
315 retval = build.execute()
316 if retval != os.EX_OK:
317 raise self._pkg_failure(retval)
318 @@ -6661,7 +6841,9 @@
319 (mergecount, len(mymergelist), pkg_key)
320 emergelog(xterm_titles, msg, short_msg=short_msg)
321
322 - build = EbuildBuild(pkg=pkg, settings=pkgsettings)
323 + build = EbuildBuild(pkg=pkg, register=self._register,
324 + schedule=self._schedule, settings=pkgsettings,
325 + unregister=self._unregister)
326 retval = build.execute()
327 if retval != os.EX_OK:
328 raise self._pkg_failure(retval)
329 @@ -9297,7 +9479,7 @@
330 mymergelist = mydepgraph.altlist()
331 mydepgraph.break_refs(mymergelist)
332 mydepgraph.break_refs(mydepgraph.digraph.order)
333 - mergetask = MergeTask(settings, trees, mtimedb, myopts,
334 + mergetask = Scheduler(settings, trees, mtimedb, myopts,
335 spinner, mymergelist, favorites, mydepgraph.digraph)
336 del mydepgraph
337 clear_caches(trees)
338 @@ -9344,7 +9526,7 @@
339 mydepgraph.saveNomergeFavorites()
340 mydepgraph.break_refs(pkglist)
341 mydepgraph.break_refs(mydepgraph.digraph.order)
342 - mergetask = MergeTask(settings, trees, mtimedb, myopts,
343 + mergetask = Scheduler(settings, trees, mtimedb, myopts,
344 spinner, pkglist, favorites, mydepgraph.digraph)
345 del mydepgraph
346 clear_caches(trees)
347
348 Modified: main/branches/prefix/pym/portage/__init__.py
349 ===================================================================
350 --- main/branches/prefix/pym/portage/__init__.py 2008-07-01 16:59:40 UTC (rev 10878)
351 +++ main/branches/prefix/pym/portage/__init__.py 2008-07-01 17:09:13 UTC (rev 10879)
352 @@ -1405,7 +1405,7 @@
353
354 # Blacklist vars that could interfere with portage internals.
355 for blacklisted in "CATEGORY", "EBUILD_PHASE", \
356 - "PKGUSE", "PORTAGE_CONFIGROOT", \
357 + "EMERGE_FROM", "PKGUSE", "PORTAGE_CONFIGROOT", \
358 "PORTAGE_IUSE", "PORTAGE_USE", "ROOT", \
359 "EPREFIX", "EROOT":
360 for cfg in self.lookuplist:
361 @@ -2960,6 +2960,10 @@
362 env=mysettings.environ()
363 keywords["opt_name"]="[%s]" % mysettings["PF"]
364
365 + if keywords.get("returnpid"):
366 + # emerge handles logging externally
367 + keywords.pop("logfile", None)
368 +
369 fd_pipes = keywords.get("fd_pipes")
370 if fd_pipes is None:
371 fd_pipes = {
372 @@ -4180,11 +4184,15 @@
373 return 1
374
375 # parse actionmap to spawn ebuild with the appropriate args
376 -def spawnebuild(mydo,actionmap,mysettings,debug,alwaysdep=0,logfile=None):
377 - if alwaysdep or "noauto" not in mysettings.features:
378 +def spawnebuild(mydo, actionmap, mysettings, debug, alwaysdep=0,
379 + logfile=None, fd_pipes=None, returnpid=False):
380 + if not returnpid and \
381 + (alwaysdep or "noauto" not in mysettings.features):
382 # process dependency first
383 if "dep" in actionmap[mydo]:
384 - retval=spawnebuild(actionmap[mydo]["dep"],actionmap,mysettings,debug,alwaysdep=alwaysdep,logfile=logfile)
385 + retval = spawnebuild(actionmap[mydo]["dep"], actionmap,
386 + mysettings, debug, alwaysdep=alwaysdep, logfile=logfile,
387 + fd_pipes=fd_pipes, returnpid=returnpid)
388 if retval:
389 return retval
390 kwargs = actionmap[mydo]["args"]
391 @@ -4196,10 +4204,13 @@
392 mysettings._filter_calling_env = True
393 try:
394 phase_retval = spawn(actionmap[mydo]["cmd"] % mydo,
395 - mysettings, debug=debug, logfile=logfile, **kwargs)
396 + mysettings, debug=debug, logfile=logfile,
397 + fd_pipes=fd_pipes, returnpid=returnpid, **kwargs)
398 finally:
399 mysettings["EBUILD_PHASE"] = ""
400 mysettings._filter_calling_env = filter_calling_env_state
401 + if returnpid:
402 + return phase_retval
403 msg = _doebuild_exit_status_check(mydo, mysettings)
404 if msg:
405 phase_retval = 1
406 @@ -4208,138 +4219,174 @@
407 for l in wrap(msg, 72):
408 eerror(l, phase=mydo, key=mysettings.mycpv)
409
410 - if "userpriv" in mysettings.features and \
411 - not kwargs["droppriv"] and secpass >= 2:
412 + _post_phase_userpriv_perms(mysettings)
413 + if mydo == "install":
414 + _check_build_log(mysettings)
415 + if phase_retval == os.EX_OK:
416 + phase_retval = _post_src_install_checks(mysettings)
417 + return phase_retval
418 +
419 +def _post_phase_userpriv_perms(mysettings):
420 + if "userpriv" in mysettings.features and secpass >= 2:
421 """ Privileged phases may have left files that need to be made
422 writable to a less privileged user."""
423 apply_recursive_permissions(mysettings["T"],
424 uid=portage_uid, gid=portage_gid, dirmode=070, dirmask=0,
425 filemode=060, filemask=0)
426
427 - if phase_retval == os.EX_OK:
428 - if mydo == "install" and logfile:
429 - try:
430 - f = open(logfile, 'rb')
431 - except EnvironmentError:
432 - pass
433 - else:
434 - am_maintainer_mode = []
435 +def _post_src_install_checks(mysettings):
436 + _post_src_install_uid_fix(mysettings)
437 + retval = _spawn_misc_sh(mysettings, ["install_qa_check",
438 + "install_symlink_html_docs"])
439 + if retval != os.EX_OK:
440 + writemsg("!!! install_qa_check failed; exiting.\n",
441 + noiselevel=-1)
442 + return retval
443
444 - bash_command_not_found = []
445 - bash_command_not_found_re = re.compile(
446 - r'(.*): line (\d*): (.*): command not found$')
447 +def _check_build_log(mysettings):
448 + """
449 + Search the content of $PORTAGE_LOG_FILE if it exists
450 + and generate the following QA Notices when appropriate:
451
452 - configure_opts_warn = []
453 - configure_opts_warn_re = re.compile(
454 - r'^configure: WARNING: Unrecognized options: .*')
455 - am_maintainer_mode_re = re.compile(r'.*/missing --run .*')
456 - am_maintainer_mode_exclude_re = \
457 - re.compile(r'.*/missing --run (autoheader|makeinfo)')
458 - try:
459 - for line in f:
460 - if am_maintainer_mode_re.search(line) is not None and \
461 - am_maintainer_mode_exclude_re.search(line) is None:
462 - am_maintainer_mode.append(line.rstrip("\n"))
463 + * Automake "maintainer mode"
464 + * command not found
465 + * Unrecognized configure options
466 + """
467 + logfile = mysettings.get("PORTAGE_LOG_FILE")
468 + if logfile is None:
469 + return
470 + try:
471 + f = open(logfile, 'rb')
472 + except EnvironmentError:
473 + return
474
475 - if bash_command_not_found_re.match(line) is not None:
476 - bash_command_not_found.append(line.rstrip("\n"))
477 + am_maintainer_mode = []
478 + bash_command_not_found = []
479 + bash_command_not_found_re = re.compile(
480 + r'(.*): line (\d*): (.*): command not found$')
481
482 - if configure_opts_warn_re.match(line) is not None:
483 - configure_opts_warn.append(line.rstrip("\n"))
484 - finally:
485 - f.close()
486 + configure_opts_warn = []
487 + configure_opts_warn_re = re.compile(
488 + r'^configure: WARNING: Unrecognized options: .*')
489 + am_maintainer_mode_re = re.compile(r'.*/missing --run .*')
490 + am_maintainer_mode_exclude_re = \
491 + re.compile(r'.*/missing --run (autoheader|makeinfo)')
492 + try:
493 + for line in f:
494 + if am_maintainer_mode_re.search(line) is not None and \
495 + am_maintainer_mode_exclude_re.search(line) is None:
496 + am_maintainer_mode.append(line.rstrip("\n"))
497
498 - from portage.elog.messages import eqawarn
499 - def _eqawarn(lines):
500 - for line in lines:
501 - eqawarn(line, phase=mydo, key=mysettings.mycpv)
502 - from textwrap import wrap
503 - wrap_width = 70
504 + if bash_command_not_found_re.match(line) is not None:
505 + bash_command_not_found.append(line.rstrip("\n"))
506
507 - if am_maintainer_mode:
508 - msg = ["QA Notice: Automake \"maintainer mode\" detected:"]
509 - msg.append("")
510 - msg.extend("\t" + line for line in am_maintainer_mode)
511 - msg.append("")
512 - msg.extend(wrap(
513 - "If you patch Makefile.am, " + \
514 - "configure.in, or configure.ac then you " + \
515 - "should use autotools.eclass and " + \
516 - "eautomake or eautoreconf. Exceptions " + \
517 - "are limited to system packages " + \
518 - "for which it is impossible to run " + \
519 - "autotools during stage building. " + \
520 - "See http://www.gentoo.org/p" + \
521 - "roj/en/qa/autofailure.xml for more information.",
522 - wrap_width))
523 - _eqawarn(msg)
524 + if configure_opts_warn_re.match(line) is not None:
525 + configure_opts_warn.append(line.rstrip("\n"))
526 + finally:
527 + f.close()
528
529 - if bash_command_not_found:
530 - msg = ["QA Notice: command not found:"]
531 - msg.append("")
532 - msg.extend("\t" + line for line in bash_command_not_found)
533 - _eqawarn(msg)
534 + from portage.elog.messages import eqawarn
535 + def _eqawarn(lines):
536 + for line in lines:
537 + eqawarn(line, phase="install", key=mysettings.mycpv)
538 + from textwrap import wrap
539 + wrap_width = 70
540
541 - if configure_opts_warn:
542 - msg = ["QA Notice: Unrecognized configure options:"]
543 - msg.append("")
544 - msg.extend("\t" + line for line in configure_opts_warn)
545 - _eqawarn(msg)
546 + if am_maintainer_mode:
547 + msg = ["QA Notice: Automake \"maintainer mode\" detected:"]
548 + msg.append("")
549 + msg.extend("\t" + line for line in am_maintainer_mode)
550 + msg.append("")
551 + msg.extend(wrap(
552 + "If you patch Makefile.am, " + \
553 + "configure.in, or configure.ac then you " + \
554 + "should use autotools.eclass and " + \
555 + "eautomake or eautoreconf. Exceptions " + \
556 + "are limited to system packages " + \
557 + "for which it is impossible to run " + \
558 + "autotools during stage building. " + \
559 + "See http://www.gentoo.org/p" + \
560 + "roj/en/qa/autofailure.xml for more information.",
561 + wrap_width))
562 + _eqawarn(msg)
563
564 - if mydo == "install":
565 - # User and group bits that match the "portage" user or group are
566 - # automatically mapped to PORTAGE_INST_UID and PORTAGE_INST_GID if
567 - # necessary. The chown system call may clear S_ISUID and S_ISGID
568 - # bits, so those bits are restored if necessary.
569 - inst_uid = int(mysettings["PORTAGE_INST_UID"])
570 - inst_gid = int(mysettings["PORTAGE_INST_GID"])
571 - for parent, dirs, files in os.walk(mysettings["D"]):
572 - for fname in chain(dirs, files):
573 - fpath = os.path.join(parent, fname)
574 - mystat = os.lstat(fpath)
575 - if mystat.st_uid != portage_uid and \
576 - mystat.st_gid != portage_gid:
577 - continue
578 - myuid = -1
579 - mygid = -1
580 - if mystat.st_uid == portage_uid:
581 - myuid = inst_uid
582 - if mystat.st_gid == portage_gid:
583 - mygid = inst_gid
584 - apply_secpass_permissions(fpath, uid=myuid, gid=mygid,
585 - mode=mystat.st_mode, stat_cached=mystat,
586 - follow_links=False)
587 - # Note: PORTAGE_BIN_PATH may differ from the global
588 - # constant when portage is reinstalling itself.
589 - portage_bin_path = mysettings["PORTAGE_BIN_PATH"]
590 - misc_sh_binary = os.path.join(portage_bin_path,
591 - os.path.basename(MISC_SH_BINARY))
592 - mycommand = " ".join([_shell_quote(misc_sh_binary),
593 - "install_qa_check", "install_symlink_html_docs"])
594 - _doebuild_exit_status_unlink(
595 - mysettings.get("EBUILD_EXIT_STATUS_FILE"))
596 - filter_calling_env_state = mysettings._filter_calling_env
597 - if os.path.exists(os.path.join(mysettings["T"], "environment")):
598 - mysettings._filter_calling_env = True
599 - try:
600 - qa_retval = spawn(mycommand, mysettings, debug=debug,
601 - logfile=logfile, **kwargs)
602 - finally:
603 - mysettings._filter_calling_env = filter_calling_env_state
604 - msg = _doebuild_exit_status_check(mydo, mysettings)
605 - if msg:
606 - qa_retval = 1
607 - from textwrap import wrap
608 - from portage.elog.messages import eerror
609 - for l in wrap(msg, 72):
610 - eerror(l, phase=mydo, key=mysettings.mycpv)
611 - if qa_retval != os.EX_OK:
612 - writemsg("!!! install_qa_check failed; exiting.\n",
613 - noiselevel=-1)
614 - return qa_retval
615 - return phase_retval
616 + if bash_command_not_found:
617 + msg = ["QA Notice: command not found:"]
618 + msg.append("")
619 + msg.extend("\t" + line for line in bash_command_not_found)
620 + _eqawarn(msg)
621
622 + if configure_opts_warn:
623 + msg = ["QA Notice: Unrecognized configure options:"]
624 + msg.append("")
625 + msg.extend("\t" + line for line in configure_opts_warn)
626 + _eqawarn(msg)
627
628 +def _post_src_install_uid_fix(mysettings):
629 + """
630 + Files in $D with user and group bits that match the "portage"
631 + user or group are automatically mapped to PORTAGE_INST_UID and
632 + PORTAGE_INST_GID if necessary. The chown system call may clear
633 + S_ISUID and S_ISGID bits, so those bits are restored if
634 + necessary.
635 + """
636 + inst_uid = int(mysettings["PORTAGE_INST_UID"])
637 + inst_gid = int(mysettings["PORTAGE_INST_GID"])
638 + for parent, dirs, files in os.walk(mysettings["D"]):
639 + for fname in chain(dirs, files):
640 + fpath = os.path.join(parent, fname)
641 + mystat = os.lstat(fpath)
642 + if mystat.st_uid != portage_uid and \
643 + mystat.st_gid != portage_gid:
644 + continue
645 + myuid = -1
646 + mygid = -1
647 + if mystat.st_uid == portage_uid:
648 + myuid = inst_uid
649 + if mystat.st_gid == portage_gid:
650 + mygid = inst_gid
651 + apply_secpass_permissions(fpath, uid=myuid, gid=mygid,
652 + mode=mystat.st_mode, stat_cached=mystat,
653 + follow_links=False)
654 +
655 +def _spawn_misc_sh(mysettings, commands, **kwargs):
656 + """
657 + @param mysettings: the ebuild config
658 + @type mysettings: config
659 + @param commands: a list of function names to call in misc-functions.sh
660 + @type commands: list
661 + @rtype: int
662 + @returns: the return value from the spawn() call
663 + """
664 +
665 + # Note: PORTAGE_BIN_PATH may differ from the global
666 + # constant when portage is reinstalling itself.
667 + portage_bin_path = mysettings["PORTAGE_BIN_PATH"]
668 + misc_sh_binary = os.path.join(portage_bin_path,
669 + os.path.basename(MISC_SH_BINARY))
670 + mycommand = " ".join([_shell_quote(misc_sh_binary)] + commands)
671 + _doebuild_exit_status_unlink(
672 + mysettings.get("EBUILD_EXIT_STATUS_FILE"))
673 + filter_calling_env_state = mysettings._filter_calling_env
674 + if os.path.exists(os.path.join(mysettings["T"], "environment")):
675 + mysettings._filter_calling_env = True
676 + debug = mysettings.get("PORTAGE_DEBUG") == "1"
677 + logfile = mysettings.get("PORTAGE_LOG_FILE")
678 + mydo = mysettings["EBUILD_PHASE"]
679 + try:
680 + rval = spawn(mycommand, mysettings, debug=debug,
681 + logfile=logfile, **kwargs)
682 + finally:
683 + mysettings._filter_calling_env = filter_calling_env_state
684 + msg = _doebuild_exit_status_check(mydo, mysettings)
685 + if msg:
686 + rval = 1
687 + from textwrap import wrap
688 + from portage.elog.messages import eerror
689 + for l in wrap(msg, 72):
690 + eerror(l, phase=mydo, key=mysettings.mycpv)
691 + return rval
692 +
693 _eapi_prefix_re = re.compile("(^|\s*)%s($|\s*)" % portage.const.EAPIPREFIX)
694 _eapi_num_re = re.compile("(^|\s*)[0-9]+($|\s*)")
695
696 @@ -4793,8 +4840,9 @@
697
698 def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
699 fetchonly=0, cleanup=0, dbkey=None, use_cache=1, fetchall=0, tree=None,
700 - mydbapi=None, vartree=None, prev_mtimes=None):
701 -
702 + mydbapi=None, vartree=None, prev_mtimes=None,
703 + fd_pipes=None, returnpid=False):
704 +
705 """
706 Wrapper function that invokes specific ebuild phases through the spawning
707 of ebuild.sh
708 @@ -5206,7 +5254,10 @@
709 elif mydo == "setup":
710 retval = spawn(
711 _shell_quote(ebuild_sh_binary) + " " + mydo, mysettings,
712 - debug=debug, free=1, logfile=logfile)
713 + debug=debug, free=1, logfile=logfile, fd_pipes=fd_pipes,
714 + returnpid=returnpid)
715 + if returnpid:
716 + return retval
717 retval = exit_status_check(retval)
718 if secpass >= 2:
719 """ Privileged phases may have left files that need to be made
720 @@ -5315,7 +5366,10 @@
721 # unpack compile install`, we will try and fetch 4 times :/
722 need_distfiles = (mydo in ("fetch", "unpack") or \
723 mydo not in ("digest", "manifest") and "noauto" not in features)
724 - if need_distfiles and not fetch(
725 + emerge_skip_distfiles = "EMERGE_FROM" in mysettings and \
726 + mydo not in ("fetch", "unpack")
727 + if not emerge_skip_distfiles and \
728 + need_distfiles and not fetch(
729 fetchme, mysettings, listonly=listonly, fetchonly=fetchonly):
730 if have_build_dirs:
731 # Create an elog message for this fetch failure since the
732 @@ -5347,10 +5401,8 @@
733 return 1
734
735 # See above comment about fetching only when needed
736 - if not digestcheck(checkme, mysettings, ("strict" in features),
737 - (mydo not in ["digest","fetch","unpack"] and \
738 - mysettings.get("PORTAGE_CALLER", None) == "ebuild" and \
739 - "noauto" in features)):
740 + if not emerge_skip_distfiles and \
741 + not digestcheck(checkme, mysettings, "strict" in features):
742 return 1
743
744 if mydo == "fetch":
745 @@ -5435,7 +5487,8 @@
746 raise portage.exception.PermissionDenied(
747 "access('%s', os.W_OK)" % parent_dir)
748 retval = spawnebuild(mydo,
749 - actionmap, mysettings, debug, logfile=logfile)
750 + actionmap, mysettings, debug, logfile=logfile,
751 + fd_pipes=fd_pipes, returnpid=returnpid)
752 elif mydo=="qmerge":
753 # check to ensure install was run. this *only* pops up when users
754 # forget it and are using ebuild
755 @@ -5455,7 +5508,8 @@
756 mydbapi=mydbapi, vartree=vartree, prev_mtimes=prev_mtimes)
757 elif mydo=="merge":
758 retval = spawnebuild("install", actionmap, mysettings, debug,
759 - alwaysdep=1, logfile=logfile)
760 + alwaysdep=1, logfile=logfile, fd_pipes=fd_pipes,
761 + returnpid=returnpid)
762 retval = exit_status_check(retval)
763 if retval != os.EX_OK:
764 # The merge phase handles this already. Callers don't know how
765
766 --
767 gentoo-commits@l.g.o mailing list