Gentoo Archives: gentoo-commits

From: "Fabian Groffen (grobian)" <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r13704 - main/branches/prefix/pym/_emerge
Date: Sat, 27 Jun 2009 12:51:45
Message-Id: E1MKXNO-0004sJ-Ly@stork.gentoo.org
1 Author: grobian
2 Date: 2009-06-27 12:51:25 +0000 (Sat, 27 Jun 2009)
3 New Revision: 13704
4
5 Added:
6 main/branches/prefix/pym/_emerge/AbstractDepPriority.py
7 main/branches/prefix/pym/_emerge/AbstractPollTask.py
8 main/branches/prefix/pym/_emerge/AsynchronousTask.py
9 main/branches/prefix/pym/_emerge/AtomArg.py
10 main/branches/prefix/pym/_emerge/Binpkg.py
11 main/branches/prefix/pym/_emerge/BinpkgExtractorAsync.py
12 main/branches/prefix/pym/_emerge/BinpkgFetcher.py
13 main/branches/prefix/pym/_emerge/BinpkgPrefetcher.py
14 main/branches/prefix/pym/_emerge/BinpkgVerifier.py
15 main/branches/prefix/pym/_emerge/Blocker.py
16 main/branches/prefix/pym/_emerge/BlockerCache.py
17 main/branches/prefix/pym/_emerge/BlockerDepPriority.py
18 main/branches/prefix/pym/_emerge/CompositeTask.py
19 main/branches/prefix/pym/_emerge/DepPriority.py
20 main/branches/prefix/pym/_emerge/DepPriorityNormalRange.py
21 main/branches/prefix/pym/_emerge/DepPrioritySatisfiedRange.py
22 main/branches/prefix/pym/_emerge/Dependency.py
23 main/branches/prefix/pym/_emerge/DependencyArg.py
24 main/branches/prefix/pym/_emerge/EbuildBinpkg.py
25 main/branches/prefix/pym/_emerge/EbuildBuild.py
26 main/branches/prefix/pym/_emerge/EbuildBuildDir.py
27 main/branches/prefix/pym/_emerge/EbuildExecuter.py
28 main/branches/prefix/pym/_emerge/EbuildFetcher.py
29 main/branches/prefix/pym/_emerge/EbuildFetchonly.py
30 main/branches/prefix/pym/_emerge/EbuildMerge.py
31 main/branches/prefix/pym/_emerge/EbuildMetadataPhase.py
32 main/branches/prefix/pym/_emerge/EbuildPhase.py
33 main/branches/prefix/pym/_emerge/EbuildProcess.py
34 main/branches/prefix/pym/_emerge/MiscFunctionsProcess.py
35 main/branches/prefix/pym/_emerge/PackageArg.py
36 main/branches/prefix/pym/_emerge/PackageMerge.py
37 main/branches/prefix/pym/_emerge/PackageVirtualDbapi.py
38 main/branches/prefix/pym/_emerge/PipeReader.py
39 main/branches/prefix/pym/_emerge/PollConstants.py
40 main/branches/prefix/pym/_emerge/PollSelectAdapter.py
41 main/branches/prefix/pym/_emerge/ProgressHandler.py
42 main/branches/prefix/pym/_emerge/RepoDisplay.py
43 main/branches/prefix/pym/_emerge/SequentialTaskQueue.py
44 main/branches/prefix/pym/_emerge/SetArg.py
45 main/branches/prefix/pym/_emerge/SlotObject.py
46 main/branches/prefix/pym/_emerge/SpawnProcess.py
47 main/branches/prefix/pym/_emerge/SubProcess.py
48 main/branches/prefix/pym/_emerge/Task.py
49 main/branches/prefix/pym/_emerge/TaskSequence.py
50 main/branches/prefix/pym/_emerge/UnmergeDepPriority.py
51 main/branches/prefix/pym/_emerge/UseFlagDisplay.py
52 Modified:
53 main/branches/prefix/pym/_emerge/__init__.py
54 main/branches/prefix/pym/_emerge/help.py
55 Log:
56 Merged from trunk -r13662:13663, tried to re-apply all Prefix patches,
57 but unfortunately the code was changed next to just being split.
58
59 | 13663 | Bug #275047 - Split _emerge/__init__.py into smaller pieces. |
60 | zmedico | Thanks to Sebastian Mingramm (few) <s.mingramm@×××.de> for |
61 | | this patch. |
62
63
64 Copied: main/branches/prefix/pym/_emerge/AbstractDepPriority.py (from rev 13663, main/trunk/pym/_emerge/AbstractDepPriority.py)
65 ===================================================================
66 --- main/branches/prefix/pym/_emerge/AbstractDepPriority.py (rev 0)
67 +++ main/branches/prefix/pym/_emerge/AbstractDepPriority.py 2009-06-27 12:51:25 UTC (rev 13704)
68 @@ -0,0 +1,26 @@
69 +from _emerge.SlotObject import SlotObject
70 +class AbstractDepPriority(SlotObject):
71 + __slots__ = ("buildtime", "runtime", "runtime_post")
72 +
73 + def __lt__(self, other):
74 + return self.__int__() < other
75 +
76 + def __le__(self, other):
77 + return self.__int__() <= other
78 +
79 + def __eq__(self, other):
80 + return self.__int__() == other
81 +
82 + def __ne__(self, other):
83 + return self.__int__() != other
84 +
85 + def __gt__(self, other):
86 + return self.__int__() > other
87 +
88 + def __ge__(self, other):
89 + return self.__int__() >= other
90 +
91 + def copy(self):
92 + import copy
93 + return copy.copy(self)
94 +
95
96 Copied: main/branches/prefix/pym/_emerge/AbstractPollTask.py (from rev 13663, main/trunk/pym/_emerge/AbstractPollTask.py)
97 ===================================================================
98 --- main/branches/prefix/pym/_emerge/AbstractPollTask.py (rev 0)
99 +++ main/branches/prefix/pym/_emerge/AbstractPollTask.py 2009-06-27 12:51:25 UTC (rev 13704)
100 @@ -0,0 +1,24 @@
101 +from _emerge.AsynchronousTask import AsynchronousTask
102 +from _emerge.PollConstants import PollConstants
103 +class AbstractPollTask(AsynchronousTask):
104 +
105 + __slots__ = ("scheduler",) + \
106 + ("_registered",)
107 +
108 + _bufsize = 4096
109 + _exceptional_events = PollConstants.POLLERR | PollConstants.POLLNVAL
110 + _registered_events = PollConstants.POLLIN | PollConstants.POLLHUP | \
111 + _exceptional_events
112 +
113 + def _unregister(self):
114 + raise NotImplementedError(self)
115 +
116 + def _unregister_if_appropriate(self, event):
117 + if self._registered:
118 + if event & self._exceptional_events:
119 + self._unregister()
120 + self.cancel()
121 + elif event & PollConstants.POLLHUP:
122 + self._unregister()
123 + self.wait()
124 +
125
126 Copied: main/branches/prefix/pym/_emerge/AsynchronousTask.py (from rev 13663, main/trunk/pym/_emerge/AsynchronousTask.py)
127 ===================================================================
128 --- main/branches/prefix/pym/_emerge/AsynchronousTask.py (rev 0)
129 +++ main/branches/prefix/pym/_emerge/AsynchronousTask.py 2009-06-27 12:51:25 UTC (rev 13704)
130 @@ -0,0 +1,112 @@
131 +from _emerge.SlotObject import SlotObject
132 +class AsynchronousTask(SlotObject):
133 + """
134 + Subclasses override _wait() and _poll() so that calls
135 + to public methods can be wrapped for implementing
136 + hooks such as exit listener notification.
137 +
138 + Sublasses should call self.wait() to notify exit listeners after
139 + the task is complete and self.returncode has been set.
140 + """
141 +
142 + __slots__ = ("background", "cancelled", "returncode") + \
143 + ("_exit_listeners", "_exit_listener_stack", "_start_listeners")
144 +
145 + def start(self):
146 + """
147 + Start an asynchronous task and then return as soon as possible.
148 + """
149 + self._start_hook()
150 + self._start()
151 +
152 + def _start(self):
153 + raise NotImplementedError(self)
154 +
155 + def isAlive(self):
156 + return self.returncode is None
157 +
158 + def poll(self):
159 + self._wait_hook()
160 + return self._poll()
161 +
162 + def _poll(self):
163 + return self.returncode
164 +
165 + def wait(self):
166 + if self.returncode is None:
167 + self._wait()
168 + self._wait_hook()
169 + return self.returncode
170 +
171 + def _wait(self):
172 + return self.returncode
173 +
174 + def cancel(self):
175 + self.cancelled = True
176 + self.wait()
177 +
178 + def addStartListener(self, f):
179 + """
180 + The function will be called with one argument, a reference to self.
181 + """
182 + if self._start_listeners is None:
183 + self._start_listeners = []
184 + self._start_listeners.append(f)
185 +
186 + def removeStartListener(self, f):
187 + if self._start_listeners is None:
188 + return
189 + self._start_listeners.remove(f)
190 +
191 + def _start_hook(self):
192 + if self._start_listeners is not None:
193 + start_listeners = self._start_listeners
194 + self._start_listeners = None
195 +
196 + for f in start_listeners:
197 + f(self)
198 +
199 + def addExitListener(self, f):
200 + """
201 + The function will be called with one argument, a reference to self.
202 + """
203 + if self._exit_listeners is None:
204 + self._exit_listeners = []
205 + self._exit_listeners.append(f)
206 +
207 + def removeExitListener(self, f):
208 + if self._exit_listeners is None:
209 + if self._exit_listener_stack is not None:
210 + self._exit_listener_stack.remove(f)
211 + return
212 + self._exit_listeners.remove(f)
213 +
214 + def _wait_hook(self):
215 + """
216 + Call this method after the task completes, just before returning
217 + the returncode from wait() or poll(). This hook is
218 + used to trigger exit listeners when the returncode first
219 + becomes available.
220 + """
221 + if self.returncode is not None and \
222 + self._exit_listeners is not None:
223 +
224 + # This prevents recursion, in case one of the
225 + # exit handlers triggers this method again by
226 + # calling wait(). Use a stack that gives
227 + # removeExitListener() an opportunity to consume
228 + # listeners from the stack, before they can get
229 + # called below. This is necessary because a call
230 + # to one exit listener may result in a call to
231 + # removeExitListener() for another listener on
232 + # the stack. That listener needs to be removed
233 + # from the stack since it would be inconsistent
234 + # to call it after it has been been passed into
235 + # removeExitListener().
236 + self._exit_listener_stack = self._exit_listeners
237 + self._exit_listeners = None
238 +
239 + self._exit_listener_stack.reverse()
240 + while self._exit_listener_stack:
241 + self._exit_listener_stack.pop()(self)
242 +
243
244 Copied: main/branches/prefix/pym/_emerge/AtomArg.py (from rev 13663, main/trunk/pym/_emerge/AtomArg.py)
245 ===================================================================
246 --- main/branches/prefix/pym/_emerge/AtomArg.py (rev 0)
247 +++ main/branches/prefix/pym/_emerge/AtomArg.py 2009-06-27 12:51:25 UTC (rev 13704)
248 @@ -0,0 +1,19 @@
249 +from _emerge.DependencyArg import DependencyArg
250 +
251 +# for an explanation on this logic, see pym/_emerge/__init__.py
252 +import os
253 +import sys
254 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
255 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
256 +else:
257 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
258 +import portage
259 +
260 +class AtomArg(DependencyArg):
261 + def __init__(self, atom=None, **kwargs):
262 + DependencyArg.__init__(self, **kwargs)
263 + self.atom = atom
264 + if not isinstance(self.atom, portage.dep.Atom):
265 + self.atom = portage.dep.Atom(self.atom)
266 + self.set = (self.atom, )
267 +
268
269 Copied: main/branches/prefix/pym/_emerge/Binpkg.py (from rev 13663, main/trunk/pym/_emerge/Binpkg.py)
270 ===================================================================
271 --- main/branches/prefix/pym/_emerge/Binpkg.py (rev 0)
272 +++ main/branches/prefix/pym/_emerge/Binpkg.py 2009-06-27 12:51:25 UTC (rev 13704)
273 @@ -0,0 +1,301 @@
274 +from _emerge.EbuildPhase import EbuildPhase
275 +from _emerge.BinpkgFetcher import BinpkgFetcher
276 +from _emerge.BinpkgExtractorAsync import BinpkgExtractorAsync
277 +from _emerge.CompositeTask import CompositeTask
278 +from _emerge.BinpkgVerifier import BinpkgVerifier
279 +from _emerge.EbuildMerge import EbuildMerge
280 +from _emerge.EbuildBuildDir import EbuildBuildDir
281 +from portage.util import writemsg
282 +# for an explanation on this logic, see pym/_emerge/__init__.py
283 +import os
284 +import sys
285 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
286 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
287 +else:
288 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
289 +import portage
290 +from portage.output import colorize
291 +class Binpkg(CompositeTask):
292 +
293 + __slots__ = ("find_blockers",
294 + "ldpath_mtimes", "logger", "opts",
295 + "pkg", "pkg_count", "prefetcher", "settings", "world_atom") + \
296 + ("_bintree", "_build_dir", "_ebuild_path", "_fetched_pkg",
297 + "_image_dir", "_infloc", "_pkg_path", "_tree", "_verify")
298 +
299 + def _writemsg_level(self, msg, level=0, noiselevel=0):
300 +
301 + if not self.background:
302 + portage.util.writemsg_level(msg,
303 + level=level, noiselevel=noiselevel)
304 +
305 + log_path = self.settings.get("PORTAGE_LOG_FILE")
306 + if log_path is not None:
307 + f = open(log_path, 'a')
308 + try:
309 + f.write(msg)
310 + finally:
311 + f.close()
312 +
313 + def _start(self):
314 +
315 + pkg = self.pkg
316 + settings = self.settings
317 + settings.setcpv(pkg)
318 + self._tree = "bintree"
319 + self._bintree = self.pkg.root_config.trees[self._tree]
320 + self._verify = not self.opts.pretend
321 +
322 + dir_path = os.path.join(settings["PORTAGE_TMPDIR"],
323 + "portage", pkg.category, pkg.pf)
324 + self._build_dir = EbuildBuildDir(dir_path=dir_path,
325 + pkg=pkg, settings=settings)
326 + self._image_dir = os.path.join(dir_path, "image")
327 + self._infloc = os.path.join(dir_path, "build-info")
328 + self._ebuild_path = os.path.join(self._infloc, pkg.pf + ".ebuild")
329 + settings["EBUILD"] = self._ebuild_path
330 + debug = settings.get("PORTAGE_DEBUG") == "1"
331 + portage.doebuild_environment(self._ebuild_path, "setup",
332 + settings["ROOT"], settings, debug, 1, self._bintree.dbapi)
333 + settings.configdict["pkg"]["EMERGE_FROM"] = pkg.type_name
334 +
335 + # The prefetcher has already completed or it
336 + # could be running now. If it's running now,
337 + # wait for it to complete since it holds
338 + # a lock on the file being fetched. The
339 + # portage.locks functions are only designed
340 + # to work between separate processes. Since
341 + # the lock is held by the current process,
342 + # use the scheduler and fetcher methods to
343 + # synchronize with the fetcher.
344 + prefetcher = self.prefetcher
345 + if prefetcher is None:
346 + pass
347 + elif not prefetcher.isAlive():
348 + prefetcher.cancel()
349 + elif prefetcher.poll() is None:
350 +
351 + waiting_msg = ("Fetching '%s' " + \
352 + "in the background. " + \
353 + "To view fetch progress, run `tail -f " + \
354 + "/var/log/emerge-fetch.log` in another " + \
355 + "terminal.") % prefetcher.pkg_path
356 + msg_prefix = colorize("GOOD", " * ")
357 + from textwrap import wrap
358 + waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \
359 + for line in wrap(waiting_msg, 65))
360 + if not self.background:
361 + writemsg(waiting_msg, noiselevel=-1)
362 +
363 + self._current_task = prefetcher
364 + prefetcher.addExitListener(self._prefetch_exit)
365 + return
366 +
367 + self._prefetch_exit(prefetcher)
368 +
369 + def _prefetch_exit(self, prefetcher):
370 +
371 + pkg = self.pkg
372 + pkg_count = self.pkg_count
373 + if not (self.opts.pretend or self.opts.fetchonly):
374 + self._build_dir.lock()
375 + # If necessary, discard old log so that we don't
376 + # append to it.
377 + self._build_dir.clean_log()
378 + # Initialze PORTAGE_LOG_FILE.
379 + portage.prepare_build_dirs(self.settings["ROOT"], self.settings, 1)
380 + fetcher = BinpkgFetcher(background=self.background,
381 + logfile=self.settings.get("PORTAGE_LOG_FILE"), pkg=self.pkg,
382 + pretend=self.opts.pretend, scheduler=self.scheduler)
383 + pkg_path = fetcher.pkg_path
384 + self._pkg_path = pkg_path
385 +
386 + if self.opts.getbinpkg and self._bintree.isremote(pkg.cpv):
387 +
388 + msg = " --- (%s of %s) Fetching Binary (%s::%s)" %\
389 + (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path)
390 + short_msg = "emerge: (%s of %s) %s Fetch" % \
391 + (pkg_count.curval, pkg_count.maxval, pkg.cpv)
392 + self.logger.log(msg, short_msg=short_msg)
393 + self._start_task(fetcher, self._fetcher_exit)
394 + return
395 +
396 + self._fetcher_exit(fetcher)
397 +
398 + def _fetcher_exit(self, fetcher):
399 +
400 + # The fetcher only has a returncode when
401 + # --getbinpkg is enabled.
402 + if fetcher.returncode is not None:
403 + self._fetched_pkg = True
404 + if self._default_exit(fetcher) != os.EX_OK:
405 + self._unlock_builddir()
406 + self.wait()
407 + return
408 +
409 + if self.opts.pretend:
410 + self._current_task = None
411 + self.returncode = os.EX_OK
412 + self.wait()
413 + return
414 +
415 + verifier = None
416 + if self._verify:
417 + logfile = None
418 + if self.background:
419 + logfile = self.settings.get("PORTAGE_LOG_FILE")
420 + verifier = BinpkgVerifier(background=self.background,
421 + logfile=logfile, pkg=self.pkg)
422 + self._start_task(verifier, self._verifier_exit)
423 + return
424 +
425 + self._verifier_exit(verifier)
426 +
427 + def _verifier_exit(self, verifier):
428 + if verifier is not None and \
429 + self._default_exit(verifier) != os.EX_OK:
430 + self._unlock_builddir()
431 + self.wait()
432 + return
433 +
434 + logger = self.logger
435 + pkg = self.pkg
436 + pkg_count = self.pkg_count
437 + pkg_path = self._pkg_path
438 +
439 + if self._fetched_pkg:
440 + self._bintree.inject(pkg.cpv, filename=pkg_path)
441 +
442 + if self.opts.fetchonly:
443 + self._current_task = None
444 + self.returncode = os.EX_OK
445 + self.wait()
446 + return
447 +
448 + msg = " === (%s of %s) Merging Binary (%s::%s)" % \
449 + (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path)
450 + short_msg = "emerge: (%s of %s) %s Merge Binary" % \
451 + (pkg_count.curval, pkg_count.maxval, pkg.cpv)
452 + logger.log(msg, short_msg=short_msg)
453 +
454 + phase = "clean"
455 + settings = self.settings
456 + ebuild_phase = EbuildPhase(background=self.background,
457 + pkg=pkg, phase=phase, scheduler=self.scheduler,
458 + settings=settings, tree=self._tree)
459 +
460 + self._start_task(ebuild_phase, self._clean_exit)
461 +
462 + def _clean_exit(self, clean_phase):
463 + if self._default_exit(clean_phase) != os.EX_OK:
464 + self._unlock_builddir()
465 + self.wait()
466 + return
467 +
468 + dir_path = self._build_dir.dir_path
469 +
470 + infloc = self._infloc
471 + pkg = self.pkg
472 + pkg_path = self._pkg_path
473 +
474 + dir_mode = 0755
475 + for mydir in (dir_path, self._image_dir, infloc):
476 + portage.util.ensure_dirs(mydir, uid=portage.data.portage_uid,
477 + gid=portage.data.portage_gid, mode=dir_mode)
478 +
479 + # This initializes PORTAGE_LOG_FILE.
480 + portage.prepare_build_dirs(self.settings["ROOT"], self.settings, 1)
481 + self._writemsg_level(">>> Extracting info\n")
482 +
483 + pkg_xpak = portage.xpak.tbz2(self._pkg_path)
484 + check_missing_metadata = ("CATEGORY", "PF")
485 + missing_metadata = set()
486 + for k in check_missing_metadata:
487 + v = pkg_xpak.getfile(k)
488 + if not v:
489 + missing_metadata.add(k)
490 +
491 + pkg_xpak.unpackinfo(infloc)
492 + for k in missing_metadata:
493 + if k == "CATEGORY":
494 + v = pkg.category
495 + elif k == "PF":
496 + v = pkg.pf
497 + else:
498 + continue
499 +
500 + f = open(os.path.join(infloc, k), 'wb')
501 + try:
502 + f.write(v + "\n")
503 + finally:
504 + f.close()
505 +
506 + # Store the md5sum in the vdb.
507 + f = open(os.path.join(infloc, "BINPKGMD5"), "w")
508 + try:
509 + f.write(str(portage.checksum.perform_md5(pkg_path)) + "\n")
510 + finally:
511 + f.close()
512 +
513 + # This gives bashrc users an opportunity to do various things
514 + # such as remove binary packages after they're installed.
515 + settings = self.settings
516 + settings.setcpv(self.pkg)
517 + settings["PORTAGE_BINPKG_FILE"] = pkg_path
518 + settings.backup_changes("PORTAGE_BINPKG_FILE")
519 +
520 + phase = "setup"
521 + setup_phase = EbuildPhase(background=self.background,
522 + pkg=self.pkg, phase=phase, scheduler=self.scheduler,
523 + settings=settings, tree=self._tree)
524 +
525 + setup_phase.addExitListener(self._setup_exit)
526 + self._current_task = setup_phase
527 + self.scheduler.scheduleSetup(setup_phase)
528 +
529 + def _setup_exit(self, setup_phase):
530 + if self._default_exit(setup_phase) != os.EX_OK:
531 + self._unlock_builddir()
532 + self.wait()
533 + return
534 +
535 + extractor = BinpkgExtractorAsync(background=self.background,
536 + image_dir=self._image_dir,
537 + pkg=self.pkg, pkg_path=self._pkg_path, scheduler=self.scheduler)
538 + self._writemsg_level(">>> Extracting %s\n" % self.pkg.cpv)
539 + self._start_task(extractor, self._extractor_exit)
540 +
541 + def _extractor_exit(self, extractor):
542 + if self._final_exit(extractor) != os.EX_OK:
543 + self._unlock_builddir()
544 + writemsg("!!! Error Extracting '%s'\n" % self._pkg_path,
545 + noiselevel=-1)
546 + self.wait()
547 +
548 + def _unlock_builddir(self):
549 + if self.opts.pretend or self.opts.fetchonly:
550 + return
551 + portage.elog.elog_process(self.pkg.cpv, self.settings)
552 + self._build_dir.unlock()
553 +
554 + def install(self):
555 +
556 + # This gives bashrc users an opportunity to do various things
557 + # such as remove binary packages after they're installed.
558 + settings = self.settings
559 + settings["PORTAGE_BINPKG_FILE"] = self._pkg_path
560 + settings.backup_changes("PORTAGE_BINPKG_FILE")
561 +
562 + merge = EbuildMerge(find_blockers=self.find_blockers,
563 + ldpath_mtimes=self.ldpath_mtimes, logger=self.logger,
564 + pkg=self.pkg, pkg_count=self.pkg_count,
565 + pkg_path=self._pkg_path, scheduler=self.scheduler,
566 + settings=settings, tree=self._tree, world_atom=self.world_atom)
567 +
568 + try:
569 + retval = merge.execute()
570 + finally:
571 + settings.pop("PORTAGE_BINPKG_FILE", None)
572 + self._unlock_builddir()
573 + return retval
574 +
575
576 Copied: main/branches/prefix/pym/_emerge/BinpkgExtractorAsync.py (from rev 13663, main/trunk/pym/_emerge/BinpkgExtractorAsync.py)
577 ===================================================================
578 --- main/branches/prefix/pym/_emerge/BinpkgExtractorAsync.py (rev 0)
579 +++ main/branches/prefix/pym/_emerge/BinpkgExtractorAsync.py 2009-06-27 12:51:25 UTC (rev 13704)
580 @@ -0,0 +1,24 @@
581 +from _emerge.SpawnProcess import SpawnProcess
582 +# for an explanation on this logic, see pym/_emerge/__init__.py
583 +import os
584 +import sys
585 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
586 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
587 +else:
588 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
589 +import portage
590 +class BinpkgExtractorAsync(SpawnProcess):
591 +
592 + __slots__ = ("image_dir", "pkg", "pkg_path")
593 +
594 + _shell_binary = portage.const.BASH_BINARY
595 +
596 + def _start(self):
597 + self.args = [self._shell_binary, "-c",
598 + "bzip2 -dqc -- %s | tar -xp -C %s -f -" % \
599 + (portage._shell_quote(self.pkg_path),
600 + portage._shell_quote(self.image_dir))]
601 +
602 + self.env = self.pkg.root_config.settings.environ()
603 + SpawnProcess._start(self)
604 +
605
606 Copied: main/branches/prefix/pym/_emerge/BinpkgFetcher.py (from rev 13663, main/trunk/pym/_emerge/BinpkgFetcher.py)
607 ===================================================================
608 --- main/branches/prefix/pym/_emerge/BinpkgFetcher.py (rev 0)
609 +++ main/branches/prefix/pym/_emerge/BinpkgFetcher.py 2009-06-27 12:51:25 UTC (rev 13704)
610 @@ -0,0 +1,151 @@
611 +from _emerge.SpawnProcess import SpawnProcess
612 +import urlparse
613 +import sys
614 +import shlex
615 +# for an explanation on this logic, see pym/_emerge/__init__.py
616 +import os
617 +import sys
618 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
619 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
620 +else:
621 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
622 +import portage
623 +class BinpkgFetcher(SpawnProcess):
624 +
625 + __slots__ = ("pkg", "pretend",
626 + "locked", "pkg_path", "_lock_obj")
627 +
628 + def __init__(self, **kwargs):
629 + SpawnProcess.__init__(self, **kwargs)
630 + pkg = self.pkg
631 + self.pkg_path = pkg.root_config.trees["bintree"].getname(pkg.cpv)
632 +
633 + def _start(self):
634 +
635 + if self.cancelled:
636 + return
637 +
638 + pkg = self.pkg
639 + pretend = self.pretend
640 + bintree = pkg.root_config.trees["bintree"]
641 + settings = bintree.settings
642 + use_locks = "distlocks" in settings.features
643 + pkg_path = self.pkg_path
644 +
645 + if not pretend:
646 + portage.util.ensure_dirs(os.path.dirname(pkg_path))
647 + if use_locks:
648 + self.lock()
649 + exists = os.path.exists(pkg_path)
650 + resume = exists and os.path.basename(pkg_path) in bintree.invalids
651 + if not (pretend or resume):
652 + # Remove existing file or broken symlink.
653 + try:
654 + os.unlink(pkg_path)
655 + except OSError:
656 + pass
657 +
658 + # urljoin doesn't work correctly with
659 + # unrecognized protocols like sftp
660 + if bintree._remote_has_index:
661 + rel_uri = bintree._remotepkgs[pkg.cpv].get("PATH")
662 + if not rel_uri:
663 + rel_uri = pkg.cpv + ".tbz2"
664 + uri = bintree._remote_base_uri.rstrip("/") + \
665 + "/" + rel_uri.lstrip("/")
666 + else:
667 + uri = settings["PORTAGE_BINHOST"].rstrip("/") + \
668 + "/" + pkg.pf + ".tbz2"
669 +
670 + if pretend:
671 + portage.writemsg_stdout("\n%s\n" % uri, noiselevel=-1)
672 + self.returncode = os.EX_OK
673 + self.wait()
674 + return
675 +
676 + protocol = urlparse.urlparse(uri)[0]
677 + fcmd_prefix = "FETCHCOMMAND"
678 + if resume:
679 + fcmd_prefix = "RESUMECOMMAND"
680 + fcmd = settings.get(fcmd_prefix + "_" + protocol.upper())
681 + if not fcmd:
682 + fcmd = settings.get(fcmd_prefix)
683 +
684 + fcmd_vars = {
685 + "DISTDIR" : os.path.dirname(pkg_path),
686 + "URI" : uri,
687 + "FILE" : os.path.basename(pkg_path)
688 + }
689 +
690 + fetch_env = dict(settings.iteritems())
691 + fetch_args = [portage.util.varexpand(x, mydict=fcmd_vars) \
692 + for x in shlex.split(fcmd)]
693 +
694 + if self.fd_pipes is None:
695 + self.fd_pipes = {}
696 + fd_pipes = self.fd_pipes
697 +
698 + # Redirect all output to stdout since some fetchers like
699 + # wget pollute stderr (if portage detects a problem then it
700 + # can send it's own message to stderr).
701 + fd_pipes.setdefault(0, sys.stdin.fileno())
702 + fd_pipes.setdefault(1, sys.stdout.fileno())
703 + fd_pipes.setdefault(2, sys.stdout.fileno())
704 +
705 + self.args = fetch_args
706 + self.env = fetch_env
707 + SpawnProcess._start(self)
708 +
709 + def _set_returncode(self, wait_retval):
710 + SpawnProcess._set_returncode(self, wait_retval)
711 + if self.returncode == os.EX_OK:
712 + # If possible, update the mtime to match the remote package if
713 + # the fetcher didn't already do it automatically.
714 + bintree = self.pkg.root_config.trees["bintree"]
715 + if bintree._remote_has_index:
716 + remote_mtime = bintree._remotepkgs[self.pkg.cpv].get("MTIME")
717 + if remote_mtime is not None:
718 + try:
719 + remote_mtime = long(remote_mtime)
720 + except ValueError:
721 + pass
722 + else:
723 + try:
724 + local_mtime = long(os.stat(self.pkg_path).st_mtime)
725 + except OSError:
726 + pass
727 + else:
728 + if remote_mtime != local_mtime:
729 + try:
730 + os.utime(self.pkg_path,
731 + (remote_mtime, remote_mtime))
732 + except OSError:
733 + pass
734 +
735 + if self.locked:
736 + self.unlock()
737 +
738 + def lock(self):
739 + """
740 + This raises an AlreadyLocked exception if lock() is called
741 + while a lock is already held. In order to avoid this, call
742 + unlock() or check whether the "locked" attribute is True
743 + or False before calling lock().
744 + """
745 + if self._lock_obj is not None:
746 + raise self.AlreadyLocked((self._lock_obj,))
747 +
748 + self._lock_obj = portage.locks.lockfile(
749 + self.pkg_path, wantnewlockfile=1)
750 + self.locked = True
751 +
752 + class AlreadyLocked(portage.exception.PortageException):
753 + pass
754 +
755 + def unlock(self):
756 + if self._lock_obj is None:
757 + return
758 + portage.locks.unlockfile(self._lock_obj)
759 + self._lock_obj = None
760 + self.locked = False
761 +
762
763 Copied: main/branches/prefix/pym/_emerge/BinpkgPrefetcher.py (from rev 13663, main/trunk/pym/_emerge/BinpkgPrefetcher.py)
764 ===================================================================
765 --- main/branches/prefix/pym/_emerge/BinpkgPrefetcher.py (rev 0)
766 +++ main/branches/prefix/pym/_emerge/BinpkgPrefetcher.py 2009-06-27 12:51:25 UTC (rev 13704)
767 @@ -0,0 +1,38 @@
768 +from _emerge.BinpkgFetcher import BinpkgFetcher
769 +from _emerge.CompositeTask import CompositeTask
770 +from _emerge.BinpkgVerifier import BinpkgVerifier
771 +import os
772 +class BinpkgPrefetcher(CompositeTask):
773 +
774 + __slots__ = ("pkg",) + \
775 + ("pkg_path", "_bintree",)
776 +
777 + def _start(self):
778 + self._bintree = self.pkg.root_config.trees["bintree"]
779 + fetcher = BinpkgFetcher(background=self.background,
780 + logfile=self.scheduler.fetch.log_file, pkg=self.pkg,
781 + scheduler=self.scheduler)
782 + self.pkg_path = fetcher.pkg_path
783 + self._start_task(fetcher, self._fetcher_exit)
784 +
785 + def _fetcher_exit(self, fetcher):
786 +
787 + if self._default_exit(fetcher) != os.EX_OK:
788 + self.wait()
789 + return
790 +
791 + verifier = BinpkgVerifier(background=self.background,
792 + logfile=self.scheduler.fetch.log_file, pkg=self.pkg)
793 + self._start_task(verifier, self._verifier_exit)
794 +
795 + def _verifier_exit(self, verifier):
796 + if self._default_exit(verifier) != os.EX_OK:
797 + self.wait()
798 + return
799 +
800 + self._bintree.inject(self.pkg.cpv, filename=self.pkg_path)
801 +
802 + self._current_task = None
803 + self.returncode = os.EX_OK
804 + self.wait()
805 +
806
807 Copied: main/branches/prefix/pym/_emerge/BinpkgVerifier.py (from rev 13663, main/trunk/pym/_emerge/BinpkgVerifier.py)
808 ===================================================================
809 --- main/branches/prefix/pym/_emerge/BinpkgVerifier.py (rev 0)
810 +++ main/branches/prefix/pym/_emerge/BinpkgVerifier.py 2009-06-27 12:51:25 UTC (rev 13704)
811 @@ -0,0 +1,67 @@
812 +from _emerge.AsynchronousTask import AsynchronousTask
813 +from portage.util import writemsg
814 +import sys
815 +# for an explanation on this logic, see pym/_emerge/__init__.py
816 +import os
817 +import sys
818 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
819 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
820 +else:
821 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
822 +import portage
823 +class BinpkgVerifier(AsynchronousTask):
824 + __slots__ = ("logfile", "pkg",)
825 +
826 + def _start(self):
827 + """
828 + Note: Unlike a normal AsynchronousTask.start() method,
829 + this one does all work is synchronously. The returncode
830 + attribute will be set before it returns.
831 + """
832 +
833 + pkg = self.pkg
834 + root_config = pkg.root_config
835 + bintree = root_config.trees["bintree"]
836 + rval = os.EX_OK
837 + stdout_orig = sys.stdout
838 + stderr_orig = sys.stderr
839 + log_file = None
840 + if self.background and self.logfile is not None:
841 + log_file = open(self.logfile, 'a')
842 + try:
843 + if log_file is not None:
844 + sys.stdout = log_file
845 + sys.stderr = log_file
846 + try:
847 + bintree.digestCheck(pkg)
848 + except portage.exception.FileNotFound:
849 + writemsg("!!! Fetching Binary failed " + \
850 + "for '%s'\n" % pkg.cpv, noiselevel=-1)
851 + rval = 1
852 + except portage.exception.DigestException, e:
853 + writemsg("\n!!! Digest verification failed:\n",
854 + noiselevel=-1)
855 + writemsg("!!! %s\n" % e.value[0],
856 + noiselevel=-1)
857 + writemsg("!!! Reason: %s\n" % e.value[1],
858 + noiselevel=-1)
859 + writemsg("!!! Got: %s\n" % e.value[2],
860 + noiselevel=-1)
861 + writemsg("!!! Expected: %s\n" % e.value[3],
862 + noiselevel=-1)
863 + rval = 1
864 + if rval != os.EX_OK:
865 + pkg_path = bintree.getname(pkg.cpv)
866 + head, tail = os.path.split(pkg_path)
867 + temp_filename = portage._checksum_failure_temp_file(head, tail)
868 + writemsg("File renamed to '%s'\n" % (temp_filename,),
869 + noiselevel=-1)
870 + finally:
871 + sys.stdout = stdout_orig
872 + sys.stderr = stderr_orig
873 + if log_file is not None:
874 + log_file.close()
875 +
876 + self.returncode = rval
877 + self.wait()
878 +
879
880 Copied: main/branches/prefix/pym/_emerge/Blocker.py (from rev 13663, main/trunk/pym/_emerge/Blocker.py)
881 ===================================================================
882 --- main/branches/prefix/pym/_emerge/Blocker.py (rev 0)
883 +++ main/branches/prefix/pym/_emerge/Blocker.py 2009-06-27 12:51:25 UTC (rev 13704)
884 @@ -0,0 +1,25 @@
885 +from _emerge.Task import Task
886 +# for an explanation on this logic, see pym/_emerge/__init__.py
887 +import os
888 +import sys
889 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
890 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
891 +else:
892 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
893 +import portage
894 +class Blocker(Task):
895 +
896 + __hash__ = Task.__hash__
897 + __slots__ = ("root", "atom", "cp", "eapi", "satisfied")
898 +
899 + def __init__(self, **kwargs):
900 + Task.__init__(self, **kwargs)
901 + self.cp = portage.dep_getkey(self.atom)
902 +
903 + def _get_hash_key(self):
904 + hash_key = getattr(self, "_hash_key", None)
905 + if hash_key is None:
906 + self._hash_key = \
907 + ("blocks", self.root, self.atom, self.eapi)
908 + return self._hash_key
909 +
910
911 Copied: main/branches/prefix/pym/_emerge/BlockerCache.py (from rev 13663, main/trunk/pym/_emerge/BlockerCache.py)
912 ===================================================================
913 --- main/branches/prefix/pym/_emerge/BlockerCache.py (rev 0)
914 +++ main/branches/prefix/pym/_emerge/BlockerCache.py 2009-06-27 12:51:25 UTC (rev 13704)
915 @@ -0,0 +1,177 @@
916 +from portage.util import writemsg
917 +from portage.data import secpass
918 +# for an explanation on this logic, see pym/_emerge/__init__.py
919 +import os
920 +import sys
921 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
922 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
923 +else:
924 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
925 +import portage
926 +try:
927 + import cPickle as pickle
928 +except ImportError:
929 + import pickle
930 +import os
931 +class BlockerCache(portage.cache.mappings.MutableMapping):
932 + """This caches blockers of installed packages so that dep_check does not
933 + have to be done for every single installed package on every invocation of
934 + emerge. The cache is invalidated whenever it is detected that something
935 + has changed that might alter the results of dep_check() calls:
936 + 1) the set of installed packages (including COUNTER) has changed
937 + 2) the old-style virtuals have changed
938 + """
939 +
940 + # Number of uncached packages to trigger cache update, since
941 + # it's wasteful to update it for every vdb change.
942 + _cache_threshold = 5
943 +
944 + class BlockerData(object):
945 +
946 + __slots__ = ("__weakref__", "atoms", "counter")
947 +
948 + def __init__(self, counter, atoms):
949 + self.counter = counter
950 + self.atoms = atoms
951 +
952 + def __init__(self, myroot, vardb):
953 + self._vardb = vardb
954 + self._virtuals = vardb.settings.getvirtuals()
955 + self._cache_filename = os.path.join(myroot,
956 + portage.CACHE_PATH.lstrip(os.path.sep), "vdb_blockers.pickle")
957 + self._cache_version = "1"
958 + self._cache_data = None
959 + self._modified = set()
960 + self._load()
961 +
962 + def _load(self):
963 + try:
964 + f = open(self._cache_filename, mode='rb')
965 + mypickle = pickle.Unpickler(f)
966 + try:
967 + mypickle.find_global = None
968 + except AttributeError:
969 + # TODO: If py3k, override Unpickler.find_class().
970 + pass
971 + self._cache_data = mypickle.load()
972 + f.close()
973 + del f
974 + except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError), e:
975 + if isinstance(e, pickle.UnpicklingError):
976 + writemsg("!!! Error loading '%s': %s\n" % \
977 + (self._cache_filename, str(e)), noiselevel=-1)
978 + del e
979 +
980 + cache_valid = self._cache_data and \
981 + isinstance(self._cache_data, dict) and \
982 + self._cache_data.get("version") == self._cache_version and \
983 + isinstance(self._cache_data.get("blockers"), dict)
984 + if cache_valid:
985 + # Validate all the atoms and counters so that
986 + # corruption is detected as soon as possible.
987 + invalid_items = set()
988 + for k, v in self._cache_data["blockers"].iteritems():
989 + if not isinstance(k, basestring):
990 + invalid_items.add(k)
991 + continue
992 + try:
993 + if portage.catpkgsplit(k) is None:
994 + invalid_items.add(k)
995 + continue
996 + except portage.exception.InvalidData:
997 + invalid_items.add(k)
998 + continue
999 + if not isinstance(v, tuple) or \
1000 + len(v) != 2:
1001 + invalid_items.add(k)
1002 + continue
1003 + counter, atoms = v
1004 + if not isinstance(counter, (int, long)):
1005 + invalid_items.add(k)
1006 + continue
1007 + if not isinstance(atoms, (list, tuple)):
1008 + invalid_items.add(k)
1009 + continue
1010 + invalid_atom = False
1011 + for atom in atoms:
1012 + if not isinstance(atom, basestring):
1013 + invalid_atom = True
1014 + break
1015 + if atom[:1] != "!" or \
1016 + not portage.isvalidatom(
1017 + atom, allow_blockers=True):
1018 + invalid_atom = True
1019 + break
1020 + if invalid_atom:
1021 + invalid_items.add(k)
1022 + continue
1023 +
1024 + for k in invalid_items:
1025 + del self._cache_data["blockers"][k]
1026 + if not self._cache_data["blockers"]:
1027 + cache_valid = False
1028 +
1029 + if not cache_valid:
1030 + self._cache_data = {"version":self._cache_version}
1031 + self._cache_data["blockers"] = {}
1032 + self._cache_data["virtuals"] = self._virtuals
1033 + self._modified.clear()
1034 +
1035 + def flush(self):
1036 + """If the current user has permission and the internal blocker cache
1037 + been updated, save it to disk and mark it unmodified. This is called
1038 + by emerge after it has proccessed blockers for all installed packages.
1039 + Currently, the cache is only written if the user has superuser
1040 + privileges (since that's required to obtain a lock), but all users
1041 + have read access and benefit from faster blocker lookups (as long as
1042 + the entire cache is still valid). The cache is stored as a pickled
1043 + dict object with the following format:
1044 +
1045 + {
1046 + version : "1",
1047 + "blockers" : {cpv1:(counter,(atom1, atom2...)), cpv2...},
1048 + "virtuals" : vardb.settings.getvirtuals()
1049 + }
1050 + """
1051 + if len(self._modified) >= self._cache_threshold and \
1052 + secpass >= 2:
1053 + try:
1054 + f = portage.util.atomic_ofstream(self._cache_filename, mode='wb')
1055 + pickle.dump(self._cache_data, f, protocol=2)
1056 + f.close()
1057 + portage.util.apply_secpass_permissions(
1058 + self._cache_filename, gid=portage.portage_gid, mode=0644)
1059 + except (IOError, OSError), e:
1060 + pass
1061 + self._modified.clear()
1062 +
1063 + def __setitem__(self, cpv, blocker_data):
1064 + """
1065 + Update the cache and mark it as modified for a future call to
1066 + self.flush().
1067 +
1068 + @param cpv: Package for which to cache blockers.
1069 + @type cpv: String
1070 + @param blocker_data: An object with counter and atoms attributes.
1071 + @type blocker_data: BlockerData
1072 + """
1073 + self._cache_data["blockers"][cpv] = \
1074 + (blocker_data.counter, tuple(str(x) for x in blocker_data.atoms))
1075 + self._modified.add(cpv)
1076 +
1077 + def __iter__(self):
1078 + if self._cache_data is None:
1079 + # triggered by python-trace
1080 + return iter([])
1081 + return iter(self._cache_data["blockers"])
1082 +
1083 + def __delitem__(self, cpv):
1084 + del self._cache_data["blockers"][cpv]
1085 +
1086 + def __getitem__(self, cpv):
1087 + """
1088 + @rtype: BlockerData
1089 + @returns: An object with counter and atoms attributes.
1090 + """
1091 + return self.BlockerData(*self._cache_data["blockers"][cpv])
1092 +
1093
1094 Copied: main/branches/prefix/pym/_emerge/BlockerDepPriority.py (from rev 13663, main/trunk/pym/_emerge/BlockerDepPriority.py)
1095 ===================================================================
1096 --- main/branches/prefix/pym/_emerge/BlockerDepPriority.py (rev 0)
1097 +++ main/branches/prefix/pym/_emerge/BlockerDepPriority.py 2009-06-27 12:51:25 UTC (rev 13704)
1098 @@ -0,0 +1,10 @@
1099 +from _emerge.DepPriority import DepPriority
1100 +class BlockerDepPriority(DepPriority):
1101 + __slots__ = ()
1102 + def __int__(self):
1103 + return 0
1104 +
1105 + def __str__(self):
1106 + return 'blocker'
1107 +
1108 +BlockerDepPriority.instance = BlockerDepPriority()
1109
1110 Copied: main/branches/prefix/pym/_emerge/CompositeTask.py (from rev 13663, main/trunk/pym/_emerge/CompositeTask.py)
1111 ===================================================================
1112 --- main/branches/prefix/pym/_emerge/CompositeTask.py (rev 0)
1113 +++ main/branches/prefix/pym/_emerge/CompositeTask.py 2009-06-27 12:51:25 UTC (rev 13704)
1114 @@ -0,0 +1,115 @@
1115 +from _emerge.AsynchronousTask import AsynchronousTask
1116 +import os
1117 +class CompositeTask(AsynchronousTask):
1118 +
1119 + __slots__ = ("scheduler",) + ("_current_task",)
1120 +
1121 + def isAlive(self):
1122 + return self._current_task is not None
1123 +
1124 + def cancel(self):
1125 + self.cancelled = True
1126 + if self._current_task is not None:
1127 + self._current_task.cancel()
1128 +
1129 + def _poll(self):
1130 + """
1131 + This does a loop calling self._current_task.poll()
1132 + repeatedly as long as the value of self._current_task
1133 + keeps changing. It calls poll() a maximum of one time
1134 + for a given self._current_task instance. This is useful
1135 + since calling poll() on a task can trigger advance to
1136 + the next task could eventually lead to the returncode
1137 + being set in cases when polling only a single task would
1138 + not have the same effect.
1139 + """
1140 +
1141 + prev = None
1142 + while True:
1143 + task = self._current_task
1144 + if task is None or task is prev:
1145 + # don't poll the same task more than once
1146 + break
1147 + task.poll()
1148 + prev = task
1149 +
1150 + return self.returncode
1151 +
1152 + def _wait(self):
1153 +
1154 + prev = None
1155 + while True:
1156 + task = self._current_task
1157 + if task is None:
1158 + # don't wait for the same task more than once
1159 + break
1160 + if task is prev:
1161 + # Before the task.wait() method returned, an exit
1162 + # listener should have set self._current_task to either
1163 + # a different task or None. Something is wrong.
1164 + raise AssertionError("self._current_task has not " + \
1165 + "changed since calling wait", self, task)
1166 + task.wait()
1167 + prev = task
1168 +
1169 + return self.returncode
1170 +
1171 + def _assert_current(self, task):
1172 + """
1173 + Raises an AssertionError if the given task is not the
1174 + same one as self._current_task. This can be useful
1175 + for detecting bugs.
1176 + """
1177 + if task is not self._current_task:
1178 + raise AssertionError("Unrecognized task: %s" % (task,))
1179 +
1180 + def _default_exit(self, task):
1181 + """
1182 + Calls _assert_current() on the given task and then sets the
1183 + composite returncode attribute if task.returncode != os.EX_OK.
1184 + If the task failed then self._current_task will be set to None.
1185 + Subclasses can use this as a generic task exit callback.
1186 +
1187 + @rtype: int
1188 + @returns: The task.returncode attribute.
1189 + """
1190 + self._assert_current(task)
1191 + if task.returncode != os.EX_OK:
1192 + self.returncode = task.returncode
1193 + self._current_task = None
1194 + return task.returncode
1195 +
1196 + def _final_exit(self, task):
1197 + """
1198 + Assumes that task is the final task of this composite task.
1199 + Calls _default_exit() and sets self.returncode to the task's
1200 + returncode and sets self._current_task to None.
1201 + """
1202 + self._default_exit(task)
1203 + self._current_task = None
1204 + self.returncode = task.returncode
1205 + return self.returncode
1206 +
1207 + def _default_final_exit(self, task):
1208 + """
1209 + This calls _final_exit() and then wait().
1210 +
1211 + Subclasses can use this as a generic final task exit callback.
1212 +
1213 + """
1214 + self._final_exit(task)
1215 + return self.wait()
1216 +
1217 + def _start_task(self, task, exit_handler):
1218 + """
1219 + Register exit handler for the given task, set it
1220 + as self._current_task, and call task.start().
1221 +
1222 + Subclasses can use this as a generic way to start
1223 + a task.
1224 +
1225 + """
1226 + task.addExitListener(exit_handler)
1227 + self._current_task = task
1228 + task.start()
1229 +
1230
1231 Copied: main/branches/prefix/pym/_emerge/DepPriority.py (from rev 13663, main/trunk/pym/_emerge/DepPriority.py)
1232 ===================================================================
1233 --- main/branches/prefix/pym/_emerge/DepPriority.py (rev 0)
1234 +++ main/branches/prefix/pym/_emerge/DepPriority.py 2009-06-27 12:51:25 UTC (rev 13704)
1235 @@ -0,0 +1,44 @@
1236 +from _emerge.AbstractDepPriority import AbstractDepPriority
1237 +class DepPriority(AbstractDepPriority):
1238 +
1239 + __slots__ = ("satisfied", "optional", "rebuild")
1240 +
1241 + def __int__(self):
1242 + """
1243 + Note: These priorities are only used for measuring hardness
1244 + in the circular dependency display via digraph.debug_print(),
1245 + and nothing more. For actual merge order calculations, the
1246 + measures defined by the DepPriorityNormalRange and
1247 + DepPrioritySatisfiedRange classes are used.
1248 +
1249 + Attributes Hardness
1250 +
1251 + buildtime 0
1252 + runtime -1
1253 + runtime_post -2
1254 + optional -3
1255 + (none of the above) -4
1256 +
1257 + """
1258 +
1259 + if self.buildtime:
1260 + return 0
1261 + if self.runtime:
1262 + return -1
1263 + if self.runtime_post:
1264 + return -2
1265 + if self.optional:
1266 + return -3
1267 + return -4
1268 +
1269 + def __str__(self):
1270 + if self.optional:
1271 + return "optional"
1272 + if self.buildtime:
1273 + return "buildtime"
1274 + if self.runtime:
1275 + return "runtime"
1276 + if self.runtime_post:
1277 + return "runtime_post"
1278 + return "soft"
1279 +
1280
1281 Copied: main/branches/prefix/pym/_emerge/DepPriorityNormalRange.py (from rev 13663, main/trunk/pym/_emerge/DepPriorityNormalRange.py)
1282 ===================================================================
1283 --- main/branches/prefix/pym/_emerge/DepPriorityNormalRange.py (rev 0)
1284 +++ main/branches/prefix/pym/_emerge/DepPriorityNormalRange.py 2009-06-27 12:51:25 UTC (rev 13704)
1285 @@ -0,0 +1,44 @@
1286 +from _emerge.DepPriority import DepPriority
1287 +class DepPriorityNormalRange(object):
1288 + """
1289 + DepPriority properties Index Category
1290 +
1291 + buildtime HARD
1292 + runtime 3 MEDIUM
1293 + runtime_post 2 MEDIUM_SOFT
1294 + optional 1 SOFT
1295 + (none of the above) 0 NONE
1296 + """
1297 + MEDIUM = 3
1298 + MEDIUM_SOFT = 2
1299 + SOFT = 1
1300 + NONE = 0
1301 +
1302 + @classmethod
1303 + def _ignore_optional(cls, priority):
1304 + if priority.__class__ is not DepPriority:
1305 + return False
1306 + return bool(priority.optional)
1307 +
1308 + @classmethod
1309 + def _ignore_runtime_post(cls, priority):
1310 + if priority.__class__ is not DepPriority:
1311 + return False
1312 + return bool(priority.optional or priority.runtime_post)
1313 +
1314 + @classmethod
1315 + def _ignore_runtime(cls, priority):
1316 + if priority.__class__ is not DepPriority:
1317 + return False
1318 + return not priority.buildtime
1319 +
1320 + ignore_medium = _ignore_runtime
1321 + ignore_medium_soft = _ignore_runtime_post
1322 + ignore_soft = _ignore_optional
1323 +
1324 +DepPriorityNormalRange.ignore_priority = (
1325 + None,
1326 + DepPriorityNormalRange._ignore_optional,
1327 + DepPriorityNormalRange._ignore_runtime_post,
1328 + DepPriorityNormalRange._ignore_runtime
1329 +)
1330
1331 Copied: main/branches/prefix/pym/_emerge/DepPrioritySatisfiedRange.py (from rev 13663, main/trunk/pym/_emerge/DepPrioritySatisfiedRange.py)
1332 ===================================================================
1333 --- main/branches/prefix/pym/_emerge/DepPrioritySatisfiedRange.py (rev 0)
1334 +++ main/branches/prefix/pym/_emerge/DepPrioritySatisfiedRange.py 2009-06-27 12:51:25 UTC (rev 13704)
1335 @@ -0,0 +1,96 @@
1336 +from _emerge.DepPriority import DepPriority
1337 +class DepPrioritySatisfiedRange(object):
1338 + """
1339 + DepPriority Index Category
1340 +
1341 + not satisfied and buildtime HARD
1342 + not satisfied and runtime 7 MEDIUM
1343 + not satisfied and runtime_post 6 MEDIUM_SOFT
1344 + satisfied and buildtime and rebuild 5 SOFT
1345 + satisfied and buildtime 4 SOFT
1346 + satisfied and runtime 3 SOFT
1347 + satisfied and runtime_post 2 SOFT
1348 + optional 1 SOFT
1349 + (none of the above) 0 NONE
1350 + """
1351 + MEDIUM = 7
1352 + MEDIUM_SOFT = 6
1353 + SOFT = 5
1354 + NONE = 0
1355 +
1356 + @classmethod
1357 + def _ignore_optional(cls, priority):
1358 + if priority.__class__ is not DepPriority:
1359 + return False
1360 + return bool(priority.optional)
1361 +
1362 + @classmethod
1363 + def _ignore_satisfied_runtime_post(cls, priority):
1364 + if priority.__class__ is not DepPriority:
1365 + return False
1366 + if priority.optional:
1367 + return True
1368 + if not priority.satisfied:
1369 + return False
1370 + return bool(priority.runtime_post)
1371 +
1372 + @classmethod
1373 + def _ignore_satisfied_runtime(cls, priority):
1374 + if priority.__class__ is not DepPriority:
1375 + return False
1376 + if priority.optional:
1377 + return True
1378 + if not priority.satisfied:
1379 + return False
1380 + return not priority.buildtime
1381 +
1382 + @classmethod
1383 + def _ignore_satisfied_buildtime(cls, priority):
1384 + if priority.__class__ is not DepPriority:
1385 + return False
1386 + if priority.optional:
1387 + return True
1388 + if not priority.satisfied:
1389 + return False
1390 + if priority.buildtime:
1391 + return not priority.rebuild
1392 + return True
1393 +
1394 + @classmethod
1395 + def _ignore_satisfied_buildtime_rebuild(cls, priority):
1396 + if priority.__class__ is not DepPriority:
1397 + return False
1398 + if priority.optional:
1399 + return True
1400 + return bool(priority.satisfied)
1401 +
1402 + @classmethod
1403 + def _ignore_runtime_post(cls, priority):
1404 + if priority.__class__ is not DepPriority:
1405 + return False
1406 + return bool(priority.optional or \
1407 + priority.satisfied or \
1408 + priority.runtime_post)
1409 +
1410 + @classmethod
1411 + def _ignore_runtime(cls, priority):
1412 + if priority.__class__ is not DepPriority:
1413 + return False
1414 + return bool(priority.satisfied or \
1415 + not priority.buildtime)
1416 +
1417 + ignore_medium = _ignore_runtime
1418 + ignore_medium_soft = _ignore_runtime_post
1419 + ignore_soft = _ignore_satisfied_buildtime_rebuild
1420 +
1421 +
1422 +DepPrioritySatisfiedRange.ignore_priority = (
1423 + None,
1424 + DepPrioritySatisfiedRange._ignore_optional,
1425 + DepPrioritySatisfiedRange._ignore_satisfied_runtime_post,
1426 + DepPrioritySatisfiedRange._ignore_satisfied_runtime,
1427 + DepPrioritySatisfiedRange._ignore_satisfied_buildtime,
1428 + DepPrioritySatisfiedRange._ignore_satisfied_buildtime_rebuild,
1429 + DepPrioritySatisfiedRange._ignore_runtime_post,
1430 + DepPrioritySatisfiedRange._ignore_runtime
1431 +)
1432
1433 Copied: main/branches/prefix/pym/_emerge/Dependency.py (from rev 13663, main/trunk/pym/_emerge/Dependency.py)
1434 ===================================================================
1435 --- main/branches/prefix/pym/_emerge/Dependency.py (rev 0)
1436 +++ main/branches/prefix/pym/_emerge/Dependency.py 2009-06-27 12:51:25 UTC (rev 13704)
1437 @@ -0,0 +1,12 @@
1438 +from _emerge.DepPriority import DepPriority
1439 +from _emerge.SlotObject import SlotObject
1440 +class Dependency(SlotObject):
1441 + __slots__ = ("atom", "blocker", "depth",
1442 + "parent", "onlydeps", "priority", "root")
1443 + def __init__(self, **kwargs):
1444 + SlotObject.__init__(self, **kwargs)
1445 + if self.priority is None:
1446 + self.priority = DepPriority()
1447 + if self.depth is None:
1448 + self.depth = 0
1449 +
1450
1451 Copied: main/branches/prefix/pym/_emerge/DependencyArg.py (from rev 13663, main/trunk/pym/_emerge/DependencyArg.py)
1452 ===================================================================
1453 --- main/branches/prefix/pym/_emerge/DependencyArg.py (rev 0)
1454 +++ main/branches/prefix/pym/_emerge/DependencyArg.py 2009-06-27 12:51:25 UTC (rev 13704)
1455 @@ -0,0 +1,8 @@
1456 +class DependencyArg(object):
1457 + def __init__(self, arg=None, root_config=None):
1458 + self.arg = arg
1459 + self.root_config = root_config
1460 +
1461 + def __str__(self):
1462 + return str(self.arg)
1463 +
1464
1465 Copied: main/branches/prefix/pym/_emerge/EbuildBinpkg.py (from rev 13663, main/trunk/pym/_emerge/EbuildBinpkg.py)
1466 ===================================================================
1467 --- main/branches/prefix/pym/_emerge/EbuildBinpkg.py (rev 0)
1468 +++ main/branches/prefix/pym/_emerge/EbuildBinpkg.py 2009-06-27 12:51:25 UTC (rev 13704)
1469 @@ -0,0 +1,40 @@
1470 +from _emerge.EbuildProcess import EbuildProcess
1471 +import os
1472 +class EbuildBinpkg(EbuildProcess):
1473 + """
1474 + This assumes that src_install() has successfully completed.
1475 + """
1476 + __slots__ = ("_binpkg_tmpfile",)
1477 +
1478 + def _start(self):
1479 + self.phase = "package"
1480 + self.tree = "porttree"
1481 + pkg = self.pkg
1482 + root_config = pkg.root_config
1483 + portdb = root_config.trees["porttree"].dbapi
1484 + bintree = root_config.trees["bintree"]
1485 + ebuild_path = portdb.findname(self.pkg.cpv)
1486 + settings = self.settings
1487 + debug = settings.get("PORTAGE_DEBUG") == "1"
1488 +
1489 + bintree.prevent_collision(pkg.cpv)
1490 + binpkg_tmpfile = os.path.join(bintree.pkgdir,
1491 + pkg.cpv + ".tbz2." + str(os.getpid()))
1492 + self._binpkg_tmpfile = binpkg_tmpfile
1493 + settings["PORTAGE_BINPKG_TMPFILE"] = binpkg_tmpfile
1494 + settings.backup_changes("PORTAGE_BINPKG_TMPFILE")
1495 +
1496 + try:
1497 + EbuildProcess._start(self)
1498 + finally:
1499 + settings.pop("PORTAGE_BINPKG_TMPFILE", None)
1500 +
1501 + def _set_returncode(self, wait_retval):
1502 + EbuildProcess._set_returncode(self, wait_retval)
1503 +
1504 + pkg = self.pkg
1505 + bintree = pkg.root_config.trees["bintree"]
1506 + binpkg_tmpfile = self._binpkg_tmpfile
1507 + if self.returncode == os.EX_OK:
1508 + bintree.inject(pkg.cpv, filename=binpkg_tmpfile)
1509 +
1510
1511 Copied: main/branches/prefix/pym/_emerge/EbuildBuild.py (from rev 13663, main/trunk/pym/_emerge/EbuildBuild.py)
1512 ===================================================================
1513 --- main/branches/prefix/pym/_emerge/EbuildBuild.py (rev 0)
1514 +++ main/branches/prefix/pym/_emerge/EbuildBuild.py 2009-06-27 12:51:25 UTC (rev 13704)
1515 @@ -0,0 +1,271 @@
1516 +from _emerge.EbuildExecuter import EbuildExecuter
1517 +from _emerge.EbuildPhase import EbuildPhase
1518 +from _emerge.EbuildBinpkg import EbuildBinpkg
1519 +from _emerge.EbuildFetcher import EbuildFetcher
1520 +from _emerge.CompositeTask import CompositeTask
1521 +from _emerge.EbuildMerge import EbuildMerge
1522 +from _emerge.EbuildFetchonly import EbuildFetchonly
1523 +from _emerge.EbuildBuildDir import EbuildBuildDir
1524 +from portage.util import writemsg
1525 +# for an explanation on this logic, see pym/_emerge/__init__.py
1526 +import os
1527 +import sys
1528 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
1529 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
1530 +else:
1531 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
1532 +import portage
1533 +from portage.output import colorize
1534 +class EbuildBuild(CompositeTask):
1535 +
1536 + __slots__ = ("args_set", "config_pool", "find_blockers",
1537 + "ldpath_mtimes", "logger", "opts", "pkg", "pkg_count",
1538 + "prefetcher", "settings", "world_atom") + \
1539 + ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree")
1540 +
1541 + def _start(self):
1542 +
1543 + logger = self.logger
1544 + opts = self.opts
1545 + pkg = self.pkg
1546 + settings = self.settings
1547 + world_atom = self.world_atom
1548 + root_config = pkg.root_config
1549 + tree = "porttree"
1550 + self._tree = tree
1551 + portdb = root_config.trees[tree].dbapi
1552 + settings.setcpv(pkg)
1553 + settings.configdict["pkg"]["EMERGE_FROM"] = pkg.type_name
1554 + ebuild_path = portdb.findname(self.pkg.cpv)
1555 + self._ebuild_path = ebuild_path
1556 +
1557 + prefetcher = self.prefetcher
1558 + if prefetcher is None:
1559 + pass
1560 + elif not prefetcher.isAlive():
1561 + prefetcher.cancel()
1562 + elif prefetcher.poll() is None:
1563 +
1564 + waiting_msg = "Fetching files " + \
1565 + "in the background. " + \
1566 + "To view fetch progress, run `tail -f " + \
1567 + "/var/log/emerge-fetch.log` in another " + \
1568 + "terminal."
1569 + msg_prefix = colorize("GOOD", " * ")
1570 + from textwrap import wrap
1571 + waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \
1572 + for line in wrap(waiting_msg, 65))
1573 + if not self.background:
1574 + writemsg(waiting_msg, noiselevel=-1)
1575 +
1576 + self._current_task = prefetcher
1577 + prefetcher.addExitListener(self._prefetch_exit)
1578 + return
1579 +
1580 + self._prefetch_exit(prefetcher)
1581 +
1582 + def _prefetch_exit(self, prefetcher):
1583 +
1584 + opts = self.opts
1585 + pkg = self.pkg
1586 + settings = self.settings
1587 +
1588 + if opts.fetchonly:
1589 + fetcher = EbuildFetchonly(
1590 + fetch_all=opts.fetch_all_uri,
1591 + pkg=pkg, pretend=opts.pretend,
1592 + settings=settings)
1593 + retval = fetcher.execute()
1594 + self.returncode = retval
1595 + self.wait()
1596 + return
1597 +
1598 + fetcher = EbuildFetcher(config_pool=self.config_pool,
1599 + fetchall=opts.fetch_all_uri,
1600 + fetchonly=opts.fetchonly,
1601 + background=self.background,
1602 + pkg=pkg, scheduler=self.scheduler)
1603 +
1604 + self._start_task(fetcher, self._fetch_exit)
1605 +
1606 + def _fetch_exit(self, fetcher):
1607 + opts = self.opts
1608 + pkg = self.pkg
1609 +
1610 + fetch_failed = False
1611 + if opts.fetchonly:
1612 + fetch_failed = self._final_exit(fetcher) != os.EX_OK
1613 + else:
1614 + fetch_failed = self._default_exit(fetcher) != os.EX_OK
1615 +
1616 + if fetch_failed and fetcher.logfile is not None and \
1617 + os.path.exists(fetcher.logfile):
1618 + self.settings["PORTAGE_LOG_FILE"] = fetcher.logfile
1619 +
1620 + if not fetch_failed and fetcher.logfile is not None:
1621 + # Fetch was successful, so remove the fetch log.
1622 + try:
1623 + os.unlink(fetcher.logfile)
1624 + except OSError:
1625 + pass
1626 +
1627 + if fetch_failed or opts.fetchonly:
1628 + self.wait()
1629 + return
1630 +
1631 + logger = self.logger
1632 + opts = self.opts
1633 + pkg_count = self.pkg_count
1634 + scheduler = self.scheduler
1635 + settings = self.settings
1636 + features = settings.features
1637 + ebuild_path = self._ebuild_path
1638 + system_set = pkg.root_config.sets["system"]
1639 +
1640 + self._build_dir = EbuildBuildDir(pkg=pkg, settings=settings)
1641 + self._build_dir.lock()
1642 +
1643 + # Cleaning is triggered before the setup
1644 + # phase, in portage.doebuild().
1645 + msg = " === (%s of %s) Cleaning (%s::%s)" % \
1646 + (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
1647 + short_msg = "emerge: (%s of %s) %s Clean" % \
1648 + (pkg_count.curval, pkg_count.maxval, pkg.cpv)
1649 + logger.log(msg, short_msg=short_msg)
1650 +
1651 + #buildsyspkg: Check if we need to _force_ binary package creation
1652 + self._issyspkg = "buildsyspkg" in features and \
1653 + system_set.findAtomForPackage(pkg) and \
1654 + not opts.buildpkg
1655 +
1656 + if opts.buildpkg or self._issyspkg:
1657 +
1658 + self._buildpkg = True
1659 +
1660 + msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
1661 + (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
1662 + short_msg = "emerge: (%s of %s) %s Compile" % \
1663 + (pkg_count.curval, pkg_count.maxval, pkg.cpv)
1664 + logger.log(msg, short_msg=short_msg)
1665 +
1666 + else:
1667 + msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \
1668 + (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
1669 + short_msg = "emerge: (%s of %s) %s Compile" % \
1670 + (pkg_count.curval, pkg_count.maxval, pkg.cpv)
1671 + logger.log(msg, short_msg=short_msg)
1672 +
1673 + build = EbuildExecuter(background=self.background, pkg=pkg,
1674 + scheduler=scheduler, settings=settings)
1675 + self._start_task(build, self._build_exit)
1676 +
1677 + def _unlock_builddir(self):
1678 + portage.elog.elog_process(self.pkg.cpv, self.settings)
1679 + self._build_dir.unlock()
1680 +
1681 + def _build_exit(self, build):
1682 + if self._default_exit(build) != os.EX_OK:
1683 + self._unlock_builddir()
1684 + self.wait()
1685 + return
1686 +
1687 + opts = self.opts
1688 + buildpkg = self._buildpkg
1689 +
1690 + if not buildpkg:
1691 + self._final_exit(build)
1692 + self.wait()
1693 + return
1694 +
1695 + if self._issyspkg:
1696 + msg = ">>> This is a system package, " + \
1697 + "let's pack a rescue tarball.\n"
1698 +
1699 + log_path = self.settings.get("PORTAGE_LOG_FILE")
1700 + if log_path is not None:
1701 + log_file = open(log_path, 'a')
1702 + try:
1703 + log_file.write(msg)
1704 + finally:
1705 + log_file.close()
1706 +
1707 + if not self.background:
1708 + portage.writemsg_stdout(msg, noiselevel=-1)
1709 +
1710 + packager = EbuildBinpkg(background=self.background, pkg=self.pkg,
1711 + scheduler=self.scheduler, settings=self.settings)
1712 +
1713 + self._start_task(packager, self._buildpkg_exit)
1714 +
1715 + def _buildpkg_exit(self, packager):
1716 + """
1717 + Released build dir lock when there is a failure or
1718 + when in buildpkgonly mode. Otherwise, the lock will
1719 + be released when merge() is called.
1720 + """
1721 +
1722 + if self._default_exit(packager) != os.EX_OK:
1723 + self._unlock_builddir()
1724 + self.wait()
1725 + return
1726 +
1727 + if self.opts.buildpkgonly:
1728 + # Need to call "clean" phase for buildpkgonly mode
1729 + portage.elog.elog_process(self.pkg.cpv, self.settings)
1730 + phase = "clean"
1731 + clean_phase = EbuildPhase(background=self.background,
1732 + pkg=self.pkg, phase=phase,
1733 + scheduler=self.scheduler, settings=self.settings,
1734 + tree=self._tree)
1735 + self._start_task(clean_phase, self._clean_exit)
1736 + return
1737 +
1738 + # Continue holding the builddir lock until
1739 + # after the package has been installed.
1740 + self._current_task = None
1741 + self.returncode = packager.returncode
1742 + self.wait()
1743 +
1744 + def _clean_exit(self, clean_phase):
1745 + if self._final_exit(clean_phase) != os.EX_OK or \
1746 + self.opts.buildpkgonly:
1747 + self._unlock_builddir()
1748 + self.wait()
1749 +
1750 + def install(self):
1751 + """
1752 + Install the package and then clean up and release locks.
1753 + Only call this after the build has completed successfully
1754 + and neither fetchonly nor buildpkgonly mode are enabled.
1755 + """
1756 +
1757 + find_blockers = self.find_blockers
1758 + ldpath_mtimes = self.ldpath_mtimes
1759 + logger = self.logger
1760 + pkg = self.pkg
1761 + pkg_count = self.pkg_count
1762 + settings = self.settings
1763 + world_atom = self.world_atom
1764 + ebuild_path = self._ebuild_path
1765 + tree = self._tree
1766 +
1767 + merge = EbuildMerge(find_blockers=self.find_blockers,
1768 + ldpath_mtimes=ldpath_mtimes, logger=logger, pkg=pkg,
1769 + pkg_count=pkg_count, pkg_path=ebuild_path,
1770 + scheduler=self.scheduler,
1771 + settings=settings, tree=tree, world_atom=world_atom)
1772 +
1773 + msg = " === (%s of %s) Merging (%s::%s)" % \
1774 + (pkg_count.curval, pkg_count.maxval,
1775 + pkg.cpv, ebuild_path)
1776 + short_msg = "emerge: (%s of %s) %s Merge" % \
1777 + (pkg_count.curval, pkg_count.maxval, pkg.cpv)
1778 + logger.log(msg, short_msg=short_msg)
1779 +
1780 + try:
1781 + rval = merge.execute()
1782 + finally:
1783 + self._unlock_builddir()
1784 +
1785 + return rval
1786 +
1787
1788 Copied: main/branches/prefix/pym/_emerge/EbuildBuildDir.py (from rev 13663, main/trunk/pym/_emerge/EbuildBuildDir.py)
1789 ===================================================================
1790 --- main/branches/prefix/pym/_emerge/EbuildBuildDir.py (rev 0)
1791 +++ main/branches/prefix/pym/_emerge/EbuildBuildDir.py 2009-06-27 12:51:25 UTC (rev 13704)
1792 @@ -0,0 +1,96 @@
1793 +from _emerge.SlotObject import SlotObject
1794 +# for an explanation on this logic, see pym/_emerge/__init__.py
1795 +import os
1796 +import sys
1797 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
1798 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
1799 +else:
1800 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
1801 +import portage
1802 +import errno
1803 +class EbuildBuildDir(SlotObject):
1804 +
1805 + __slots__ = ("dir_path", "pkg", "settings",
1806 + "locked", "_catdir", "_lock_obj")
1807 +
1808 + def __init__(self, **kwargs):
1809 + SlotObject.__init__(self, **kwargs)
1810 + self.locked = False
1811 +
1812 + def lock(self):
1813 + """
1814 + This raises an AlreadyLocked exception if lock() is called
1815 + while a lock is already held. In order to avoid this, call
1816 + unlock() or check whether the "locked" attribute is True
1817 + or False before calling lock().
1818 + """
1819 + if self._lock_obj is not None:
1820 + raise self.AlreadyLocked((self._lock_obj,))
1821 +
1822 + dir_path = self.dir_path
1823 + if dir_path is None:
1824 + root_config = self.pkg.root_config
1825 + portdb = root_config.trees["porttree"].dbapi
1826 + ebuild_path = portdb.findname(self.pkg.cpv)
1827 + settings = self.settings
1828 + settings.setcpv(self.pkg)
1829 + debug = settings.get("PORTAGE_DEBUG") == "1"
1830 + use_cache = 1 # always true
1831 + portage.doebuild_environment(ebuild_path, "setup", root_config.root,
1832 + self.settings, debug, use_cache, portdb)
1833 + dir_path = self.settings["PORTAGE_BUILDDIR"]
1834 +
1835 + catdir = os.path.dirname(dir_path)
1836 + self._catdir = catdir
1837 +
1838 + portage.util.ensure_dirs(os.path.dirname(catdir),
1839 + gid=portage.portage_gid,
1840 + mode=070, mask=0)
1841 + catdir_lock = None
1842 + try:
1843 + catdir_lock = portage.locks.lockdir(catdir)
1844 + portage.util.ensure_dirs(catdir,
1845 + gid=portage.portage_gid,
1846 + mode=070, mask=0)
1847 + self._lock_obj = portage.locks.lockdir(dir_path)
1848 + finally:
1849 + self.locked = self._lock_obj is not None
1850 + if catdir_lock is not None:
1851 + portage.locks.unlockdir(catdir_lock)
1852 +
1853 + def clean_log(self):
1854 + """Discard existing log."""
1855 + settings = self.settings
1856 +
1857 + for x in ('.logid', 'temp/build.log'):
1858 + try:
1859 + os.unlink(os.path.join(settings["PORTAGE_BUILDDIR"], x))
1860 + except OSError:
1861 + pass
1862 +
1863 + def unlock(self):
1864 + if self._lock_obj is None:
1865 + return
1866 +
1867 + portage.locks.unlockdir(self._lock_obj)
1868 + self._lock_obj = None
1869 + self.locked = False
1870 +
1871 + catdir = self._catdir
1872 + catdir_lock = None
1873 + try:
1874 + catdir_lock = portage.locks.lockdir(catdir)
1875 + finally:
1876 + if catdir_lock:
1877 + try:
1878 + os.rmdir(catdir)
1879 + except OSError, e:
1880 + if e.errno not in (errno.ENOENT,
1881 + errno.ENOTEMPTY, errno.EEXIST):
1882 + raise
1883 + del e
1884 + portage.locks.unlockdir(catdir_lock)
1885 +
1886 + class AlreadyLocked(portage.exception.PortageException):
1887 + pass
1888 +
1889
1890 Copied: main/branches/prefix/pym/_emerge/EbuildExecuter.py (from rev 13663, main/trunk/pym/_emerge/EbuildExecuter.py)
1891 ===================================================================
1892 --- main/branches/prefix/pym/_emerge/EbuildExecuter.py (rev 0)
1893 +++ main/branches/prefix/pym/_emerge/EbuildExecuter.py 2009-06-27 12:51:25 UTC (rev 13704)
1894 @@ -0,0 +1,99 @@
1895 +from _emerge.EbuildPhase import EbuildPhase
1896 +from _emerge.TaskSequence import TaskSequence
1897 +from _emerge.CompositeTask import CompositeTask
1898 +# for an explanation on this logic, see pym/_emerge/__init__.py
1899 +import os
1900 +import sys
1901 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
1902 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
1903 +else:
1904 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
1905 +import portage
1906 +class EbuildExecuter(CompositeTask):
1907 +
1908 + __slots__ = ("pkg", "scheduler", "settings") + ("_tree",)
1909 +
1910 + _phases = ("prepare", "configure", "compile", "test", "install")
1911 +
1912 + _live_eclasses = frozenset([
1913 + "bzr",
1914 + "cvs",
1915 + "darcs",
1916 + "git",
1917 + "mercurial",
1918 + "subversion"
1919 + ])
1920 +
1921 + def _start(self):
1922 + self._tree = "porttree"
1923 + pkg = self.pkg
1924 + phase = "clean"
1925 + clean_phase = EbuildPhase(background=self.background, pkg=pkg, phase=phase,
1926 + scheduler=self.scheduler, settings=self.settings, tree=self._tree)
1927 + self._start_task(clean_phase, self._clean_phase_exit)
1928 +
1929 + def _clean_phase_exit(self, clean_phase):
1930 +
1931 + if self._default_exit(clean_phase) != os.EX_OK:
1932 + self.wait()
1933 + return
1934 +
1935 + pkg = self.pkg
1936 + scheduler = self.scheduler
1937 + settings = self.settings
1938 + cleanup = 1
1939 +
1940 + # This initializes PORTAGE_LOG_FILE.
1941 + portage.prepare_build_dirs(pkg.root, settings, cleanup)
1942 +
1943 + setup_phase = EbuildPhase(background=self.background,
1944 + pkg=pkg, phase="setup", scheduler=scheduler,
1945 + settings=settings, tree=self._tree)
1946 +
1947 + setup_phase.addExitListener(self._setup_exit)
1948 + self._current_task = setup_phase
1949 + self.scheduler.scheduleSetup(setup_phase)
1950 +
1951 + def _setup_exit(self, setup_phase):
1952 +
1953 + if self._default_exit(setup_phase) != os.EX_OK:
1954 + self.wait()
1955 + return
1956 +
1957 + unpack_phase = EbuildPhase(background=self.background,
1958 + pkg=self.pkg, phase="unpack", scheduler=self.scheduler,
1959 + settings=self.settings, tree=self._tree)
1960 +
1961 + if self._live_eclasses.intersection(self.pkg.inherited):
1962 + # Serialize $DISTDIR access for live ebuilds since
1963 + # otherwise they can interfere with eachother.
1964 +
1965 + unpack_phase.addExitListener(self._unpack_exit)
1966 + self._current_task = unpack_phase
1967 + self.scheduler.scheduleUnpack(unpack_phase)
1968 +
1969 + else:
1970 + self._start_task(unpack_phase, self._unpack_exit)
1971 +
1972 + def _unpack_exit(self, unpack_phase):
1973 +
1974 + if self._default_exit(unpack_phase) != os.EX_OK:
1975 + self.wait()
1976 + return
1977 +
1978 + ebuild_phases = TaskSequence(scheduler=self.scheduler)
1979 +
1980 + pkg = self.pkg
1981 + phases = self._phases
1982 + eapi = pkg.metadata["EAPI"]
1983 + if eapi in ("0", "1"):
1984 + # skip src_prepare and src_configure
1985 + phases = phases[2:]
1986 +
1987 + for phase in phases:
1988 + ebuild_phases.add(EbuildPhase(background=self.background,
1989 + pkg=self.pkg, phase=phase, scheduler=self.scheduler,
1990 + settings=self.settings, tree=self._tree))
1991 +
1992 + self._start_task(ebuild_phases, self._default_final_exit)
1993 +
1994
1995 Copied: main/branches/prefix/pym/_emerge/EbuildFetcher.py (from rev 13663, main/trunk/pym/_emerge/EbuildFetcher.py)
1996 ===================================================================
1997 --- main/branches/prefix/pym/_emerge/EbuildFetcher.py (rev 0)
1998 +++ main/branches/prefix/pym/_emerge/EbuildFetcher.py 2009-06-27 12:51:25 UTC (rev 13704)
1999 @@ -0,0 +1,109 @@
2000 +from _emerge.SpawnProcess import SpawnProcess
2001 +from _emerge.EbuildBuildDir import EbuildBuildDir
2002 +# for an explanation on this logic, see pym/_emerge/__init__.py
2003 +import os
2004 +import sys
2005 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
2006 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
2007 +else:
2008 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
2009 +import portage
2010 +import os
2011 +from portage.elog.messages import eerror
2012 +class EbuildFetcher(SpawnProcess):
2013 +
2014 + __slots__ = ("config_pool", "fetchonly", "fetchall", "pkg", "prefetch") + \
2015 + ("_build_dir",)
2016 +
2017 + def _start(self):
2018 +
2019 + root_config = self.pkg.root_config
2020 + portdb = root_config.trees["porttree"].dbapi
2021 + ebuild_path = portdb.findname(self.pkg.cpv)
2022 + settings = self.config_pool.allocate()
2023 + settings.setcpv(self.pkg)
2024 +
2025 + # In prefetch mode, logging goes to emerge-fetch.log and the builddir
2026 + # should not be touched since otherwise it could interfere with
2027 + # another instance of the same cpv concurrently being built for a
2028 + # different $ROOT (currently, builds only cooperate with prefetchers
2029 + # that are spawned for the same $ROOT).
2030 + if not self.prefetch:
2031 + self._build_dir = EbuildBuildDir(pkg=self.pkg, settings=settings)
2032 + self._build_dir.lock()
2033 + self._build_dir.clean_log()
2034 + portage.prepare_build_dirs(self.pkg.root, self._build_dir.settings, 0)
2035 + if self.logfile is None:
2036 + self.logfile = settings.get("PORTAGE_LOG_FILE")
2037 +
2038 + phase = "fetch"
2039 + if self.fetchall:
2040 + phase = "fetchall"
2041 +
2042 + # If any incremental variables have been overridden
2043 + # via the environment, those values need to be passed
2044 + # along here so that they are correctly considered by
2045 + # the config instance in the subproccess.
2046 + fetch_env = os.environ.copy()
2047 +
2048 + nocolor = settings.get("NOCOLOR")
2049 + if nocolor is not None:
2050 + fetch_env["NOCOLOR"] = nocolor
2051 +
2052 + fetch_env["PORTAGE_NICENESS"] = "0"
2053 + if self.prefetch:
2054 + fetch_env["PORTAGE_PARALLEL_FETCHONLY"] = "1"
2055 +
2056 + ebuild_binary = os.path.join(
2057 + settings["PORTAGE_BIN_PATH"], "ebuild")
2058 +
2059 + fetch_args = [ebuild_binary, ebuild_path, phase]
2060 + debug = settings.get("PORTAGE_DEBUG") == "1"
2061 + if debug:
2062 + fetch_args.append("--debug")
2063 +
2064 + self.args = fetch_args
2065 + self.env = fetch_env
2066 + SpawnProcess._start(self)
2067 +
2068 + def _pipe(self, fd_pipes):
2069 + """When appropriate, use a pty so that fetcher progress bars,
2070 + like wget has, will work properly."""
2071 + if self.background or not sys.stdout.isatty():
2072 + # When the output only goes to a log file,
2073 + # there's no point in creating a pty.
2074 + return os.pipe()
2075 + stdout_pipe = fd_pipes.get(1)
2076 + got_pty, master_fd, slave_fd = \
2077 + portage._create_pty_or_pipe(copy_term_size=stdout_pipe)
2078 + return (master_fd, slave_fd)
2079 +
2080 + def _set_returncode(self, wait_retval):
2081 + SpawnProcess._set_returncode(self, wait_retval)
2082 + # Collect elog messages that might have been
2083 + # created by the pkg_nofetch phase.
2084 + if self._build_dir is not None:
2085 + # Skip elog messages for prefetch, in order to avoid duplicates.
2086 + if not self.prefetch and self.returncode != os.EX_OK:
2087 + elog_out = None
2088 + if self.logfile is not None:
2089 + if self.background:
2090 + elog_out = open(self.logfile, 'a')
2091 + msg = "Fetch failed for '%s'" % (self.pkg.cpv,)
2092 + if self.logfile is not None:
2093 + msg += ", Log file:"
2094 + eerror(msg, phase="unpack", key=self.pkg.cpv, out=elog_out)
2095 + if self.logfile is not None:
2096 + eerror(" '%s'" % (self.logfile,),
2097 + phase="unpack", key=self.pkg.cpv, out=elog_out)
2098 + if elog_out is not None:
2099 + elog_out.close()
2100 + if not self.prefetch:
2101 + portage.elog.elog_process(self.pkg.cpv, self._build_dir.settings)
2102 + features = self._build_dir.settings.features
2103 + if self.returncode == os.EX_OK:
2104 + self._build_dir.clean_log()
2105 + self._build_dir.unlock()
2106 + self.config_pool.deallocate(self._build_dir.settings)
2107 + self._build_dir = None
2108 +
2109
2110 Copied: main/branches/prefix/pym/_emerge/EbuildFetchonly.py (from rev 13663, main/trunk/pym/_emerge/EbuildFetchonly.py)
2111 ===================================================================
2112 --- main/branches/prefix/pym/_emerge/EbuildFetchonly.py (rev 0)
2113 +++ main/branches/prefix/pym/_emerge/EbuildFetchonly.py 2009-06-27 12:51:25 UTC (rev 13704)
2114 @@ -0,0 +1,81 @@
2115 +from _emerge.SlotObject import SlotObject
2116 +import shutil
2117 +# for an explanation on this logic, see pym/_emerge/__init__.py
2118 +import os
2119 +import sys
2120 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
2121 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
2122 +else:
2123 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
2124 +import portage
2125 +from portage.elog.messages import eerror
2126 +class EbuildFetchonly(SlotObject):
2127 +
2128 + __slots__ = ("fetch_all", "pkg", "pretend", "settings")
2129 +
2130 + def execute(self):
2131 + settings = self.settings
2132 + pkg = self.pkg
2133 + portdb = pkg.root_config.trees["porttree"].dbapi
2134 + ebuild_path = portdb.findname(pkg.cpv)
2135 + settings.setcpv(pkg)
2136 + debug = settings.get("PORTAGE_DEBUG") == "1"
2137 + restrict_fetch = 'fetch' in settings['PORTAGE_RESTRICT'].split()
2138 +
2139 + if restrict_fetch:
2140 + rval = self._execute_with_builddir()
2141 + else:
2142 + rval = portage.doebuild(ebuild_path, "fetch",
2143 + settings["ROOT"], settings, debug=debug,
2144 + listonly=self.pretend, fetchonly=1, fetchall=self.fetch_all,
2145 + mydbapi=portdb, tree="porttree")
2146 +
2147 + if rval != os.EX_OK:
2148 + msg = "Fetch failed for '%s'" % (pkg.cpv,)
2149 + eerror(msg, phase="unpack", key=pkg.cpv)
2150 +
2151 + return rval
2152 +
2153 + def _execute_with_builddir(self):
2154 + # To spawn pkg_nofetch requires PORTAGE_BUILDDIR for
2155 + # ensuring sane $PWD (bug #239560) and storing elog
2156 + # messages. Use a private temp directory, in order
2157 + # to avoid locking the main one.
2158 + settings = self.settings
2159 + global_tmpdir = settings["PORTAGE_TMPDIR"]
2160 + from tempfile import mkdtemp
2161 + try:
2162 + private_tmpdir = mkdtemp("", "._portage_fetch_.", global_tmpdir)
2163 + except OSError, e:
2164 + if e.errno != portage.exception.PermissionDenied.errno:
2165 + raise
2166 + raise portage.exception.PermissionDenied(global_tmpdir)
2167 + settings["PORTAGE_TMPDIR"] = private_tmpdir
2168 + settings.backup_changes("PORTAGE_TMPDIR")
2169 + try:
2170 + retval = self._execute()
2171 + finally:
2172 + settings["PORTAGE_TMPDIR"] = global_tmpdir
2173 + settings.backup_changes("PORTAGE_TMPDIR")
2174 + shutil.rmtree(private_tmpdir)
2175 + return retval
2176 +
2177 + def _execute(self):
2178 + settings = self.settings
2179 + pkg = self.pkg
2180 + root_config = pkg.root_config
2181 + portdb = root_config.trees["porttree"].dbapi
2182 + ebuild_path = portdb.findname(pkg.cpv)
2183 + debug = settings.get("PORTAGE_DEBUG") == "1"
2184 + retval = portage.doebuild(ebuild_path, "fetch",
2185 + self.settings["ROOT"], self.settings, debug=debug,
2186 + listonly=self.pretend, fetchonly=1, fetchall=self.fetch_all,
2187 + mydbapi=portdb, tree="porttree")
2188 +
2189 + if retval != os.EX_OK:
2190 + msg = "Fetch failed for '%s'" % (pkg.cpv,)
2191 + eerror(msg, phase="unpack", key=pkg.cpv)
2192 +
2193 + portage.elog.elog_process(self.pkg.cpv, self.settings)
2194 + return retval
2195 +
2196
2197 Copied: main/branches/prefix/pym/_emerge/EbuildMerge.py (from rev 13663, main/trunk/pym/_emerge/EbuildMerge.py)
2198 ===================================================================
2199 --- main/branches/prefix/pym/_emerge/EbuildMerge.py (rev 0)
2200 +++ main/branches/prefix/pym/_emerge/EbuildMerge.py 2009-06-27 12:51:25 UTC (rev 13704)
2201 @@ -0,0 +1,50 @@
2202 +from _emerge.SlotObject import SlotObject
2203 +# for an explanation on this logic, see pym/_emerge/__init__.py
2204 +import os
2205 +import sys
2206 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
2207 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
2208 +else:
2209 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
2210 +import portage
2211 +class EbuildMerge(SlotObject):
2212 +
2213 + __slots__ = ("find_blockers", "logger", "ldpath_mtimes",
2214 + "pkg", "pkg_count", "pkg_path", "pretend",
2215 + "scheduler", "settings", "tree", "world_atom")
2216 +
2217 + def execute(self):
2218 + root_config = self.pkg.root_config
2219 + settings = self.settings
2220 + retval = portage.merge(settings["CATEGORY"],
2221 + settings["PF"], settings["D"],
2222 + os.path.join(settings["PORTAGE_BUILDDIR"],
2223 + "build-info"), root_config.root, settings,
2224 + myebuild=settings["EBUILD"],
2225 + mytree=self.tree, mydbapi=root_config.trees[self.tree].dbapi,
2226 + vartree=root_config.trees["vartree"],
2227 + prev_mtimes=self.ldpath_mtimes,
2228 + scheduler=self.scheduler,
2229 + blockers=self.find_blockers)
2230 +
2231 + if retval == os.EX_OK:
2232 + self.world_atom(self.pkg)
2233 + self._log_success()
2234 +
2235 + return retval
2236 +
2237 + def _log_success(self):
2238 + pkg = self.pkg
2239 + pkg_count = self.pkg_count
2240 + pkg_path = self.pkg_path
2241 + logger = self.logger
2242 + if "noclean" not in self.settings.features:
2243 + short_msg = "emerge: (%s of %s) %s Clean Post" % \
2244 + (pkg_count.curval, pkg_count.maxval, pkg.cpv)
2245 + logger.log((" === (%s of %s) " + \
2246 + "Post-Build Cleaning (%s::%s)") % \
2247 + (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path),
2248 + short_msg=short_msg)
2249 + logger.log(" ::: completed emerge (%s of %s) %s to %s" % \
2250 + (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg.root))
2251 +
2252
2253 Copied: main/branches/prefix/pym/_emerge/EbuildMetadataPhase.py (from rev 13663, main/trunk/pym/_emerge/EbuildMetadataPhase.py)
2254 ===================================================================
2255 --- main/branches/prefix/pym/_emerge/EbuildMetadataPhase.py (rev 0)
2256 +++ main/branches/prefix/pym/_emerge/EbuildMetadataPhase.py 2009-06-27 12:51:25 UTC (rev 13704)
2257 @@ -0,0 +1,132 @@
2258 +from _emerge.SubProcess import SubProcess
2259 +from _emerge.PollConstants import PollConstants
2260 +import sys
2261 +from portage.cache.mappings import slot_dict_class
2262 +# for an explanation on this logic, see pym/_emerge/__init__.py
2263 +import os
2264 +import sys
2265 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
2266 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
2267 +else:
2268 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
2269 +import portage
2270 +from itertools import izip
2271 +import fcntl
2272 +import codecs
2273 +class EbuildMetadataPhase(SubProcess):
2274 +
2275 + """
2276 + Asynchronous interface for the ebuild "depend" phase which is
2277 + used to extract metadata from the ebuild.
2278 + """
2279 +
2280 + __slots__ = ("cpv", "ebuild_path", "fd_pipes", "metadata_callback",
2281 + "ebuild_mtime", "metadata", "portdb", "repo_path", "settings") + \
2282 + ("_raw_metadata",)
2283 +
2284 + _file_names = ("ebuild",)
2285 + _files_dict = slot_dict_class(_file_names, prefix="")
2286 + _metadata_fd = 9
2287 +
2288 + def _start(self):
2289 + settings = self.settings
2290 + settings.setcpv(self.cpv)
2291 + ebuild_path = self.ebuild_path
2292 +
2293 + eapi = None
2294 + if 'parse-eapi-glep-55' in settings.features:
2295 + pf, eapi = portage._split_ebuild_name_glep55(
2296 + os.path.basename(ebuild_path))
2297 + if eapi is None and \
2298 + 'parse-eapi-ebuild-head' in settings.features:
2299 + eapi = portage._parse_eapi_ebuild_head(codecs.open(ebuild_path,
2300 + mode='r', encoding='utf_8', errors='replace'))
2301 +
2302 + if eapi is not None:
2303 + if not portage.eapi_is_supported(eapi):
2304 + self.metadata_callback(self.cpv, self.ebuild_path,
2305 + self.repo_path, {'EAPI' : eapi}, self.ebuild_mtime)
2306 + self.returncode = os.EX_OK
2307 + self.wait()
2308 + return
2309 +
2310 + settings.configdict['pkg']['EAPI'] = eapi
2311 +
2312 + debug = settings.get("PORTAGE_DEBUG") == "1"
2313 + master_fd = None
2314 + slave_fd = None
2315 + fd_pipes = None
2316 + if self.fd_pipes is not None:
2317 + fd_pipes = self.fd_pipes.copy()
2318 + else:
2319 + fd_pipes = {}
2320 +
2321 + fd_pipes.setdefault(0, sys.stdin.fileno())
2322 + fd_pipes.setdefault(1, sys.stdout.fileno())
2323 + fd_pipes.setdefault(2, sys.stderr.fileno())
2324 +
2325 + # flush any pending output
2326 + for fd in fd_pipes.itervalues():
2327 + if fd == sys.stdout.fileno():
2328 + sys.stdout.flush()
2329 + if fd == sys.stderr.fileno():
2330 + sys.stderr.flush()
2331 +
2332 + fd_pipes_orig = fd_pipes.copy()
2333 + self._files = self._files_dict()
2334 + files = self._files
2335 +
2336 + master_fd, slave_fd = os.pipe()
2337 + fcntl.fcntl(master_fd, fcntl.F_SETFL,
2338 + fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
2339 +
2340 + fd_pipes[self._metadata_fd] = slave_fd
2341 +
2342 + self._raw_metadata = []
2343 + files.ebuild = os.fdopen(master_fd, 'r')
2344 + self._reg_id = self.scheduler.register(files.ebuild.fileno(),
2345 + self._registered_events, self._output_handler)
2346 + self._registered = True
2347 +
2348 + retval = portage.doebuild(ebuild_path, "depend",
2349 + settings["ROOT"], settings, debug,
2350 + mydbapi=self.portdb, tree="porttree",
2351 + fd_pipes=fd_pipes, returnpid=True)
2352 +
2353 + os.close(slave_fd)
2354 +
2355 + if isinstance(retval, int):
2356 + # doebuild failed before spawning
2357 + self._unregister()
2358 + self.returncode = retval
2359 + self.wait()
2360 + return
2361 +
2362 + self.pid = retval[0]
2363 + portage.process.spawned_pids.remove(self.pid)
2364 +
2365 + def _output_handler(self, fd, event):
2366 +
2367 + if event & PollConstants.POLLIN:
2368 + self._raw_metadata.append(self._files.ebuild.read())
2369 + if not self._raw_metadata[-1]:
2370 + self._unregister()
2371 + self.wait()
2372 +
2373 + self._unregister_if_appropriate(event)
2374 + return self._registered
2375 +
2376 + def _set_returncode(self, wait_retval):
2377 + SubProcess._set_returncode(self, wait_retval)
2378 + if self.returncode == os.EX_OK:
2379 + metadata_lines = "".join(self._raw_metadata).splitlines()
2380 + if len(portage.auxdbkeys) != len(metadata_lines):
2381 + # Don't trust bash's returncode if the
2382 + # number of lines is incorrect.
2383 + self.returncode = 1
2384 + else:
2385 + metadata = izip(portage.auxdbkeys, metadata_lines)
2386 + self.metadata = self.metadata_callback(self.cpv,
2387 + self.ebuild_path, self.repo_path, metadata,
2388 + self.ebuild_mtime)
2389 +
2390
2391 Copied: main/branches/prefix/pym/_emerge/EbuildPhase.py (from rev 13663, main/trunk/pym/_emerge/EbuildPhase.py)
2392 ===================================================================
2393 --- main/branches/prefix/pym/_emerge/EbuildPhase.py (rev 0)
2394 +++ main/branches/prefix/pym/_emerge/EbuildPhase.py 2009-06-27 12:51:25 UTC (rev 13704)
2395 @@ -0,0 +1,72 @@
2396 +from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
2397 +from _emerge.EbuildProcess import EbuildProcess
2398 +from _emerge.CompositeTask import CompositeTask
2399 +from portage.util import writemsg
2400 +# for an explanation on this logic, see pym/_emerge/__init__.py
2401 +import os
2402 +import sys
2403 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
2404 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
2405 +else:
2406 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
2407 +import portage
2408 +class EbuildPhase(CompositeTask):
2409 +
2410 + __slots__ = ("background", "pkg", "phase",
2411 + "scheduler", "settings", "tree")
2412 +
2413 + _post_phase_cmds = portage._post_phase_cmds
2414 +
2415 + def _start(self):
2416 +
2417 + ebuild_process = EbuildProcess(background=self.background,
2418 + pkg=self.pkg, phase=self.phase, scheduler=self.scheduler,
2419 + settings=self.settings, tree=self.tree)
2420 +
2421 + self._start_task(ebuild_process, self._ebuild_exit)
2422 +
2423 + def _ebuild_exit(self, ebuild_process):
2424 +
2425 + if self.phase == "install":
2426 + out = None
2427 + log_path = self.settings.get("PORTAGE_LOG_FILE")
2428 + log_file = None
2429 + if self.background and log_path is not None:
2430 + log_file = open(log_path, 'a')
2431 + out = log_file
2432 + try:
2433 + portage._check_build_log(self.settings, out=out)
2434 + finally:
2435 + if log_file is not None:
2436 + log_file.close()
2437 +
2438 + if self._default_exit(ebuild_process) != os.EX_OK:
2439 + self.wait()
2440 + return
2441 +
2442 + settings = self.settings
2443 +
2444 + if self.phase == "install":
2445 + portage._post_src_install_chost_fix(settings)
2446 + portage._post_src_install_uid_fix(settings)
2447 +
2448 + post_phase_cmds = self._post_phase_cmds.get(self.phase)
2449 + if post_phase_cmds is not None:
2450 + post_phase = MiscFunctionsProcess(background=self.background,
2451 + commands=post_phase_cmds, phase=self.phase, pkg=self.pkg,
2452 + scheduler=self.scheduler, settings=settings)
2453 + self._start_task(post_phase, self._post_phase_exit)
2454 + return
2455 +
2456 + self.returncode = ebuild_process.returncode
2457 + self._current_task = None
2458 + self.wait()
2459 +
2460 + def _post_phase_exit(self, post_phase):
2461 + if self._final_exit(post_phase) != os.EX_OK:
2462 + writemsg("!!! post %s failed; exiting.\n" % self.phase,
2463 + noiselevel=-1)
2464 + self._current_task = None
2465 + self.wait()
2466 + return
2467 +
2468
2469 Copied: main/branches/prefix/pym/_emerge/EbuildProcess.py (from rev 13663, main/trunk/pym/_emerge/EbuildProcess.py)
2470 ===================================================================
2471 --- main/branches/prefix/pym/_emerge/EbuildProcess.py (rev 0)
2472 +++ main/branches/prefix/pym/_emerge/EbuildProcess.py 2009-06-27 12:51:25 UTC (rev 13704)
2473 @@ -0,0 +1,55 @@
2474 +from _emerge.SpawnProcess import SpawnProcess
2475 +# for an explanation on this logic, see pym/_emerge/__init__.py
2476 +import os
2477 +import sys
2478 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
2479 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
2480 +else:
2481 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
2482 +import portage
2483 +class EbuildProcess(SpawnProcess):
2484 +
2485 + __slots__ = ("phase", "pkg", "settings", "tree")
2486 +
2487 + def _start(self):
2488 + # Don't open the log file during the clean phase since the
2489 + # open file can result in an nfs lock on $T/build.log which
2490 + # prevents the clean phase from removing $T.
2491 + if self.phase not in ("clean", "cleanrm"):
2492 + self.logfile = self.settings.get("PORTAGE_LOG_FILE")
2493 + SpawnProcess._start(self)
2494 +
2495 + def _pipe(self, fd_pipes):
2496 + stdout_pipe = fd_pipes.get(1)
2497 + got_pty, master_fd, slave_fd = \
2498 + portage._create_pty_or_pipe(copy_term_size=stdout_pipe)
2499 + return (master_fd, slave_fd)
2500 +
2501 + def _spawn(self, args, **kwargs):
2502 +
2503 + root_config = self.pkg.root_config
2504 + tree = self.tree
2505 + mydbapi = root_config.trees[tree].dbapi
2506 + settings = self.settings
2507 + ebuild_path = settings["EBUILD"]
2508 + debug = settings.get("PORTAGE_DEBUG") == "1"
2509 +
2510 + rval = portage.doebuild(ebuild_path, self.phase,
2511 + root_config.root, settings, debug,
2512 + mydbapi=mydbapi, tree=tree, **kwargs)
2513 +
2514 + return rval
2515 +
2516 + def _set_returncode(self, wait_retval):
2517 + SpawnProcess._set_returncode(self, wait_retval)
2518 +
2519 + if self.phase not in ("clean", "cleanrm"):
2520 + self.returncode = portage._doebuild_exit_status_check_and_log(
2521 + self.settings, self.phase, self.returncode)
2522 +
2523 + if self.phase == "test" and self.returncode != os.EX_OK and \
2524 + "test-fail-continue" in self.settings.features:
2525 + self.returncode = os.EX_OK
2526 +
2527 + portage._post_phase_userpriv_perms(self.settings)
2528 +
2529
2530 Copied: main/branches/prefix/pym/_emerge/MiscFunctionsProcess.py (from rev 13663, main/trunk/pym/_emerge/MiscFunctionsProcess.py)
2531 ===================================================================
2532 --- main/branches/prefix/pym/_emerge/MiscFunctionsProcess.py (rev 0)
2533 +++ main/branches/prefix/pym/_emerge/MiscFunctionsProcess.py 2009-06-27 12:51:25 UTC (rev 13704)
2534 @@ -0,0 +1,42 @@
2535 +from _emerge.SpawnProcess import SpawnProcess
2536 +# for an explanation on this logic, see pym/_emerge/__init__.py
2537 +import os
2538 +import sys
2539 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
2540 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
2541 +else:
2542 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
2543 +import portage
2544 +class MiscFunctionsProcess(SpawnProcess):
2545 + """
2546 + Spawns misc-functions.sh with an existing ebuild environment.
2547 + """
2548 +
2549 + __slots__ = ("commands", "phase", "pkg", "settings")
2550 +
2551 + def _start(self):
2552 + settings = self.settings
2553 + settings.pop("EBUILD_PHASE", None)
2554 + portage_bin_path = settings["PORTAGE_BIN_PATH"]
2555 + misc_sh_binary = os.path.join(portage_bin_path,
2556 + os.path.basename(portage.const.MISC_SH_BINARY))
2557 +
2558 + self.args = [portage._shell_quote(misc_sh_binary)] + self.commands
2559 + self.logfile = settings.get("PORTAGE_LOG_FILE")
2560 +
2561 + portage._doebuild_exit_status_unlink(
2562 + settings.get("EBUILD_EXIT_STATUS_FILE"))
2563 +
2564 + SpawnProcess._start(self)
2565 +
2566 + def _spawn(self, args, **kwargs):
2567 + settings = self.settings
2568 + debug = settings.get("PORTAGE_DEBUG") == "1"
2569 + return portage.spawn(" ".join(args), settings,
2570 + debug=debug, **kwargs)
2571 +
2572 + def _set_returncode(self, wait_retval):
2573 + SpawnProcess._set_returncode(self, wait_retval)
2574 + self.returncode = portage._doebuild_exit_status_check_and_log(
2575 + self.settings, self.phase, self.returncode)
2576 +
2577
2578 Copied: main/branches/prefix/pym/_emerge/PackageArg.py (from rev 13663, main/trunk/pym/_emerge/PackageArg.py)
2579 ===================================================================
2580 --- main/branches/prefix/pym/_emerge/PackageArg.py (rev 0)
2581 +++ main/branches/prefix/pym/_emerge/PackageArg.py 2009-06-27 12:51:25 UTC (rev 13704)
2582 @@ -0,0 +1,16 @@
2583 +from _emerge.DependencyArg import DependencyArg
2584 +# for an explanation on this logic, see pym/_emerge/__init__.py
2585 +import os
2586 +import sys
2587 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
2588 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
2589 +else:
2590 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
2591 +import portage
2592 +class PackageArg(DependencyArg):
2593 + def __init__(self, package=None, **kwargs):
2594 + DependencyArg.__init__(self, **kwargs)
2595 + self.package = package
2596 + self.atom = portage.dep.Atom("=" + package.cpv)
2597 + self.set = (self.atom, )
2598 +
2599
2600 Copied: main/branches/prefix/pym/_emerge/PackageMerge.py (from rev 13663, main/trunk/pym/_emerge/PackageMerge.py)
2601 ===================================================================
2602 --- main/branches/prefix/pym/_emerge/PackageMerge.py (rev 0)
2603 +++ main/branches/prefix/pym/_emerge/PackageMerge.py 2009-06-27 12:51:25 UTC (rev 13704)
2604 @@ -0,0 +1,42 @@
2605 +from _emerge.AsynchronousTask import AsynchronousTask
2606 +from portage.output import colorize
2607 +class PackageMerge(AsynchronousTask):
2608 + """
2609 + TODO: Implement asynchronous merge so that the scheduler can
2610 + run while a merge is executing.
2611 + """
2612 +
2613 + __slots__ = ("merge",)
2614 +
2615 + def _start(self):
2616 +
2617 + pkg = self.merge.pkg
2618 + pkg_count = self.merge.pkg_count
2619 +
2620 + if pkg.installed:
2621 + action_desc = "Uninstalling"
2622 + preposition = "from"
2623 + counter_str = ""
2624 + else:
2625 + action_desc = "Installing"
2626 + preposition = "to"
2627 + counter_str = "(%s of %s) " % \
2628 + (colorize("MERGE_LIST_PROGRESS", str(pkg_count.curval)),
2629 + colorize("MERGE_LIST_PROGRESS", str(pkg_count.maxval)))
2630 +
2631 + msg = "%s %s%s" % \
2632 + (action_desc,
2633 + counter_str,
2634 + colorize("GOOD", pkg.cpv))
2635 +
2636 + if pkg.root != "/":
2637 + msg += " %s %s" % (preposition, pkg.root)
2638 +
2639 + if not self.merge.build_opts.fetchonly and \
2640 + not self.merge.build_opts.pretend and \
2641 + not self.merge.build_opts.buildpkgonly:
2642 + self.merge.statusMessage(msg)
2643 +
2644 + self.returncode = self.merge.merge()
2645 + self.wait()
2646 +
2647
2648 Copied: main/branches/prefix/pym/_emerge/PackageVirtualDbapi.py (from rev 13663, main/trunk/pym/_emerge/PackageVirtualDbapi.py)
2649 ===================================================================
2650 --- main/branches/prefix/pym/_emerge/PackageVirtualDbapi.py (rev 0)
2651 +++ main/branches/prefix/pym/_emerge/PackageVirtualDbapi.py 2009-06-27 12:51:25 UTC (rev 13704)
2652 @@ -0,0 +1,141 @@
2653 +# for an explanation on this logic, see pym/_emerge/__init__.py
2654 +import os
2655 +import sys
2656 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
2657 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
2658 +else:
2659 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
2660 +import portage
2661 +class PackageVirtualDbapi(portage.dbapi):
2662 + """
2663 + A dbapi-like interface class that represents the state of the installed
2664 + package database as new packages are installed, replacing any packages
2665 + that previously existed in the same slot. The main difference between
2666 + this class and fakedbapi is that this one uses Package instances
2667 + internally (passed in via cpv_inject() and cpv_remove() calls).
2668 + """
2669 + def __init__(self, settings):
2670 + portage.dbapi.__init__(self)
2671 + self.settings = settings
2672 + self._match_cache = {}
2673 + self._cp_map = {}
2674 + self._cpv_map = {}
2675 +
2676 + def clear(self):
2677 + """
2678 + Remove all packages.
2679 + """
2680 + if self._cpv_map:
2681 + self._clear_cache()
2682 + self._cp_map.clear()
2683 + self._cpv_map.clear()
2684 +
2685 + def copy(self):
2686 + obj = PackageVirtualDbapi(self.settings)
2687 + obj._match_cache = self._match_cache.copy()
2688 + obj._cp_map = self._cp_map.copy()
2689 + for k, v in obj._cp_map.iteritems():
2690 + obj._cp_map[k] = v[:]
2691 + obj._cpv_map = self._cpv_map.copy()
2692 + return obj
2693 +
2694 + def __iter__(self):
2695 + return self._cpv_map.itervalues()
2696 +
2697 + def __contains__(self, item):
2698 + existing = self._cpv_map.get(item.cpv)
2699 + if existing is not None and \
2700 + existing == item:
2701 + return True
2702 + return False
2703 +
2704 + def get(self, item, default=None):
2705 + cpv = getattr(item, "cpv", None)
2706 + if cpv is None:
2707 + if len(item) != 4:
2708 + return default
2709 + type_name, root, cpv, operation = item
2710 +
2711 + existing = self._cpv_map.get(cpv)
2712 + if existing is not None and \
2713 + existing == item:
2714 + return existing
2715 + return default
2716 +
2717 + def match_pkgs(self, atom):
2718 + return [self._cpv_map[cpv] for cpv in self.match(atom)]
2719 +
2720 + def _clear_cache(self):
2721 + if self._categories is not None:
2722 + self._categories = None
2723 + if self._match_cache:
2724 + self._match_cache = {}
2725 +
2726 + def match(self, origdep, use_cache=1):
2727 + result = self._match_cache.get(origdep)
2728 + if result is not None:
2729 + return result[:]
2730 + result = portage.dbapi.match(self, origdep, use_cache=use_cache)
2731 + self._match_cache[origdep] = result
2732 + return result[:]
2733 +
2734 + def cpv_exists(self, cpv):
2735 + return cpv in self._cpv_map
2736 +
2737 + def cp_list(self, mycp, use_cache=1):
2738 + cachelist = self._match_cache.get(mycp)
2739 + # cp_list() doesn't expand old-style virtuals
2740 + if cachelist and cachelist[0].startswith(mycp):
2741 + return cachelist[:]
2742 + cpv_list = self._cp_map.get(mycp)
2743 + if cpv_list is None:
2744 + cpv_list = []
2745 + else:
2746 + cpv_list = [pkg.cpv for pkg in cpv_list]
2747 + self._cpv_sort_ascending(cpv_list)
2748 + if not (not cpv_list and mycp.startswith("virtual/")):
2749 + self._match_cache[mycp] = cpv_list
2750 + return cpv_list[:]
2751 +
2752 + def cp_all(self):
2753 + return list(self._cp_map)
2754 +
2755 + def cpv_all(self):
2756 + return list(self._cpv_map)
2757 +
2758 + def cpv_inject(self, pkg):
2759 + cp_list = self._cp_map.get(pkg.cp)
2760 + if cp_list is None:
2761 + cp_list = []
2762 + self._cp_map[pkg.cp] = cp_list
2763 + e_pkg = self._cpv_map.get(pkg.cpv)
2764 + if e_pkg is not None:
2765 + if e_pkg == pkg:
2766 + return
2767 + self.cpv_remove(e_pkg)
2768 + for e_pkg in cp_list:
2769 + if e_pkg.slot_atom == pkg.slot_atom:
2770 + if e_pkg == pkg:
2771 + return
2772 + self.cpv_remove(e_pkg)
2773 + break
2774 + cp_list.append(pkg)
2775 + self._cpv_map[pkg.cpv] = pkg
2776 + self._clear_cache()
2777 +
2778 + def cpv_remove(self, pkg):
2779 + old_pkg = self._cpv_map.get(pkg.cpv)
2780 + if old_pkg != pkg:
2781 + raise KeyError(pkg)
2782 + self._cp_map[pkg.cp].remove(pkg)
2783 + del self._cpv_map[pkg.cpv]
2784 + self._clear_cache()
2785 +
2786 + def aux_get(self, cpv, wants):
2787 + metadata = self._cpv_map[cpv].metadata
2788 + return [metadata.get(x, "") for x in wants]
2789 +
2790 + def aux_update(self, cpv, values):
2791 + self._cpv_map[cpv].metadata.update(values)
2792 + self._clear_cache()
2793 +
2794
2795 Copied: main/branches/prefix/pym/_emerge/PipeReader.py (from rev 13663, main/trunk/pym/_emerge/PipeReader.py)
2796 ===================================================================
2797 --- main/branches/prefix/pym/_emerge/PipeReader.py (rev 0)
2798 +++ main/branches/prefix/pym/_emerge/PipeReader.py 2009-06-27 12:51:25 UTC (rev 13704)
2799 @@ -0,0 +1,98 @@
2800 +from _emerge.AbstractPollTask import AbstractPollTask
2801 +from _emerge.PollConstants import PollConstants
2802 +import sys
2803 +import os
2804 +import fcntl
2805 +import array
2806 +class PipeReader(AbstractPollTask):
2807 +
2808 + """
2809 + Reads output from one or more files and saves it in memory,
2810 + for retrieval via the getvalue() method. This is driven by
2811 + the scheduler's poll() loop, so it runs entirely within the
2812 + current process.
2813 + """
2814 +
2815 + __slots__ = ("input_files",) + \
2816 + ("_read_data", "_reg_ids")
2817 +
2818 + def _start(self):
2819 + self._reg_ids = set()
2820 + self._read_data = []
2821 + for k, f in self.input_files.iteritems():
2822 + fcntl.fcntl(f.fileno(), fcntl.F_SETFL,
2823 + fcntl.fcntl(f.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
2824 + self._reg_ids.add(self.scheduler.register(f.fileno(),
2825 + self._registered_events, self._output_handler))
2826 + self._registered = True
2827 +
2828 + def isAlive(self):
2829 + return self._registered
2830 +
2831 + def cancel(self):
2832 + if self.returncode is None:
2833 + self.returncode = 1
2834 + self.cancelled = True
2835 + self.wait()
2836 +
2837 + def _wait(self):
2838 + if self.returncode is not None:
2839 + return self.returncode
2840 +
2841 + if self._registered:
2842 + self.scheduler.schedule(self._reg_ids)
2843 + self._unregister()
2844 +
2845 + self.returncode = os.EX_OK
2846 + return self.returncode
2847 +
2848 + def getvalue(self):
2849 + """Retrieve the entire contents"""
2850 + if sys.hexversion >= 0x3000000:
2851 + return bytes().join(self._read_data)
2852 + return "".join(self._read_data)
2853 +
2854 + def close(self):
2855 + """Free the memory buffer."""
2856 + self._read_data = None
2857 +
2858 + def _output_handler(self, fd, event):
2859 +
2860 + if event & PollConstants.POLLIN:
2861 +
2862 + for f in self.input_files.itervalues():
2863 + if fd == f.fileno():
2864 + break
2865 +
2866 + buf = array.array('B')
2867 + try:
2868 + buf.fromfile(f, self._bufsize)
2869 + except EOFError:
2870 + pass
2871 +
2872 + if buf:
2873 + self._read_data.append(buf.tostring())
2874 + else:
2875 + self._unregister()
2876 + self.wait()
2877 +
2878 + self._unregister_if_appropriate(event)
2879 + return self._registered
2880 +
2881 + def _unregister(self):
2882 + """
2883 + Unregister from the scheduler and close open files.
2884 + """
2885 +
2886 + self._registered = False
2887 +
2888 + if self._reg_ids is not None:
2889 + for reg_id in self._reg_ids:
2890 + self.scheduler.unregister(reg_id)
2891 + self._reg_ids = None
2892 +
2893 + if self.input_files is not None:
2894 + for f in self.input_files.itervalues():
2895 + f.close()
2896 + self.input_files = None
2897 +
2898
2899 Copied: main/branches/prefix/pym/_emerge/PollConstants.py (from rev 13663, main/trunk/pym/_emerge/PollConstants.py)
2900 ===================================================================
2901 --- main/branches/prefix/pym/_emerge/PollConstants.py (rev 0)
2902 +++ main/branches/prefix/pym/_emerge/PollConstants.py 2009-06-27 12:51:25 UTC (rev 13704)
2903 @@ -0,0 +1,15 @@
2904 +import select
2905 +class PollConstants(object):
2906 +
2907 + """
2908 + Provides POLL* constants that are equivalent to those from the
2909 + select module, for use by PollSelectAdapter.
2910 + """
2911 +
2912 + names = ("POLLIN", "POLLPRI", "POLLOUT", "POLLERR", "POLLHUP", "POLLNVAL")
2913 + v = 1
2914 + for k in names:
2915 + locals()[k] = getattr(select, k, v)
2916 + v *= 2
2917 + del k, v
2918 +
2919
2920 Copied: main/branches/prefix/pym/_emerge/PollSelectAdapter.py (from rev 13663, main/trunk/pym/_emerge/PollSelectAdapter.py)
2921 ===================================================================
2922 --- main/branches/prefix/pym/_emerge/PollSelectAdapter.py (rev 0)
2923 +++ main/branches/prefix/pym/_emerge/PollSelectAdapter.py 2009-06-27 12:51:25 UTC (rev 13704)
2924 @@ -0,0 +1,70 @@
2925 +from _emerge.PollConstants import PollConstants
2926 +import select
2927 +class PollSelectAdapter(PollConstants):
2928 +
2929 + """
2930 + Use select to emulate a poll object, for
2931 + systems that don't support poll().
2932 + """
2933 +
2934 + def __init__(self):
2935 + self._registered = {}
2936 + self._select_args = [[], [], []]
2937 +
2938 + def register(self, fd, *args):
2939 + """
2940 + Only POLLIN is currently supported!
2941 + """
2942 + if len(args) > 1:
2943 + raise TypeError(
2944 + "register expected at most 2 arguments, got " + \
2945 + repr(1 + len(args)))
2946 +
2947 + eventmask = PollConstants.POLLIN | \
2948 + PollConstants.POLLPRI | PollConstants.POLLOUT
2949 + if args:
2950 + eventmask = args[0]
2951 +
2952 + self._registered[fd] = eventmask
2953 + self._select_args = None
2954 +
2955 + def unregister(self, fd):
2956 + self._select_args = None
2957 + del self._registered[fd]
2958 +
2959 + def poll(self, *args):
2960 + if len(args) > 1:
2961 + raise TypeError(
2962 + "poll expected at most 2 arguments, got " + \
2963 + repr(1 + len(args)))
2964 +
2965 + timeout = None
2966 + if args:
2967 + timeout = args[0]
2968 +
2969 + select_args = self._select_args
2970 + if select_args is None:
2971 + select_args = [self._registered.keys(), [], []]
2972 +
2973 + if timeout is not None:
2974 + select_args = select_args[:]
2975 + # Translate poll() timeout args to select() timeout args:
2976 + #
2977 + # | units | value(s) for indefinite block
2978 + # ---------|--------------|------------------------------
2979 + # poll | milliseconds | omitted, negative, or None
2980 + # ---------|--------------|------------------------------
2981 + # select | seconds | omitted
2982 + # ---------|--------------|------------------------------
2983 +
2984 + if timeout is not None and timeout < 0:
2985 + timeout = None
2986 + if timeout is not None:
2987 + select_args.append(timeout / 1000)
2988 +
2989 + select_events = select.select(*select_args)
2990 + poll_events = []
2991 + for fd in select_events[0]:
2992 + poll_events.append((fd, PollConstants.POLLIN))
2993 + return poll_events
2994 +
2995
2996 Copied: main/branches/prefix/pym/_emerge/ProgressHandler.py (from rev 13663, main/trunk/pym/_emerge/ProgressHandler.py)
2997 ===================================================================
2998 --- main/branches/prefix/pym/_emerge/ProgressHandler.py (rev 0)
2999 +++ main/branches/prefix/pym/_emerge/ProgressHandler.py 2009-06-27 12:51:25 UTC (rev 13704)
3000 @@ -0,0 +1,19 @@
3001 +import time
3002 +class ProgressHandler(object):
3003 + def __init__(self):
3004 + self.curval = 0
3005 + self.maxval = 0
3006 + self._last_update = 0
3007 + self.min_latency = 0.2
3008 +
3009 + def onProgress(self, maxval, curval):
3010 + self.maxval = maxval
3011 + self.curval = curval
3012 + cur_time = time.time()
3013 + if cur_time - self._last_update >= self.min_latency:
3014 + self._last_update = cur_time
3015 + self.display()
3016 +
3017 + def display(self):
3018 + raise NotImplementedError(self)
3019 +
3020
3021 Copied: main/branches/prefix/pym/_emerge/RepoDisplay.py (from rev 13663, main/trunk/pym/_emerge/RepoDisplay.py)
3022 ===================================================================
3023 --- main/branches/prefix/pym/_emerge/RepoDisplay.py (rev 0)
3024 +++ main/branches/prefix/pym/_emerge/RepoDisplay.py 2009-06-27 12:51:25 UTC (rev 13704)
3025 @@ -0,0 +1,61 @@
3026 +from portage.output import teal
3027 +import os
3028 +class RepoDisplay(object):
3029 + def __init__(self, roots):
3030 + self._shown_repos = {}
3031 + self._unknown_repo = False
3032 + repo_paths = set()
3033 + for root_config in roots.itervalues():
3034 + portdir = root_config.settings.get("PORTDIR")
3035 + if portdir:
3036 + repo_paths.add(portdir)
3037 + overlays = root_config.settings.get("PORTDIR_OVERLAY")
3038 + if overlays:
3039 + repo_paths.update(overlays.split())
3040 + repo_paths = list(repo_paths)
3041 + self._repo_paths = repo_paths
3042 + self._repo_paths_real = [ os.path.realpath(repo_path) \
3043 + for repo_path in repo_paths ]
3044 +
3045 + # pre-allocate index for PORTDIR so that it always has index 0.
3046 + for root_config in roots.itervalues():
3047 + portdb = root_config.trees["porttree"].dbapi
3048 + portdir = portdb.porttree_root
3049 + if portdir:
3050 + self.repoStr(portdir)
3051 +
3052 + def repoStr(self, repo_path_real):
3053 + real_index = -1
3054 + if repo_path_real:
3055 + real_index = self._repo_paths_real.index(repo_path_real)
3056 + if real_index == -1:
3057 + s = "?"
3058 + self._unknown_repo = True
3059 + else:
3060 + shown_repos = self._shown_repos
3061 + repo_paths = self._repo_paths
3062 + repo_path = repo_paths[real_index]
3063 + index = shown_repos.get(repo_path)
3064 + if index is None:
3065 + index = len(shown_repos)
3066 + shown_repos[repo_path] = index
3067 + s = str(index)
3068 + return s
3069 +
3070 + def __str__(self):
3071 + output = []
3072 + shown_repos = self._shown_repos
3073 + unknown_repo = self._unknown_repo
3074 + if shown_repos or self._unknown_repo:
3075 + output.append("Portage tree and overlays:\n")
3076 + show_repo_paths = list(shown_repos)
3077 + for repo_path, repo_index in shown_repos.iteritems():
3078 + show_repo_paths[repo_index] = repo_path
3079 + if show_repo_paths:
3080 + for index, repo_path in enumerate(show_repo_paths):
3081 + output.append(" "+teal("["+str(index)+"]")+" %s\n" % repo_path)
3082 + if unknown_repo:
3083 + output.append(" "+teal("[?]") + \
3084 + " indicates that the source repository could not be determined\n")
3085 + return "".join(output)
3086 +
3087
3088 Copied: main/branches/prefix/pym/_emerge/SequentialTaskQueue.py (from rev 13663, main/trunk/pym/_emerge/SequentialTaskQueue.py)
3089 ===================================================================
3090 --- main/branches/prefix/pym/_emerge/SequentialTaskQueue.py (rev 0)
3091 +++ main/branches/prefix/pym/_emerge/SequentialTaskQueue.py 2009-06-27 12:51:25 UTC (rev 13704)
3092 @@ -0,0 +1,83 @@
3093 +from _emerge.SlotObject import SlotObject
3094 +from collections import deque
3095 +class SequentialTaskQueue(SlotObject):
3096 +
3097 + __slots__ = ("max_jobs", "running_tasks") + \
3098 + ("_dirty", "_scheduling", "_task_queue")
3099 +
3100 + def __init__(self, **kwargs):
3101 + SlotObject.__init__(self, **kwargs)
3102 + self._task_queue = deque()
3103 + self.running_tasks = set()
3104 + if self.max_jobs is None:
3105 + self.max_jobs = 1
3106 + self._dirty = True
3107 +
3108 + def add(self, task):
3109 + self._task_queue.append(task)
3110 + self._dirty = True
3111 +
3112 + def addFront(self, task):
3113 + self._task_queue.appendleft(task)
3114 + self._dirty = True
3115 +
3116 + def schedule(self):
3117 +
3118 + if not self._dirty:
3119 + return False
3120 +
3121 + if not self:
3122 + return False
3123 +
3124 + if self._scheduling:
3125 + # Ignore any recursive schedule() calls triggered via
3126 + # self._task_exit().
3127 + return False
3128 +
3129 + self._scheduling = True
3130 +
3131 + task_queue = self._task_queue
3132 + running_tasks = self.running_tasks
3133 + max_jobs = self.max_jobs
3134 + state_changed = False
3135 +
3136 + while task_queue and \
3137 + (max_jobs is True or len(running_tasks) < max_jobs):
3138 + task = task_queue.popleft()
3139 + cancelled = getattr(task, "cancelled", None)
3140 + if not cancelled:
3141 + running_tasks.add(task)
3142 + task.addExitListener(self._task_exit)
3143 + task.start()
3144 + state_changed = True
3145 +
3146 + self._dirty = False
3147 + self._scheduling = False
3148 +
3149 + return state_changed
3150 +
3151 + def _task_exit(self, task):
3152 + """
3153 + Since we can always rely on exit listeners being called, the set of
3154 + running tasks is always pruned automatically and there is never any need
3155 + to actively prune it.
3156 + """
3157 + self.running_tasks.remove(task)
3158 + if self._task_queue:
3159 + self._dirty = True
3160 +
3161 + def clear(self):
3162 + self._task_queue.clear()
3163 + running_tasks = self.running_tasks
3164 + while running_tasks:
3165 + task = running_tasks.pop()
3166 + task.removeExitListener(self._task_exit)
3167 + task.cancel()
3168 + self._dirty = False
3169 +
3170 + def __nonzero__(self):
3171 + return bool(self._task_queue or self.running_tasks)
3172 +
3173 + def __len__(self):
3174 + return len(self._task_queue) + len(self.running_tasks)
3175 +
3176
3177 Copied: main/branches/prefix/pym/_emerge/SetArg.py (from rev 13663, main/trunk/pym/_emerge/SetArg.py)
3178 ===================================================================
3179 --- main/branches/prefix/pym/_emerge/SetArg.py (rev 0)
3180 +++ main/branches/prefix/pym/_emerge/SetArg.py 2009-06-27 12:51:25 UTC (rev 13704)
3181 @@ -0,0 +1,8 @@
3182 +from _emerge.DependencyArg import DependencyArg
3183 +from portage.sets import SETPREFIX
3184 +class SetArg(DependencyArg):
3185 + def __init__(self, set=None, **kwargs):
3186 + DependencyArg.__init__(self, **kwargs)
3187 + self.set = set
3188 + self.name = self.arg[len(SETPREFIX):]
3189 +
3190
3191 Copied: main/branches/prefix/pym/_emerge/SlotObject.py (from rev 13663, main/trunk/pym/_emerge/SlotObject.py)
3192 ===================================================================
3193 --- main/branches/prefix/pym/_emerge/SlotObject.py (rev 0)
3194 +++ main/branches/prefix/pym/_emerge/SlotObject.py 2009-06-27 12:51:25 UTC (rev 13704)
3195 @@ -0,0 +1,39 @@
3196 +class SlotObject(object):
3197 + __slots__ = ("__weakref__",)
3198 +
3199 + def __init__(self, **kwargs):
3200 + classes = [self.__class__]
3201 + while classes:
3202 + c = classes.pop()
3203 + if c is SlotObject:
3204 + continue
3205 + classes.extend(c.__bases__)
3206 + slots = getattr(c, "__slots__", None)
3207 + if not slots:
3208 + continue
3209 + for myattr in slots:
3210 + myvalue = kwargs.get(myattr, None)
3211 + setattr(self, myattr, myvalue)
3212 +
3213 + def copy(self):
3214 + """
3215 + Create a new instance and copy all attributes
3216 + defined from __slots__ (including those from
3217 + inherited classes).
3218 + """
3219 + obj = self.__class__()
3220 +
3221 + classes = [self.__class__]
3222 + while classes:
3223 + c = classes.pop()
3224 + if c is SlotObject:
3225 + continue
3226 + classes.extend(c.__bases__)
3227 + slots = getattr(c, "__slots__", None)
3228 + if not slots:
3229 + continue
3230 + for myattr in slots:
3231 + setattr(obj, myattr, getattr(self, myattr))
3232 +
3233 + return obj
3234 +
3235
3236 Copied: main/branches/prefix/pym/_emerge/SpawnProcess.py (from rev 13663, main/trunk/pym/_emerge/SpawnProcess.py)
3237 ===================================================================
3238 --- main/branches/prefix/pym/_emerge/SpawnProcess.py (rev 0)
3239 +++ main/branches/prefix/pym/_emerge/SpawnProcess.py 2009-06-27 12:51:25 UTC (rev 13704)
3240 @@ -0,0 +1,219 @@
3241 +from _emerge.SubProcess import SubProcess
3242 +from _emerge.PollConstants import PollConstants
3243 +import sys
3244 +from portage.cache.mappings import slot_dict_class
3245 +# for an explanation on this logic, see pym/_emerge/__init__.py
3246 +import os
3247 +import sys
3248 +if os.environ.__contains__("PORTAGE_PYTHONPATH"):
3249 + sys.path.insert(0, os.environ["PORTAGE_PYTHONPATH"])
3250 +else:
3251 + sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
3252 +import portage
3253 +import fcntl
3254 +import errno
3255 +import array
3256 +class SpawnProcess(SubProcess):
3257 +
3258 + """
3259 + Constructor keyword args are passed into portage.process.spawn().
3260 + The required "args" keyword argument will be passed as the first
3261 + spawn() argument.
3262 + """
3263 +
3264 + _spawn_kwarg_names = ("env", "opt_name", "fd_pipes",
3265 + "uid", "gid", "groups", "umask", "logfile",
3266 + "path_lookup", "pre_exec")
3267 +
3268 + __slots__ = ("args",) + \
3269 + _spawn_kwarg_names
3270 +
3271 + _file_names = ("log", "process", "stdout")
3272 + _files_dict = slot_dict_class(_file_names, prefix="")
3273 +
3274 + def _start(self):
3275 +
3276 + if self.cancelled:
3277 + return
3278 +
3279 + if self.fd_pipes is None:
3280 + self.fd_pipes = {}
3281 + fd_pipes = self.fd_pipes
3282 + fd_pipes.setdefault(0, sys.stdin.fileno())
3283 + fd_pipes.setdefault(1, sys.stdout.fileno())
3284 + fd_pipes.setdefault(2, sys.stderr.fileno())
3285 +
3286 + # flush any pending output
3287 + for fd in fd_pipes.itervalues():
3288 + if fd == sys.stdout.fileno():
3289 + sys.stdout.flush()
3290 + if fd == sys.stderr.fileno():
3291 + sys.stderr.flush()
3292 +
3293 + logfile = self.logfile
3294 + self._files = self._files_dict()
3295 + files = self._files
3296 +
3297 + master_fd, slave_fd = self._pipe(fd_pipes)
3298 + fcntl.fcntl(master_fd, fcntl.F_SETFL,
3299 + fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
3300 +
3301 + null_input = None
3302 + fd_pipes_orig = fd_pipes.copy()
3303 + if self.background:
3304 + # TODO: Use job control functions like tcsetpgrp() to control
3305 + # access to stdin. Until then, use /dev/null so that any
3306 + # attempts to read from stdin will immediately return EOF
3307 + # instead of blocking indefinitely.
3308 + null_input = open('/dev/null', 'rb')
3309 + fd_pipes[0] = null_input.fileno()
3310 + else:
3311 + fd_pipes[0] = fd_pipes_orig[0]
3312 +
3313 + files.process = os.fdopen(master_fd, 'rb')
3314 + if logfile is not None:
3315 +
3316 + fd_pipes[1] = slave_fd
3317 + fd_pipes[2] = slave_fd
3318 +
3319 + files.log = open(logfile, mode='ab')
3320 + portage.util.apply_secpass_permissions(logfile,
3321 + uid=portage.portage_uid, gid=portage.portage_gid,
3322 + mode=0660)
3323 +
3324 + if not self.background:
3325 + files.stdout = os.fdopen(os.dup(fd_pipes_orig[1]), 'wb')
3326 +
3327 + output_handler = self._output_handler
3328 +
3329 + else:
3330 +
3331 + # Create a dummy pipe so the scheduler can monitor
3332 + # the process from inside a poll() loop.
3333 + fd_pipes[self._dummy_pipe_fd] = slave_fd
3334 + if self.background:
3335 + fd_pipes[1] = slave_fd
3336 + fd_pipes[2] = slave_fd
3337 + output_handler = self._dummy_handler
3338 +
3339 + kwargs = {}
3340 + for k in self._spawn_kwarg_names:
3341 + v = getattr(self, k)
3342 + if v is not None:
3343 + kwargs[k] = v
3344 +
3345 + kwargs["fd_pipes"] = fd_pipes
3346 + kwargs["returnpid"] = True
3347 + kwargs.pop("logfile", None)
3348 +
3349 + self._reg_id = self.scheduler.register(files.process.fileno(),
3350 + self._registered_events, output_handler)
3351 + self._registered = True
3352 +
3353 + retval = self._spawn(self.args, **kwargs)
3354 +
3355 + os.close(slave_fd)
3356 + if null_input is not None:
3357 + null_input.close()
3358 +
3359 + if isinstance(retval, int):
3360 + # spawn failed
3361 + self._unregister()
3362 + self.returncode = retval
3363 + self.wait()
3364 + return
3365 +
3366 + self.pid = retval[0]
3367 + portage.process.spawned_pids.remove(self.pid)
3368 +
3369 + def _pipe(self, fd_pipes):
3370 + """
3371 + @type fd_pipes: dict
3372 + @param fd_pipes: pipes from which to copy terminal size if desired.
3373 + """
3374 + return os.pipe()
3375 +
3376 + def _spawn(self, args, **kwargs):
3377 + return portage.process.spawn(args, **kwargs)
3378 +
3379 + def _output_handler(self, fd, event):
3380 +
3381 + if event & PollConstants.POLLIN:
3382 +
3383 + files = self._files
3384 + buf = array.array('B')
3385 + try:
3386 + buf.fromfile(files.process, self._bufsize)
3387 + except EOFError:
3388 + pass
3389 +
3390 + if buf:
3391 + if not self.background:
3392 + write_successful = False
3393 + failures = 0
3394 + while True:
3395 + try:
3396 + if not write_successful:
3397 + buf.tofile(files.stdout)
3398 + write_successful = True
3399 + files.stdout.flush()
3400 + break
3401 + except IOError, e:
3402 + if e.errno != errno.EAGAIN:
3403 + raise
3404 + del e
3405 + failures += 1
3406 + if failures > 50:
3407 + # Avoid a potentially infinite loop. In
3408 + # most cases, the failure count is zero
3409 + # and it's unlikely to exceed 1.
3410 + raise
3411 +
3412 + # This means that a subprocess has put an inherited
3413 + # stdio file descriptor (typically stdin) into
3414 + # O_NONBLOCK mode. This is not acceptable (see bug
3415 + # #264435), so revert it. We need to use a loop
3416 + # here since there's a race condition due to
3417 + # parallel processes being able to change the
3418 + # flags on the inherited file descriptor.
3419 + # TODO: When possible, avoid having child processes
3420 + # inherit stdio file descriptors from portage
3421 + # (maybe it can't be avoided with
3422 + # PROPERTIES=interactive).
3423 + fcntl.fcntl(files.stdout.fileno(), fcntl.F_SETFL,
3424 + fcntl.fcntl(files.stdout.fileno(),
3425 + fcntl.F_GETFL) ^ os.O_NONBLOCK)
3426 +
3427 + buf.tofile(files.log)
3428 + files.log.flush()
3429 + else:
3430 + self._unregister()
3431 + self.wait()
3432 +
3433 + self._unregister_if_appropriate(event)
3434 + return self._registered
3435 +
3436 + def _dummy_handler(self, fd, event):
3437 + """
3438 + This method is mainly interested in detecting EOF, since
3439 + the only purpose of the pipe is to allow the scheduler to
3440 + monitor the process from inside a poll() loop.
3441 + """
3442 +
3443 + if event & PollConstants.POLLIN:
3444 +
3445 + buf = array.array('B')
3446 + try:
3447 + buf.fromfile(self._files.process, self._bufsize)
3448 + except EOFError:
3449 + pass
3450 +
3451 + if buf:
3452 + pass
3453 + else:
3454 + self._unregister()
3455 + self.wait()
3456 +
3457 + self._unregister_if_appropriate(event)
3458 + return self._registered
3459 +
3460
3461 Copied: main/branches/prefix/pym/_emerge/SubProcess.py (from rev 13663, main/trunk/pym/_emerge/SubProcess.py)
3462 ===================================================================
3463 --- main/branches/prefix/pym/_emerge/SubProcess.py (rev 0)
3464 +++ main/branches/prefix/pym/_emerge/SubProcess.py 2009-06-27 12:51:25 UTC (rev 13704)
3465 @@ -0,0 +1,104 @@
3466 +from _emerge.AbstractPollTask import AbstractPollTask
3467 +import signal
3468 +import os
3469 +import errno
3470 +class SubProcess(AbstractPollTask):
3471 +
3472 + __slots__ = ("pid",) + \
3473 + ("_files", "_reg_id")
3474 +
3475 + # A file descriptor is required for the scheduler to monitor changes from
3476 + # inside a poll() loop. When logging is not enabled, create a pipe just to
3477 + # serve this purpose alone.
3478 + _dummy_pipe_fd = 9
3479 +
3480 + def _poll(self):
3481 + if self.returncode is not None:
3482 + return self.returncode
3483 + if self.pid is None:
3484 + return self.returncode
3485 + if self._registered:
3486 + return self.returncode
3487 +
3488 + try:
3489 + retval = os.waitpid(self.pid, os.WNOHANG)
3490 + except OSError, e:
3491 + if e.errno != errno.ECHILD:
3492 + raise
3493 + del e
3494 + retval = (self.pid, 1)
3495 +
3496 + if retval == (0, 0):
3497 + return None
3498 + self._set_returncode(retval)
3499 + return self.returncode
3500 +
3501 + def cancel(self):
3502 + if self.isAlive():
3503 + try:
3504 + os.kill(self.pid, signal.SIGTERM)
3505 + except OSError, e:
3506 + if e.errno != errno.ESRCH:
3507 + raise
3508 + del e
3509 +
3510 + self.cancelled = True
3511 + if self.pid is not None:
3512 + self.wait()
3513 + return self.returncode
3514 +
3515 + def isAlive(self):
3516 + return self.pid is not None and \
3517 + self.returncode is None
3518 +
3519 + def _wait(self):
3520 +
3521 + if self.returncode is not None:
3522 + return self.returncode
3523 +
3524 + if self._registered:
3525 + self.scheduler.schedule(self._reg_id)
3526 + self._unregister()
3527 + if self.returncode is not None:
3528 + return self.returncode
3529 +
3530 + try:
3531 + wait_retval = os.waitpid(self.pid, 0)
3532 + except OSError, e:
3533 + if e.errno != errno.ECHILD:
3534 + raise
3535 + del e
3536 + self._set_returncode((self.pid, 1))
3537 + else:
3538 + self._set_returncode(wait_retval)
3539 +
3540 + return self.returncode
3541 +
3542 + def _unregister(self):
3543 + """
3544 + Unregister from the scheduler and close open files.
3545 + """
3546 +
3547 + self._registered = False
3548 +
3549 + if self._reg_id is not None:
3550 + self.scheduler.unregister(self._reg_id)
3551 + self._reg_id = None
3552 +
3553 + if self._files is not None:
3554 + for f in self._files.itervalues():
3555 + f.close()
3556 + self._files = None
3557 +
3558 + def _set_returncode(self, wait_retval):
3559 +
3560 + retval = wait_retval[1]
3561 +
3562 + if retval != os.EX_OK:
3563 + if retval & 0xff:
3564 + retval = (retval & 0xff) << 8
3565 + else:
3566 + retval = retval >> 8
3567 +
3568 + self.returncode = retval
3569 +
3570
3571 Copied: main/branches/prefix/pym/_emerge/Task.py (from rev 13663, main/trunk/pym/_emerge/Task.py)
3572 ===================================================================
3573 --- main/branches/prefix/pym/_emerge/Task.py (rev 0)
3574 +++ main/branches/prefix/pym/_emerge/Task.py 2009-06-27 12:51:25 UTC (rev 13704)
3575 @@ -0,0 +1,37 @@
3576 +from _emerge.SlotObject import SlotObject
3577 +class Task(SlotObject):
3578 + __slots__ = ("_hash_key", "_hash_value")
3579 +
3580 + def _get_hash_key(self):
3581 + hash_key = getattr(self, "_hash_key", None)
3582 + if hash_key is None:
3583 + raise NotImplementedError(self)
3584 + return hash_key
3585 +
3586 + def __eq__(self, other):
3587 + return self._get_hash_key() == other
3588 +
3589 + def __ne__(self, other):
3590 + return self._get_hash_key() != other
3591 +
3592 + def __hash__(self):
3593 + hash_value = getattr(self, "_hash_value", None)
3594 + if hash_value is None:
3595 + self._hash_value = hash(self._get_hash_key())
3596 + return self._hash_value
3597 +
3598 + def __len__(self):
3599 + return len(self._get_hash_key())
3600 +
3601 + def __getitem__(self, key):
3602 + return self._get_hash_key()[key]
3603 +
3604 + def __iter__(self):
3605 + return iter(self._get_hash_key())
3606 +
3607 + def __contains__(self, key):
3608 + return key in self._get_hash_key()
3609 +
3610 + def __str__(self):
3611 + return str(self._get_hash_key())
3612 +
3613
3614 Copied: main/branches/prefix/pym/_emerge/TaskSequence.py (from rev 13663, main/trunk/pym/_emerge/TaskSequence.py)
3615 ===================================================================
3616 --- main/branches/prefix/pym/_emerge/TaskSequence.py (rev 0)
3617 +++ main/branches/prefix/pym/_emerge/TaskSequence.py 2009-06-27 12:51:25 UTC (rev 13704)
3618 @@ -0,0 +1,40 @@
3619 +from _emerge.CompositeTask import CompositeTask
3620 +from _emerge.AsynchronousTask import AsynchronousTask
3621 +import os
3622 +from collections import deque
3623 +class TaskSequence(CompositeTask):
3624 + """
3625 + A collection of tasks that executes sequentially. Each task
3626 + must have a addExitListener() method that can be used as
3627 + a means to trigger movement from one task to the next.
3628 + """
3629 +
3630 + __slots__ = ("_task_queue",)
3631 +
3632 + def __init__(self, **kwargs):
3633 + AsynchronousTask.__init__(self, **kwargs)
3634 + self._task_queue = deque()
3635 +
3636 + def add(self, task):
3637 + self._task_queue.append(task)
3638 +
3639 + def _start(self):
3640 + self._start_next_task()
3641 +
3642 + def cancel(self):
3643 + self._task_queue.clear()
3644 + CompositeTask.cancel(self)
3645 +
3646 + def _start_next_task(self):
3647 + self._start_task(self._task_queue.popleft(),
3648 + self._task_exit_handler)
3649 +
3650 + def _task_exit_handler(self, task):
3651 + if self._default_exit(task) != os.EX_OK:
3652 + self.wait()
3653 + elif self._task_queue:
3654 + self._start_next_task()
3655 + else:
3656 + self._final_exit(task)
3657 + self.wait()
3658 +
3659
3660 Copied: main/branches/prefix/pym/_emerge/UnmergeDepPriority.py (from rev 13663, main/trunk/pym/_emerge/UnmergeDepPriority.py)
3661 ===================================================================
3662 --- main/branches/prefix/pym/_emerge/UnmergeDepPriority.py (rev 0)
3663 +++ main/branches/prefix/pym/_emerge/UnmergeDepPriority.py 2009-06-27 12:51:25 UTC (rev 13704)
3664 @@ -0,0 +1,31 @@
3665 +from _emerge.AbstractDepPriority import AbstractDepPriority
3666 +class UnmergeDepPriority(AbstractDepPriority):
3667 + __slots__ = ("optional", "satisfied",)
3668 + """
3669 + Combination of properties Priority Category
3670 +
3671 + runtime 0 HARD
3672 + runtime_post -1 HARD
3673 + buildtime -2 SOFT
3674 + (none of the above) -2 SOFT
3675 + """
3676 +
3677 + MAX = 0
3678 + SOFT = -2
3679 + MIN = -2
3680 +
3681 + def __int__(self):
3682 + if self.runtime:
3683 + return 0
3684 + if self.runtime_post:
3685 + return -1
3686 + if self.buildtime:
3687 + return -2
3688 + return -2
3689 +
3690 + def __str__(self):
3691 + myvalue = self.__int__()
3692 + if myvalue > self.SOFT:
3693 + return "hard"
3694 + return "soft"
3695 +
3696
3697 Copied: main/branches/prefix/pym/_emerge/UseFlagDisplay.py (from rev 13663, main/trunk/pym/_emerge/UseFlagDisplay.py)
3698 ===================================================================
3699 --- main/branches/prefix/pym/_emerge/UseFlagDisplay.py (rev 0)
3700 +++ main/branches/prefix/pym/_emerge/UseFlagDisplay.py 2009-06-27 12:51:25 UTC (rev 13704)
3701 @@ -0,0 +1,44 @@
3702 +from portage.output import red
3703 +from portage.util import cmp_sort_key
3704 +from portage.output import blue
3705 +class UseFlagDisplay(object):
3706 +
3707 + __slots__ = ('name', 'enabled', 'forced')
3708 +
3709 + def __init__(self, name, enabled, forced):
3710 + self.name = name
3711 + self.enabled = enabled
3712 + self.forced = forced
3713 +
3714 + def __str__(self):
3715 + s = self.name
3716 + if self.enabled:
3717 + s = red(s)
3718 + else:
3719 + s = '-' + s
3720 + s = blue(s)
3721 + if self.forced:
3722 + s = '(%s)' % s
3723 + return s
3724 +
3725 + def _cmp_combined(a, b):
3726 + """
3727 + Sort by name, combining enabled and disabled flags.
3728 + """
3729 + return (a.name > b.name) - (a.name < b.name)
3730 +
3731 + sort_combined = cmp_sort_key(_cmp_combined)
3732 + del _cmp_combined
3733 +
3734 + def _cmp_separated(a, b):
3735 + """
3736 + Sort by name, separating enabled flags from disabled flags.
3737 + """
3738 + enabled_diff = b.enabled - a.enabled
3739 + if enabled_diff:
3740 + return enabled_diff
3741 + return (a.name > b.name) - (a.name < b.name)
3742 +
3743 + sort_separated = cmp_sort_key(_cmp_separated)
3744 + del _cmp_separated
3745 +
3746
3747 Modified: main/branches/prefix/pym/_emerge/__init__.py
3748 ===================================================================
3749 --- main/branches/prefix/pym/_emerge/__init__.py 2009-06-26 23:38:01 UTC (rev 13703)
3750 +++ main/branches/prefix/pym/_emerge/__init__.py 2009-06-27 12:51:25 UTC (rev 13704)
3751 @@ -3,26 +3,19 @@
3752 # Distributed under the terms of the GNU General Public License v2
3753 # $Id$
3754
3755 -import array
3756 -import codecs
3757 -from collections import deque
3758 -import fcntl
3759 import formatter
3760 import logging
3761 import pwd
3762 import select
3763 import shlex
3764 -import shutil
3765 import signal
3766 import sys
3767 import textwrap
3768 -import urlparse
3769 import weakref
3770 import gc
3771 import os, stat
3772 import platform
3773
3774 -
3775 # Portage module path logic (Prefix way)
3776 # In principle we don't want to be dependant on the environment
3777 # (PYTHONPATH) and/or python hardcoded default search path.
3778 @@ -42,13 +35,12 @@
3779 sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pym"))
3780 import portage
3781
3782 -
3783 from portage import digraph
3784 from portage.const import NEWS_LIB_PATH
3785
3786 import _emerge.help
3787 import portage.xpak, commands, errno, re, socket, time
3788 -from portage.output import blue, bold, colorize, darkblue, darkgreen, darkred, green, \
3789 +from portage.output import blue, bold, colorize, darkblue, darkgreen, green, \
3790 nc_len, red, teal, turquoise, xtermTitle, \
3791 xtermTitleReset, yellow
3792 from portage.output import create_color_func
3793 @@ -74,10 +66,36 @@
3794
3795 from itertools import chain, izip
3796
3797 -try:
3798 - import cPickle as pickle
3799 -except ImportError:
3800 - import pickle
3801 +from _emerge.SlotObject import SlotObject
3802 +from _emerge.DepPriority import DepPriority
3803 +from _emerge.BlockerDepPriority import BlockerDepPriority
3804 +from _emerge.UnmergeDepPriority import UnmergeDepPriority
3805 +from _emerge.DepPriorityNormalRange import DepPriorityNormalRange
3806 +from _emerge.DepPrioritySatisfiedRange import DepPrioritySatisfiedRange
3807 +from _emerge.Task import Task
3808 +from _emerge.Blocker import Blocker
3809 +from _emerge.PollConstants import PollConstants
3810 +from _emerge.AsynchronousTask import AsynchronousTask
3811 +from _emerge.CompositeTask import CompositeTask
3812 +from _emerge.EbuildFetcher import EbuildFetcher
3813 +from _emerge.EbuildBuild import EbuildBuild
3814 +from _emerge.EbuildMetadataPhase import EbuildMetadataPhase
3815 +from _emerge.EbuildPhase import EbuildPhase
3816 +from _emerge.Binpkg import Binpkg
3817 +from _emerge.BinpkgPrefetcher import BinpkgPrefetcher
3818 +from _emerge.PackageMerge import PackageMerge
3819 +from _emerge.DependencyArg import DependencyArg
3820 +from _emerge.AtomArg import AtomArg
3821 +from _emerge.PackageArg import PackageArg
3822 +from _emerge.SetArg import SetArg
3823 +from _emerge.Dependency import Dependency
3824 +from _emerge.BlockerCache import BlockerCache
3825 +from _emerge.PackageVirtualDbapi import PackageVirtualDbapi
3826 +from _emerge.RepoDisplay import RepoDisplay
3827 +from _emerge.UseFlagDisplay import UseFlagDisplay
3828 +from _emerge.PollSelectAdapter import PollSelectAdapter
3829 +from _emerge.SequentialTaskQueue import SequentialTaskQueue
3830 +from _emerge.ProgressHandler import ProgressHandler
3831
3832 try:
3833 from cStringIO import StringIO
3834 @@ -253,7 +271,7 @@
3835 "v":"--verbose", "V":"--version"
3836 }
3837
3838 -_emerge_log_dir = EPREFIX+'/var/log'
3839 +_emerge_log_dir = '/var/log'
3840
3841 def emergelog(xterm_titles, mystr, short_msg=None):
3842 if xterm_titles and short_msg:
3843 @@ -884,292 +902,6 @@
3844 else:
3845 yield flag
3846
3847 -class SlotObject(object):
3848 - __slots__ = ("__weakref__",)
3849 -
3850 - def __init__(self, **kwargs):
3851 - classes = [self.__class__]
3852 - while classes:
3853 - c = classes.pop()
3854 - if c is SlotObject:
3855 - continue
3856 - classes.extend(c.__bases__)
3857 - slots = getattr(c, "__slots__", None)
3858 - if not slots:
3859 - continue
3860 - for myattr in slots:
3861 - myvalue = kwargs.get(myattr, None)
3862 - setattr(self, myattr, myvalue)
3863 -
3864 - def copy(self):
3865 - """
3866 - Create a new instance and copy all attributes
3867 - defined from __slots__ (including those from
3868 - inherited classes).
3869 - """
3870 - obj = self.__class__()
3871 -
3872 - classes = [self.__class__]
3873 - while classes:
3874 - c = classes.pop()
3875 - if c is SlotObject:
3876 - continue
3877 - classes.extend(c.__bases__)
3878 - slots = getattr(c, "__slots__", None)
3879 - if not slots:
3880 - continue
3881 - for myattr in slots:
3882 - setattr(obj, myattr, getattr(self, myattr))
3883 -
3884 - return obj
3885 -
3886 -class AbstractDepPriority(SlotObject):
3887 - __slots__ = ("buildtime", "runtime", "runtime_post")
3888 -
3889 - def __lt__(self, other):
3890 - return self.__int__() < other
3891 -
3892 - def __le__(self, other):
3893 - return self.__int__() <= other
3894 -
3895 - def __eq__(self, other):
3896 - return self.__int__() == other
3897 -
3898 - def __ne__(self, other):
3899 - return self.__int__() != other
3900 -
3901 - def __gt__(self, other):
3902 - return self.__int__() > other
3903 -
3904 - def __ge__(self, other):
3905 - return self.__int__() >= other
3906 -
3907 - def copy(self):
3908 - import copy
3909 - return copy.copy(self)
3910 -
3911 -class DepPriority(AbstractDepPriority):
3912 -
3913 - __slots__ = ("satisfied", "optional", "rebuild")
3914 -
3915 - def __int__(self):
3916 - """
3917 - Note: These priorities are only used for measuring hardness
3918 - in the circular dependency display via digraph.debug_print(),
3919 - and nothing more. For actual merge order calculations, the
3920 - measures defined by the DepPriorityNormalRange and
3921 - DepPrioritySatisfiedRange classes are used.
3922 -
3923 - Attributes Hardness
3924 -
3925 - buildtime 0
3926 - runtime -1
3927 - runtime_post -2
3928 - optional -3
3929 - (none of the above) -4
3930 -
3931 - """
3932 -
3933 - if self.buildtime:
3934 - return 0
3935 - if self.runtime:
3936 - return -1
3937 - if self.runtime_post:
3938 - return -2
3939 - if self.optional:
3940 - return -3
3941 - return -4
3942 -
3943 - def __str__(self):
3944 - if self.optional:
3945 - return "optional"
3946 - if self.buildtime:
3947 - return "buildtime"
3948 - if self.runtime:
3949 - return "runtime"
3950 - if self.runtime_post:
3951 - return "runtime_post"
3952 - return "soft"
3953 -
3954 -class BlockerDepPriority(DepPriority):
3955 - __slots__ = ()
3956 - def __int__(self):
3957 - return 0
3958 -
3959 - def __str__(self):
3960 - return 'blocker'
3961 -
3962 -BlockerDepPriority.instance = BlockerDepPriority()
3963 -
3964 -class UnmergeDepPriority(AbstractDepPriority):
3965 - __slots__ = ("optional", "satisfied",)
3966 - """
3967 - Combination of properties Priority Category
3968 -
3969 - runtime 0 HARD
3970 - runtime_post -1 HARD
3971 - buildtime -2 SOFT
3972 - (none of the above) -2 SOFT
3973 - """
3974 -
3975 - MAX = 0
3976 - SOFT = -2
3977 - MIN = -2
3978 -
3979 - def __int__(self):
3980 - if self.runtime:
3981 - return 0
3982 - if self.runtime_post:
3983 - return -1
3984 - if self.buildtime:
3985 - return -2
3986 - return -2
3987 -
3988 - def __str__(self):
3989 - myvalue = self.__int__()
3990 - if myvalue > self.SOFT:
3991 - return "hard"
3992 - return "soft"
3993 -
3994 -class DepPriorityNormalRange(object):
3995 - """
3996 - DepPriority properties Index Category
3997 -
3998 - buildtime HARD
3999 - runtime 3 MEDIUM
4000 - runtime_post 2 MEDIUM_SOFT
4001 - optional 1 SOFT
4002 - (none of the above) 0 NONE
4003 - """
4004 - MEDIUM = 3
4005 - MEDIUM_SOFT = 2
4006 - SOFT = 1
4007 - NONE = 0
4008 -
4009 - @classmethod
4010 - def _ignore_optional(cls, priority):
4011 - if priority.__class__ is not DepPriority:
4012 - return False
4013 - return bool(priority.optional)
4014 -
4015 - @classmethod
4016 - def _ignore_runtime_post(cls, priority):
4017 - if priority.__class__ is not DepPriority:
4018 - return False
4019 - return bool(priority.optional or priority.runtime_post)
4020 -
4021 - @classmethod
4022 - def _ignore_runtime(cls, priority):
4023 - if priority.__class__ is not DepPriority:
4024 - return False
4025 - return not priority.buildtime
4026 -
4027 - ignore_medium = _ignore_runtime
4028 - ignore_medium_soft = _ignore_runtime_post
4029 - ignore_soft = _ignore_optional
4030 -
4031 -DepPriorityNormalRange.ignore_priority = (
4032 - None,
4033 - DepPriorityNormalRange._ignore_optional,
4034 - DepPriorityNormalRange._ignore_runtime_post,
4035 - DepPriorityNormalRange._ignore_runtime
4036 -)
4037 -
4038 -class DepPrioritySatisfiedRange(object):
4039 - """
4040 - DepPriority Index Category
4041 -
4042 - not satisfied and buildtime HARD
4043 - not satisfied and runtime 7 MEDIUM
4044 - not satisfied and runtime_post 6 MEDIUM_SOFT
4045 - satisfied and buildtime and rebuild 5 SOFT
4046 - satisfied and buildtime 4 SOFT
4047 - satisfied and runtime 3 SOFT
4048 - satisfied and runtime_post 2 SOFT
4049 - optional 1 SOFT
4050 - (none of the above) 0 NONE
4051 - """
4052 - MEDIUM = 7
4053 - MEDIUM_SOFT = 6
4054 - SOFT = 5
4055 - NONE = 0
4056 -
4057 - @classmethod
4058 - def _ignore_optional(cls, priority):
4059 - if priority.__class__ is not DepPriority:
4060 - return False
4061 - return bool(priority.optional)
4062 -
4063 - @classmethod
4064 - def _ignore_satisfied_runtime_post(cls, priority):
4065 - if priority.__class__ is not DepPriority:
4066 - return False
4067 - if priority.optional:
4068 - return True
4069 - if not priority.satisfied:
4070 - return False
4071 - return bool(priority.runtime_post)
4072 -
4073 - @classmethod
4074 - def _ignore_satisfied_runtime(cls, priority):
4075 - if priority.__class__ is not DepPriority:
4076 - return False
4077 - if priority.optional:
4078 - return True
4079 - if not priority.satisfied:
4080 - return False
4081 - return not priority.buildtime
4082 -
4083 - @classmethod
4084 - def _ignore_satisfied_buildtime(cls, priority):
4085 - if priority.__class__ is not DepPriority:
4086 - return False
4087 - if priority.optional:
4088 - return True
4089 - if not priority.satisfied:
4090 - return False
4091 - if priority.buildtime:
4092 - return not priority.rebuild
4093 - return True
4094 -
4095 - @classmethod
4096 - def _ignore_satisfied_buildtime_rebuild(cls, priority):
4097 - if priority.__class__ is not DepPriority:
4098 - return False
4099 - if priority.optional:
4100 - return True
4101 - return bool(priority.satisfied)
4102 -
4103 - @classmethod
4104 - def _ignore_runtime_post(cls, priority):
4105 - if priority.__class__ is not DepPriority:
4106 - return False
4107 - return bool(priority.optional or \
4108 - priority.satisfied or \
4109 - priority.runtime_post)
4110 -
4111 - @classmethod
4112 - def _ignore_runtime(cls, priority):
4113 - if priority.__class__ is not DepPriority:
4114 - return False
4115 - return bool(priority.satisfied or \
4116 - not priority.buildtime)
4117 -
4118 - ignore_medium = _ignore_runtime
4119 - ignore_medium_soft = _ignore_runtime_post
4120 - ignore_soft = _ignore_satisfied_buildtime_rebuild
4121 -
4122 -DepPrioritySatisfiedRange.ignore_priority = (
4123 - None,
4124 - DepPrioritySatisfiedRange._ignore_optional,
4125 - DepPrioritySatisfiedRange._ignore_satisfied_runtime_post,
4126 - DepPrioritySatisfiedRange._ignore_satisfied_runtime,
4127 - DepPrioritySatisfiedRange._ignore_satisfied_buildtime,
4128 - DepPrioritySatisfiedRange._ignore_satisfied_buildtime_rebuild,
4129 - DepPrioritySatisfiedRange._ignore_runtime_post,
4130 - DepPrioritySatisfiedRange._ignore_runtime
4131 -)
4132 -
4133 def _find_deep_system_runtime_deps(graph):
4134 deep_system_deps = set()
4135 node_stack = []
4136 @@ -1560,58 +1292,6 @@
4137 shown_licenses.add(l)
4138 return have_eapi_mask
4139
4140 -class Task(SlotObject):
4141 - __slots__ = ("_hash_key", "_hash_value")
4142 -
4143 - def _get_hash_key(self):
4144 - hash_key = getattr(self, "_hash_key", None)
4145 - if hash_key is None:
4146 - raise NotImplementedError(self)
4147 - return hash_key
4148 -
4149 - def __eq__(self, other):
4150 - return self._get_hash_key() == other
4151 -
4152 - def __ne__(self, other):
4153 - return self._get_hash_key() != other
4154 -
4155 - def __hash__(self):
4156 - hash_value = getattr(self, "_hash_value", None)
4157 - if hash_value is None:
4158 - self._hash_value = hash(self._get_hash_key())
4159 - return self._hash_value
4160 -
4161 - def __len__(self):
4162 - return len(self._get_hash_key())
4163 -
4164 - def __getitem__(self, key):
4165 - return self._get_hash_key()[key]
4166 -
4167 - def __iter__(self):
4168 - return iter(self._get_hash_key())
4169 -
4170 - def __contains__(self, key):
4171 - return key in self._get_hash_key()
4172 -
4173 - def __str__(self):
4174 - return str(self._get_hash_key())
4175 -
4176 -class Blocker(Task):
4177 -
4178 - __hash__ = Task.__hash__
4179 - __slots__ = ("root", "atom", "cp", "eapi", "satisfied")
4180 -
4181 - def __init__(self, **kwargs):
4182 - Task.__init__(self, **kwargs)
4183 - self.cp = portage.dep_getkey(self.atom)
4184 -
4185 - def _get_hash_key(self):
4186 - hash_key = getattr(self, "_hash_key", None)
4187 - if hash_key is None:
4188 - self._hash_key = \
4189 - ("blocks", self.root, self.atom, self.eapi)
4190 - return self._hash_key
4191 -
4192 class Package(Task):
4193
4194 __hash__ = Task.__hash__
4195 @@ -1626,7 +1306,8 @@
4196 "CHOST", "COUNTER", "DEPEND", "EAPI",
4197 "INHERITED", "IUSE", "KEYWORDS",
4198 "LICENSE", "PDEPEND", "PROVIDE", "RDEPEND",
4199 - "repository", "PROPERTIES", "RESTRICT", "SLOT", "USE", "_mtime_", "EPREFIX" ]
4200 + "repository", "PROPERTIES", "RESTRICT", "SLOT", "USE", "_mtime_",
4201 + "EPREFIX" ]
4202
4203 def __init__(self, **kwargs):
4204 Task.__init__(self, **kwargs)
4205 @@ -1784,1627 +1465,6 @@
4206 v = 0
4207 self._pkg.mtime = v
4208
4209 -class EbuildFetchonly(SlotObject):
4210 -
4211 - __slots__ = ("fetch_all", "pkg", "pretend", "settings")
4212 -
4213 - def execute(self):
4214 - settings = self.settings
4215 - pkg = self.pkg
4216 - portdb = pkg.root_config.trees["porttree"].dbapi
4217 - ebuild_path = portdb.findname(pkg.cpv)
4218 - settings.setcpv(pkg)
4219 - debug = settings.get("PORTAGE_DEBUG") == "1"
4220 - restrict_fetch = 'fetch' in settings['PORTAGE_RESTRICT'].split()
4221 -
4222 - if restrict_fetch:
4223 - rval = self._execute_with_builddir()
4224 - else:
4225 - rval = portage.doebuild(ebuild_path, "fetch",
4226 - settings["ROOT"], settings, debug=debug,
4227 - listonly=self.pretend, fetchonly=1, fetchall=self.fetch_all,
4228 - mydbapi=portdb, tree="porttree")
4229 -
4230 - if rval != os.EX_OK:
4231 - msg = "Fetch failed for '%s'" % (pkg.cpv,)
4232 - eerror(msg, phase="unpack", key=pkg.cpv)
4233 -
4234 - return rval
4235 -
4236 - def _execute_with_builddir(self):
4237 - # To spawn pkg_nofetch requires PORTAGE_BUILDDIR for
4238 - # ensuring sane $PWD (bug #239560) and storing elog
4239 - # messages. Use a private temp directory, in order
4240 - # to avoid locking the main one.
4241 - settings = self.settings
4242 - global_tmpdir = settings["PORTAGE_TMPDIR"]
4243 - from tempfile import mkdtemp
4244 - try:
4245 - private_tmpdir = mkdtemp("", "._portage_fetch_.", global_tmpdir)
4246 - except OSError, e:
4247 - if e.errno != portage.exception.PermissionDenied.errno:
4248 - raise
4249 - raise portage.exception.PermissionDenied(global_tmpdir)
4250 - settings["PORTAGE_TMPDIR"] = private_tmpdir
4251 - settings.backup_changes("PORTAGE_TMPDIR")
4252 - try:
4253 - retval = self._execute()
4254 - finally:
4255 - settings["PORTAGE_TMPDIR"] = global_tmpdir
4256 - settings.backup_changes("PORTAGE_TMPDIR")
4257 - shutil.rmtree(private_tmpdir)
4258 - return retval
4259 -
4260 - def _execute(self):
4261 - settings = self.settings
4262 - pkg = self.pkg
4263 - root_config = pkg.root_config
4264 - portdb = root_config.trees["porttree"].dbapi
4265 - ebuild_path = portdb.findname(pkg.cpv)
4266 - debug = settings.get("PORTAGE_DEBUG") == "1"
4267 - retval = portage.doebuild(ebuild_path, "fetch",
4268 - self.settings["ROOT"], self.settings, debug=debug,
4269 - listonly=self.pretend, fetchonly=1, fetchall=self.fetch_all,
4270 - mydbapi=portdb, tree="porttree")
4271 -
4272 - if retval != os.EX_OK:
4273 - msg = "Fetch failed for '%s'" % (pkg.cpv,)
4274 - eerror(msg, phase="unpack", key=pkg.cpv)
4275 -
4276 - portage.elog.elog_process(self.pkg.cpv, self.settings)
4277 - return retval
4278 -
4279 -class PollConstants(object):
4280 -
4281 - """
4282 - Provides POLL* constants that are equivalent to those from the
4283 - select module, for use by PollSelectAdapter.
4284 - """
4285 -
4286 - names = ("POLLIN", "POLLPRI", "POLLOUT", "POLLERR", "POLLHUP", "POLLNVAL")
4287 - v = 1
4288 - for k in names:
4289 - locals()[k] = getattr(select, k, v)
4290 - v *= 2
4291 - del k, v
4292 -
4293 -class AsynchronousTask(SlotObject):
4294 - """
4295 - Subclasses override _wait() and _poll() so that calls
4296 - to public methods can be wrapped for implementing
4297 - hooks such as exit listener notification.
4298 -
4299 - Sublasses should call self.wait() to notify exit listeners after
4300 - the task is complete and self.returncode has been set.
4301 - """
4302 -
4303 - __slots__ = ("background", "cancelled", "returncode") + \
4304 - ("_exit_listeners", "_exit_listener_stack", "_start_listeners")
4305 -
4306 - def start(self):
4307 - """
4308 - Start an asynchronous task and then return as soon as possible.
4309 - """
4310 - self._start_hook()
4311 - self._start()
4312 -
4313 - def _start(self):
4314 - raise NotImplementedError(self)
4315 -
4316 - def isAlive(self):
4317 - return self.returncode is None
4318 -
4319 - def poll(self):
4320 - self._wait_hook()
4321 - return self._poll()
4322 -
4323 - def _poll(self):
4324 - return self.returncode
4325 -
4326 - def wait(self):
4327 - if self.returncode is None:
4328 - self._wait()
4329 - self._wait_hook()
4330 - return self.returncode
4331 -
4332 - def _wait(self):
4333 - return self.returncode
4334 -
4335 - def cancel(self):
4336 - self.cancelled = True
4337 - self.wait()
4338 -
4339 - def addStartListener(self, f):
4340 - """
4341 - The function will be called with one argument, a reference to self.
4342 - """
4343 - if self._start_listeners is None:
4344 - self._start_listeners = []
4345 - self._start_listeners.append(f)
4346 -
4347 - def removeStartListener(self, f):
4348 - if self._start_listeners is None:
4349 - return
4350 - self._start_listeners.remove(f)
4351 -
4352 - def _start_hook(self):
4353 - if self._start_listeners is not None:
4354 - start_listeners = self._start_listeners
4355 - self._start_listeners = None
4356 -
4357 - for f in start_listeners:
4358 - f(self)
4359 -
4360 - def addExitListener(self, f):
4361 - """
4362 - The function will be called with one argument, a reference to self.
4363 - """
4364 - if self._exit_listeners is None:
4365 - self._exit_listeners = []
4366 - self._exit_listeners.append(f)
4367 -
4368 - def removeExitListener(self, f):
4369 - if self._exit_listeners is None:
4370 - if self._exit_listener_stack is not None:
4371 - self._exit_listener_stack.remove(f)
4372 - return
4373 - self._exit_listeners.remove(f)
4374 -
4375 - def _wait_hook(self):
4376 - """
4377 - Call this method after the task completes, just before returning
4378 - the returncode from wait() or poll(). This hook is
4379 - used to trigger exit listeners when the returncode first
4380 - becomes available.
4381 - """
4382 - if self.returncode is not None and \
4383 - self._exit_listeners is not None:
4384 -
4385 - # This prevents recursion, in case one of the
4386 - # exit handlers triggers this method again by
4387 - # calling wait(). Use a stack that gives
4388 - # removeExitListener() an opportunity to consume
4389 - # listeners from the stack, before they can get
4390 - # called below. This is necessary because a call
4391 - # to one exit listener may result in a call to
4392 - # removeExitListener() for another listener on
4393 - # the stack. That listener needs to be removed
4394 - # from the stack since it would be inconsistent
4395 - # to call it after it has been been passed into
4396 - # removeExitListener().
4397 - self._exit_listener_stack = self._exit_listeners
4398 - self._exit_listeners = None
4399 -
4400 - self._exit_listener_stack.reverse()
4401 - while self._exit_listener_stack:
4402 - self._exit_listener_stack.pop()(self)
4403 -
4404 -class AbstractPollTask(AsynchronousTask):
4405 -
4406 - __slots__ = ("scheduler",) + \
4407 - ("_registered",)
4408 -
4409 - _bufsize = 4096
4410 - _exceptional_events = PollConstants.POLLERR | PollConstants.POLLNVAL
4411 - _registered_events = PollConstants.POLLIN | PollConstants.POLLHUP | \
4412 - _exceptional_events
4413 -
4414 - def _unregister(self):
4415 - raise NotImplementedError(self)
4416 -
4417 - def _unregister_if_appropriate(self, event):
4418 - if self._registered:
4419 - if event & self._exceptional_events:
4420 - self._unregister()
4421 - self.cancel()
4422 - elif event & PollConstants.POLLHUP:
4423 - self._unregister()
4424 - self.wait()
4425 -
4426 -class PipeReader(AbstractPollTask):
4427 -
4428 - """
4429 - Reads output from one or more files and saves it in memory,
4430 - for retrieval via the getvalue() method. This is driven by
4431 - the scheduler's poll() loop, so it runs entirely within the
4432 - current process.
4433 - """
4434 -
4435 - __slots__ = ("input_files",) + \
4436 - ("_read_data", "_reg_ids")
4437 -
4438 - def _start(self):
4439 - self._reg_ids = set()
4440 - self._read_data = []
4441 - for k, f in self.input_files.iteritems():
4442 - fcntl.fcntl(f.fileno(), fcntl.F_SETFL,
4443 - fcntl.fcntl(f.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
4444 - self._reg_ids.add(self.scheduler.register(f.fileno(),
4445 - self._registered_events, self._output_handler))
4446 - self._registered = True
4447 -
4448 - def isAlive(self):
4449 - return self._registered
4450 -
4451 - def cancel(self):
4452 - if self.returncode is None:
4453 - self.returncode = 1
4454 - self.cancelled = True
4455 - self.wait()
4456 -
4457 - def _wait(self):
4458 - if self.returncode is not None:
4459 - return self.returncode
4460 -
4461 - if self._registered:
4462 - self.scheduler.schedule(self._reg_ids)
4463 - self._unregister()
4464 -
4465 - self.returncode = os.EX_OK
4466 - return self.returncode
4467 -
4468 - def getvalue(self):
4469 - """Retrieve the entire contents"""
4470 - if sys.hexversion >= 0x3000000:
4471 - return bytes().join(self._read_data)
4472 - return "".join(self._read_data)
4473 -
4474 - def close(self):
4475 - """Free the memory buffer."""
4476 - self._read_data = None
4477 -
4478 - def _output_handler(self, fd, event):
4479 -
4480 - if event & PollConstants.POLLIN:
4481 -
4482 - for f in self.input_files.itervalues():
4483 - if fd == f.fileno():
4484 - break
4485 -
4486 - buf = array.array('B')
4487 - try:
4488 - buf.fromfile(f, self._bufsize)
4489 - except EOFError:
4490 - pass
4491 -
4492 - if buf:
4493 - self._read_data.append(buf.tostring())
4494 - else:
4495 - self._unregister()
4496 - self.wait()
4497 -
4498 - self._unregister_if_appropriate(event)
4499 - return self._registered
4500 -
4501 - def _unregister(self):
4502 - """
4503 - Unregister from the scheduler and close open files.
4504 - """
4505 -
4506 - self._registered = False
4507 -
4508 - if self._reg_ids is not None:
4509 - for reg_id in self._reg_ids:
4510 - self.scheduler.unregister(reg_id)
4511 - self._reg_ids = None
4512 -
4513 - if self.input_files is not None:
4514 - for f in self.input_files.itervalues():
4515 - f.close()
4516 - self.input_files = None
4517 -
4518 -class CompositeTask(AsynchronousTask):
4519 -
4520 - __slots__ = ("scheduler",) + ("_current_task",)
4521 -
4522 - def isAlive(self):
4523 - return self._current_task is not None
4524 -
4525 - def cancel(self):
4526 - self.cancelled = True
4527 - if self._current_task is not None:
4528 - self._current_task.cancel()
4529 -
4530 - def _poll(self):
4531 - """
4532 - This does a loop calling self._current_task.poll()
4533 - repeatedly as long as the value of self._current_task
4534 - keeps changing. It calls poll() a maximum of one time
4535 - for a given self._current_task instance. This is useful
4536 - since calling poll() on a task can trigger advance to
4537 - the next task could eventually lead to the returncode
4538 - being set in cases when polling only a single task would
4539 - not have the same effect.
4540 - """
4541 -
4542 - prev = None
4543 - while True:
4544 - task = self._current_task
4545 - if task is None or task is prev:
4546 - # don't poll the same task more than once
4547 - break
4548 - task.poll()
4549 - prev = task
4550 -
4551 - return self.returncode
4552 -
4553 - def _wait(self):
4554 -
4555 - prev = None
4556 - while True:
4557 - task = self._current_task
4558 - if task is None:
4559 - # don't wait for the same task more than once
4560 - break
4561 - if task is prev:
4562 - # Before the task.wait() method returned, an exit
4563 - # listener should have set self._current_task to either
4564 - # a different task or None. Something is wrong.
4565 - raise AssertionError("self._current_task has not " + \
4566 - "changed since calling wait", self, task)
4567 - task.wait()
4568 - prev = task
4569 -
4570 - return self.returncode
4571 -
4572 - def _assert_current(self, task):
4573 - """
4574 - Raises an AssertionError if the given task is not the
4575 - same one as self._current_task. This can be useful
4576 - for detecting bugs.
4577 - """
4578 - if task is not self._current_task:
4579 - raise AssertionError("Unrecognized task: %s" % (task,))
4580 -
4581 - def _default_exit(self, task):
4582 - """
4583 - Calls _assert_current() on the given task and then sets the
4584 - composite returncode attribute if task.returncode != os.EX_OK.
4585 - If the task failed then self._current_task will be set to None.
4586 - Subclasses can use this as a generic task exit callback.
4587 -
4588 - @rtype: int
4589 - @returns: The task.returncode attribute.
4590 - """
4591 - self._assert_current(task)
4592 - if task.returncode != os.EX_OK:
4593 - self.returncode = task.returncode
4594 - self._current_task = None
4595 - return task.returncode
4596 -
4597 - def _final_exit(self, task):
4598 - """
4599 - Assumes that task is the final task of this composite task.
4600 - Calls _default_exit() and sets self.returncode to the task's
4601 - returncode and sets self._current_task to None.
4602 - """
4603 - self._default_exit(task)
4604 - self._current_task = None
4605 - self.returncode = task.returncode
4606 - return self.returncode
4607 -
4608 - def _default_final_exit(self, task):
4609 - """
4610 - This calls _final_exit() and then wait().
4611 -
4612 - Subclasses can use this as a generic final task exit callback.
4613 -
4614 - """
4615 - self._final_exit(task)
4616 - return self.wait()
4617 -
4618 - def _start_task(self, task, exit_handler):
4619 - """
4620 - Register exit handler for the given task, set it
4621 - as self._current_task, and call task.start().
4622 -
4623 - Subclasses can use this as a generic way to start
4624 - a task.
4625 -
4626 - """
4627 - task.addExitListener(exit_handler)
4628 - self._current_task = task
4629 - task.start()
4630 -
4631 -class TaskSequence(CompositeTask):
4632 - """
4633 - A collection of tasks that executes sequentially. Each task
4634 - must have a addExitListener() method that can be used as
4635 - a means to trigger movement from one task to the next.
4636 - """
4637 -
4638 - __slots__ = ("_task_queue",)
4639 -
4640 - def __init__(self, **kwargs):
4641 - AsynchronousTask.__init__(self, **kwargs)
4642 - self._task_queue = deque()
4643 -
4644 - def add(self, task):
4645 - self._task_queue.append(task)
4646 -
4647 - def _start(self):
4648 - self._start_next_task()
4649 -
4650 - def cancel(self):
4651 - self._task_queue.clear()
4652 - CompositeTask.cancel(self)
4653 -
4654 - def _start_next_task(self):
4655 - self._start_task(self._task_queue.popleft(),
4656 - self._task_exit_handler)
4657 -
4658 - def _task_exit_handler(self, task):
4659 - if self._default_exit(task) != os.EX_OK:
4660 - self.wait()
4661 - elif self._task_queue:
4662 - self._start_next_task()
4663 - else:
4664 - self._final_exit(task)
4665 - self.wait()
4666 -
4667 -class SubProcess(AbstractPollTask):
4668 -
4669 - __slots__ = ("pid",) + \
4670 - ("_files", "_reg_id")
4671 -
4672 - # A file descriptor is required for the scheduler to monitor changes from
4673 - # inside a poll() loop. When logging is not enabled, create a pipe just to
4674 - # serve this purpose alone.
4675 - _dummy_pipe_fd = 9
4676 -
4677 - def _poll(self):
4678 - if self.returncode is not None:
4679 - return self.returncode
4680 - if self.pid is None:
4681 - return self.returncode
4682 - if self._registered:
4683 - return self.returncode
4684 -
4685 - try:
4686 - retval = os.waitpid(self.pid, os.WNOHANG)
4687 - except OSError, e:
4688 - if e.errno != errno.ECHILD:
4689 - raise
4690 - del e
4691 - retval = (self.pid, 1)
4692 -
4693 - if retval == (0, 0):
4694 - return None
4695 - self._set_returncode(retval)
4696 - return self.returncode
4697 -
4698 - def cancel(self):
4699 - if self.isAlive():
4700 - try:
4701 - os.kill(self.pid, signal.SIGTERM)
4702 - except OSError, e:
4703 - if e.errno != errno.ESRCH:
4704 - raise
4705 - del e
4706 -
4707 - self.cancelled = True
4708 - if self.pid is not None:
4709 - self.wait()
4710 - return self.returncode
4711 -
4712 - def isAlive(self):
4713 - return self.pid is not None and \
4714 - self.returncode is None
4715 -
4716 - def _wait(self):
4717 -
4718 - if self.returncode is not None:
4719 - return self.returncode
4720 -
4721 - if self._registered:
4722 - self.scheduler.schedule(self._reg_id)
4723 - self._unregister()
4724 - if self.returncode is not None:
4725 - return self.returncode
4726 -
4727 - try:
4728 - wait_retval = os.waitpid(self.pid, 0)
4729 - except OSError, e:
4730 - if e.errno != errno.ECHILD:
4731 - raise
4732 - del e
4733 - self._set_returncode((self.pid, 1))
4734 - else:
4735 - self._set_returncode(wait_retval)
4736 -
4737 - return self.returncode
4738 -
4739 - def _unregister(self):
4740 - """
4741 - Unregister from the scheduler and close open files.
4742 - """
4743 -
4744 - self._registered = False
4745 -
4746 - if self._reg_id is not None:
4747 - self.scheduler.unregister(self._reg_id)
4748 - self._reg_id = None
4749 -
4750 - if self._files is not None:
4751 - for f in self._files.itervalues():
4752 - f.close()
4753 - self._files = None
4754 -
4755 - def _set_returncode(self, wait_retval):
4756 -
4757 - retval = wait_retval[1]
4758 -
4759 - if retval != os.EX_OK:
4760 - if retval & 0xff:
4761 - retval = (retval & 0xff) << 8
4762 - else:
4763 - retval = retval >> 8
4764 -
4765 - self.returncode = retval
4766 -
4767 -class SpawnProcess(SubProcess):
4768 -
4769 - """
4770 - Constructor keyword args are passed into portage.process.spawn().
4771 - The required "args" keyword argument will be passed as the first
4772 - spawn() argument.
4773 - """
4774 -
4775 - _spawn_kwarg_names = ("env", "opt_name", "fd_pipes",
4776 - "uid", "gid", "groups", "umask", "logfile",
4777 - "path_lookup", "pre_exec")
4778 -
4779 - __slots__ = ("args",) + \
4780 - _spawn_kwarg_names
4781 -
4782 - _file_names = ("log", "process", "stdout")
4783 - _files_dict = slot_dict_class(_file_names, prefix="")
4784 -
4785 - def _start(self):
4786 -
4787 - if self.cancelled:
4788 - return
4789 -
4790 - if self.fd_pipes is None:
4791 - self.fd_pipes = {}
4792 - fd_pipes = self.fd_pipes
4793 - fd_pipes.setdefault(0, sys.stdin.fileno())
4794 - fd_pipes.setdefault(1, sys.stdout.fileno())
4795 - fd_pipes.setdefault(2, sys.stderr.fileno())
4796 -
4797 - # flush any pending output
4798 - for fd in fd_pipes.itervalues():
4799 - if fd == sys.stdout.fileno():
4800 - sys.stdout.flush()
4801 - if fd == sys.stderr.fileno():
4802 - sys.stderr.flush()
4803 -
4804 - logfile = self.logfile
4805 - self._files = self._files_dict()
4806 - files = self._files
4807 -
4808 - master_fd, slave_fd = self._pipe(fd_pipes)
4809 - fcntl.fcntl(master_fd, fcntl.F_SETFL,
4810 - fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
4811 -
4812 - null_input = None
4813 - fd_pipes_orig = fd_pipes.copy()
4814 - if self.background:
4815 - # TODO: Use job control functions like tcsetpgrp() to control
4816 - # access to stdin. Until then, use /dev/null so that any
4817 - # attempts to read from stdin will immediately return EOF
4818 - # instead of blocking indefinitely.
4819 - null_input = open('/dev/null', 'rb')
4820 - fd_pipes[0] = null_input.fileno()
4821 - else:
4822 - fd_pipes[0] = fd_pipes_orig[0]
4823 -
4824 - files.process = os.fdopen(master_fd, 'rb')
4825 - if logfile is not None:
4826 -
4827 - fd_pipes[1] = slave_fd
4828 - fd_pipes[2] = slave_fd
4829 -
4830 - files.log = open(logfile, mode='ab')
4831 - portage.util.apply_secpass_permissions(logfile,
4832 - uid=portage.portage_uid, gid=portage.portage_gid,
4833 - mode=0660)
4834 -
4835 - if not self.background:
4836 - files.stdout = os.fdopen(os.dup(fd_pipes_orig[1]), 'wb')
4837 -
4838 - output_handler = self._output_handler
4839 -
4840 - else:
4841 -
4842 - # Create a dummy pipe so the scheduler can monitor
4843 - # the process from inside a poll() loop.
4844 - fd_pipes[self._dummy_pipe_fd] = slave_fd
4845 - if self.background:
4846 - fd_pipes[1] = slave_fd
4847 - fd_pipes[2] = slave_fd
4848 - output_handler = self._dummy_handler
4849 -
4850 - kwargs = {}
4851 - for k in self._spawn_kwarg_names:
4852 - v = getattr(self, k)
4853 - if v is not None:
4854 - kwargs[k] = v
4855 -
4856 - kwargs["fd_pipes"] = fd_pipes
4857 - kwargs["returnpid"] = True
4858 - kwargs.pop("logfile", None)
4859 -
4860 - self._reg_id = self.scheduler.register(files.process.fileno(),
4861 - self._registered_events, output_handler)
4862 - self._registered = True
4863 -
4864 - retval = self._spawn(self.args, **kwargs)
4865 -
4866 - os.close(slave_fd)
4867 - if null_input is not None:
4868 - null_input.close()
4869 -
4870 - if isinstance(retval, int):
4871 - # spawn failed
4872 - self._unregister()
4873 - self.returncode = retval
4874 - self.wait()
4875 - return
4876 -
4877 - self.pid = retval[0]
4878 - portage.process.spawned_pids.remove(self.pid)
4879 -
4880 - def _pipe(self, fd_pipes):
4881 - """
4882 - @type fd_pipes: dict
4883 - @param fd_pipes: pipes from which to copy terminal size if desired.
4884 - """
4885 - return os.pipe()
4886 -
4887 - def _spawn(self, args, **kwargs):
4888 - return portage.process.spawn(args, **kwargs)
4889 -
4890 - def _output_handler(self, fd, event):
4891 -
4892 - if event & PollConstants.POLLIN:
4893 -
4894 - files = self._files
4895 - buf = array.array('B')
4896 - try:
4897 - buf.fromfile(files.process, self._bufsize)
4898 - except EOFError:
4899 - pass
4900 -
4901 - if buf:
4902 - if not self.background:
4903 - write_successful = False
4904 - failures = 0
4905 - while True:
4906 - try:
4907 - if not write_successful:
4908 - buf.tofile(files.stdout)
4909 - write_successful = True
4910 - files.stdout.flush()
4911 - break
4912 - except IOError, e:
4913 - if e.errno != errno.EAGAIN:
4914 - raise
4915 - del e
4916 - failures += 1
4917 - if failures > 50:
4918 - # Avoid a potentially infinite loop. In
4919 - # most cases, the failure count is zero
4920 - # and it's unlikely to exceed 1.
4921 - raise
4922 -
4923 - # This means that a subprocess has put an inherited
4924 - # stdio file descriptor (typically stdin) into
4925 - # O_NONBLOCK mode. This is not acceptable (see bug
4926 - # #264435), so revert it. We need to use a loop
4927 - # here since there's a race condition due to
4928 - # parallel processes being able to change the
4929 - # flags on the inherited file descriptor.
4930 - # TODO: When possible, avoid having child processes
4931 - # inherit stdio file descriptors from portage
4932 - # (maybe it can't be avoided with
4933 - # PROPERTIES=interactive).
4934 - fcntl.fcntl(files.stdout.fileno(), fcntl.F_SETFL,
4935 - fcntl.fcntl(files.stdout.fileno(),
4936 - fcntl.F_GETFL) ^ os.O_NONBLOCK)
4937 -
4938 - buf.tofile(files.log)
4939 - files.log.flush()
4940 - else:
4941 - self._unregister()
4942 - self.wait()
4943 -
4944 - self._unregister_if_appropriate(event)
4945 - return self._registered
4946 -
4947 - def _dummy_handler(self, fd, event):
4948 - """
4949 - This method is mainly interested in detecting EOF, since
4950 - the only purpose of the pipe is to allow the scheduler to
4951 - monitor the process from inside a poll() loop.
4952 - """
4953 -
4954 - if event & PollConstants.POLLIN:
4955 -
4956 - buf = array.array('B')
4957 - try:
4958 - buf.fromfile(self._files.process, self._bufsize)
4959 - except EOFError:
4960 - pass
4961 -
4962 - if buf:
4963 - pass
4964 - else:
4965 - self._unregister()
4966 - self.wait()
4967 -
4968 - self._unregister_if_appropriate(event)
4969 - return self._registered
4970 -
4971 -class MiscFunctionsProcess(SpawnProcess):
4972 - """
4973 - Spawns misc-functions.sh with an existing ebuild environment.
4974 - """
4975 -
4976 - __slots__ = ("commands", "phase", "pkg", "settings")
4977 -
4978 - def _start(self):
4979 - settings = self.settings
4980 - settings.pop("EBUILD_PHASE", None)
4981 - portage_bin_path = settings["PORTAGE_BIN_PATH"]
4982 - misc_sh_binary = os.path.join(portage_bin_path,
4983 - os.path.basename(portage.const.MISC_SH_BINARY))
4984 -
4985 - self.args = [portage._shell_quote(misc_sh_binary)] + self.commands
4986 - self.logfile = settings.get("PORTAGE_LOG_FILE")
4987 -
4988 - portage._doebuild_exit_status_unlink(
4989 - settings.get("EBUILD_EXIT_STATUS_FILE"))
4990 -
4991 - SpawnProcess._start(self)
4992 -
4993 - def _spawn(self, args, **kwargs):
4994 - settings = self.settings
4995 - debug = settings.get("PORTAGE_DEBUG") == "1"
4996 - return portage.spawn(" ".join(args), settings,
4997 - debug=debug, **kwargs)
4998 -
4999 - def _set_returncode(self, wait_retval):
5000 - SpawnProcess._set_returncode(self, wait_retval)
5001 - self.returncode = portage._doebuild_exit_status_check_and_log(
5002 - self.settings, self.phase, self.returncode)
5003 -
5004 -class EbuildFetcher(SpawnProcess):
5005 -
5006 - __slots__ = ("config_pool", "fetchonly", "fetchall", "pkg", "prefetch") + \
5007 - ("_build_dir",)
5008 -
5009 - def _start(self):
5010 -
5011 - root_config = self.pkg.root_config
5012 - portdb = root_config.trees["porttree"].dbapi
5013 - ebuild_path = portdb.findname(self.pkg.cpv)
5014 - settings = self.config_pool.allocate()
5015 - settings.setcpv(self.pkg)
5016 -
5017 - # In prefetch mode, logging goes to emerge-fetch.log and the builddir
5018 - # should not be touched since otherwise it could interfere with
5019 - # another instance of the same cpv concurrently being built for a
5020 - # different $ROOT (currently, builds only cooperate with prefetchers
5021 - # that are spawned for the same $ROOT).
5022 - if not self.prefetch:
5023 - self._build_dir = EbuildBuildDir(pkg=self.pkg, settings=settings)
5024 - self._build_dir.lock()
5025 - self._build_dir.clean_log()
5026 - portage.prepare_build_dirs(self.pkg.root, self._build_dir.settings, 0)
5027 - if self.logfile is None:
5028 - self.logfile = settings.get("PORTAGE_LOG_FILE")
5029 -
5030 - phase = "fetch"
5031 - if self.fetchall:
5032 - phase = "fetchall"
5033 -
5034 - # If any incremental variables have been overridden
5035 - # via the environment, those values need to be passed
5036 - # along here so that they are correctly considered by
5037 - # the config instance in the subproccess.
5038 - fetch_env = os.environ.copy()
5039 -
5040 - nocolor = settings.get("NOCOLOR")
5041 - if nocolor is not None:
5042 - fetch_env["NOCOLOR"] = nocolor
5043 -
5044 - fetch_env["PORTAGE_NICENESS"] = "0"
5045 - if self.prefetch:
5046 - fetch_env["PORTAGE_PARALLEL_FETCHONLY"] = "1"
5047 -
5048 - ebuild_binary = os.path.join(
5049 - settings["PORTAGE_BIN_PATH"], "ebuild")
5050 -
5051 - fetch_args = [ebuild_binary, ebuild_path, phase]
5052 - debug = settings.get("PORTAGE_DEBUG") == "1"
5053 - if debug:
5054 - fetch_args.append("--debug")
5055 -
5056 - self.args = fetch_args
5057 - self.env = fetch_env
5058 - SpawnProcess._start(self)
5059 -
5060 - def _pipe(self, fd_pipes):
5061 - """When appropriate, use a pty so that fetcher progress bars,
5062 - like wget has, will work properly."""
5063 - if self.background or not sys.stdout.isatty():
5064 - # When the output only goes to a log file,
5065 - # there's no point in creating a pty.
5066 - return os.pipe()
5067 - stdout_pipe = fd_pipes.get(1)
5068 - got_pty, master_fd, slave_fd = \
5069 - portage._create_pty_or_pipe(copy_term_size=stdout_pipe)
5070 - return (master_fd, slave_fd)
5071 -
5072 - def _set_returncode(self, wait_retval):
5073 - SpawnProcess._set_returncode(self, wait_retval)
5074 - # Collect elog messages that might have been
5075 - # created by the pkg_nofetch phase.
5076 - if self._build_dir is not None:
5077 - # Skip elog messages for prefetch, in order to avoid duplicates.
5078 - if not self.prefetch and self.returncode != os.EX_OK:
5079 - elog_out = None
5080 - if self.logfile is not None:
5081 - if self.background:
5082 - elog_out = open(self.logfile, 'a')
5083 - msg = "Fetch failed for '%s'" % (self.pkg.cpv,)
5084 - if self.logfile is not None:
5085 - msg += ", Log file:"
5086 - eerror(msg, phase="unpack", key=self.pkg.cpv, out=elog_out)
5087 - if self.logfile is not None:
5088 - eerror(" '%s'" % (self.logfile,),
5089 - phase="unpack", key=self.pkg.cpv, out=elog_out)
5090 - if elog_out is not None:
5091 - elog_out.close()
5092 - if not self.prefetch:
5093 - portage.elog.elog_process(self.pkg.cpv, self._build_dir.settings)
5094 - features = self._build_dir.settings.features
5095 - if self.returncode == os.EX_OK:
5096 - self._build_dir.clean_log()
5097 - self._build_dir.unlock()
5098 - self.config_pool.deallocate(self._build_dir.settings)
5099 - self._build_dir = None
5100 -
5101 -class EbuildBuildDir(SlotObject):
5102 -
5103 - __slots__ = ("dir_path", "pkg", "settings",
5104 - "locked", "_catdir", "_lock_obj")
5105 -
5106 - def __init__(self, **kwargs):
5107 - SlotObject.__init__(self, **kwargs)
5108 - self.locked = False
5109 -
5110 - def lock(self):
5111 - """
5112 - This raises an AlreadyLocked exception if lock() is called
5113 - while a lock is already held. In order to avoid this, call
5114 - unlock() or check whether the "locked" attribute is True
5115 - or False before calling lock().
5116 - """
5117 - if self._lock_obj is not None:
5118 - raise self.AlreadyLocked((self._lock_obj,))
5119 -
5120 - dir_path = self.dir_path
5121 - if dir_path is None:
5122 - root_config = self.pkg.root_config
5123 - portdb = root_config.trees["porttree"].dbapi
5124 - ebuild_path = portdb.findname(self.pkg.cpv)
5125 - settings = self.settings
5126 - settings.setcpv(self.pkg)
5127 - debug = settings.get("PORTAGE_DEBUG") == "1"
5128 - use_cache = 1 # always true
5129 - portage.doebuild_environment(ebuild_path, "setup", root_config.root,
5130 - self.settings, debug, use_cache, portdb)
5131 - dir_path = self.settings["PORTAGE_BUILDDIR"]
5132 -
5133 - catdir = os.path.dirname(dir_path)
5134 - self._catdir = catdir
5135 -
5136 - portage.util.ensure_dirs(os.path.dirname(catdir),
5137 - gid=portage.portage_gid,
5138 - mode=070, mask=0)
5139 - catdir_lock = None
5140 - try:
5141 - catdir_lock = portage.locks.lockdir(catdir)
5142 - portage.util.ensure_dirs(catdir,
5143 - gid=portage.portage_gid,
5144 - mode=070, mask=0)
5145 - self._lock_obj = portage.locks.lockdir(dir_path)
5146 - finally:
5147 - self.locked = self._lock_obj is not None
5148 - if catdir_lock is not None:
5149 - portage.locks.unlockdir(catdir_lock)
5150 -
5151 - def clean_log(self):
5152 - """Discard existing log."""
5153 - settings = self.settings
5154 -
5155 - for x in ('.logid', 'temp/build.log'):
5156 - try:
5157 - os.unlink(os.path.join(settings["PORTAGE_BUILDDIR"], x))
5158 - except OSError:
5159 - pass
5160 -
5161 - def unlock(self):
5162 - if self._lock_obj is None:
5163 - return
5164 -
5165 - portage.locks.unlockdir(self._lock_obj)
5166 - self._lock_obj = None
5167 - self.locked = False
5168 -
5169 - catdir = self._catdir
5170 - catdir_lock = None
5171 - try:
5172 - catdir_lock = portage.locks.lockdir(catdir)
5173 - finally:
5174 - if catdir_lock:
5175 - try:
5176 - os.rmdir(catdir)
5177 - except OSError, e:
5178 - if e.errno not in (errno.ENOENT,
5179 - errno.ENOTEMPTY, errno.EEXIST):
5180 - raise
5181 - del e
5182 - portage.locks.unlockdir(catdir_lock)
5183 -
5184 - class AlreadyLocked(portage.exception.PortageException):
5185 - pass
5186 -
5187 -class EbuildBuild(CompositeTask):
5188 -
5189 - __slots__ = ("args_set", "config_pool", "find_blockers",
5190 - "ldpath_mtimes", "logger", "opts", "pkg", "pkg_count",
5191 - "prefetcher", "settings", "world_atom") + \
5192 - ("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree")
5193 -
5194 - def _start(self):
5195 -
5196 - logger = self.logger
5197 - opts = self.opts
5198 - pkg = self.pkg
5199 - settings = self.settings
5200 - world_atom = self.world_atom
5201 - root_config = pkg.root_config
5202 - tree = "porttree"
5203 - self._tree = tree
5204 - portdb = root_config.trees[tree].dbapi
5205 - settings.setcpv(pkg)
5206 - settings.configdict["pkg"]["EMERGE_FROM"] = pkg.type_name
5207 - ebuild_path = portdb.findname(self.pkg.cpv)
5208 - self._ebuild_path = ebuild_path
5209 -
5210 - prefetcher = self.prefetcher
5211 - if prefetcher is None:
5212 - pass
5213 - elif not prefetcher.isAlive():
5214 - prefetcher.cancel()
5215 - elif prefetcher.poll() is None:
5216 -
5217 - waiting_msg = "Fetching files " + \
5218 - "in the background. " + \
5219 - "To view fetch progress, run `tail -f " + \
5220 - "/var/log/emerge-fetch.log` in another " + \
5221 - "terminal."
5222 - msg_prefix = colorize("GOOD", " * ")
5223 - from textwrap import wrap
5224 - waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \
5225 - for line in wrap(waiting_msg, 65))
5226 - if not self.background:
5227 - writemsg(waiting_msg, noiselevel=-1)
5228 -
5229 - self._current_task = prefetcher
5230 - prefetcher.addExitListener(self._prefetch_exit)
5231 - return
5232 -
5233 - self._prefetch_exit(prefetcher)
5234 -
5235 - def _prefetch_exit(self, prefetcher):
5236 -
5237 - opts = self.opts
5238 - pkg = self.pkg
5239 - settings = self.settings
5240 -
5241 - if opts.fetchonly:
5242 - fetcher = EbuildFetchonly(
5243 - fetch_all=opts.fetch_all_uri,
5244 - pkg=pkg, pretend=opts.pretend,
5245 - settings=settings)
5246 - retval = fetcher.execute()
5247 - self.returncode = retval
5248 - self.wait()
5249 - return
5250 -
5251 - fetcher = EbuildFetcher(config_pool=self.config_pool,
5252 - fetchall=opts.fetch_all_uri,
5253 - fetchonly=opts.fetchonly,
5254 - background=self.background,
5255 - pkg=pkg, scheduler=self.scheduler)
5256 -
5257 - self._start_task(fetcher, self._fetch_exit)
5258 -
5259 - def _fetch_exit(self, fetcher):
5260 - opts = self.opts
5261 - pkg = self.pkg
5262 -
5263 - fetch_failed = False
5264 - if opts.fetchonly:
5265 - fetch_failed = self._final_exit(fetcher) != os.EX_OK
5266 - else:
5267 - fetch_failed = self._default_exit(fetcher) != os.EX_OK
5268 -
5269 - if fetch_failed and fetcher.logfile is not None and \
5270 - os.path.exists(fetcher.logfile):
5271 - self.settings["PORTAGE_LOG_FILE"] = fetcher.logfile
5272 -
5273 - if not fetch_failed and fetcher.logfile is not None:
5274 - # Fetch was successful, so remove the fetch log.
5275 - try:
5276 - os.unlink(fetcher.logfile)
5277 - except OSError:
5278 - pass
5279 -
5280 - if fetch_failed or opts.fetchonly:
5281 - self.wait()
5282 - return
5283 -
5284 - logger = self.logger
5285 - opts = self.opts
5286 - pkg_count = self.pkg_count
5287 - scheduler = self.scheduler
5288 - settings = self.settings
5289 - features = settings.features
5290 - ebuild_path = self._ebuild_path
5291 - system_set = pkg.root_config.sets["system"]
5292 -
5293 - self._build_dir = EbuildBuildDir(pkg=pkg, settings=settings)
5294 - self._build_dir.lock()
5295 -
5296 - # Cleaning is triggered before the setup
5297 - # phase, in portage.doebuild().
5298 - msg = " === (%s of %s) Cleaning (%s::%s)" % \
5299 - (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
5300 - short_msg = "emerge: (%s of %s) %s Clean" % \
5301 - (pkg_count.curval, pkg_count.maxval, pkg.cpv)
5302 - logger.log(msg, short_msg=short_msg)
5303 -
5304 - #buildsyspkg: Check if we need to _force_ binary package creation
5305 - self._issyspkg = "buildsyspkg" in features and \
5306 - system_set.findAtomForPackage(pkg) and \
5307 - not opts.buildpkg
5308 -
5309 - if opts.buildpkg or self._issyspkg:
5310 -
5311 - self._buildpkg = True
5312 -
5313 - msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
5314 - (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
5315 - short_msg = "emerge: (%s of %s) %s Compile" % \
5316 - (pkg_count.curval, pkg_count.maxval, pkg.cpv)
5317 - logger.log(msg, short_msg=short_msg)
5318 -
5319 - else:
5320 - msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \
5321 - (pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
5322 - short_msg = "emerge: (%s of %s) %s Compile" % \
5323 - (pkg_count.curval, pkg_count.maxval, pkg.cpv)
5324 - logger.log(msg, short_msg=short_msg)
5325 -
5326 - build = EbuildExecuter(background=self.background, pkg=pkg,
5327 - scheduler=scheduler, settings=settings)
5328 - self._start_task(build, self._build_exit)
5329 -
5330 - def _unlock_builddir(self):
5331 - portage.elog.elog_process(self.pkg.cpv, self.settings)
5332 - self._build_dir.unlock()
5333 -
5334 - def _build_exit(self, build):
5335 - if self._default_exit(build) != os.EX_OK:
5336 - self._unlock_builddir()
5337 - self.wait()
5338 - return
5339 -
5340 - opts = self.opts
5341 - buildpkg = self._buildpkg
5342 -
5343 - if not buildpkg:
5344 - self._final_exit(build)
5345 - self.wait()
5346 - return
5347 -
5348 - if self._issyspkg:
5349 - msg = ">>> This is a system package, " + \
5350 - "let's pack a rescue tarball.\n"
5351 -
5352 - log_path = self.settings.get("PORTAGE_LOG_FILE")
5353 - if log_path is not None:
5354 - log_file = open(log_path, 'a')
5355 - try:
5356 - log_file.write(msg)
5357 - finally:
5358 - log_file.close()
5359 -
5360 - if not self.background:
5361 - portage.writemsg_stdout(msg, noiselevel=-1)
5362 -
5363 - packager = EbuildBinpkg(background=self.background, pkg=self.pkg,
5364 - scheduler=self.scheduler, settings=self.settings)
5365 -
5366 - self._start_task(packager, self._buildpkg_exit)
5367 -
5368 - def _buildpkg_exit(self, packager):
5369 - """
5370 - Released build dir lock when there is a failure or
5371 - when in buildpkgonly mode. Otherwise, the lock will
5372 - be released when merge() is called.
5373 - """
5374 -
5375 - if self._default_exit(packager) != os.EX_OK:
5376 - self._unlock_builddir()
5377 - self.wait()
5378 - return
5379 -
5380 - if self.opts.buildpkgonly:
5381 - # Need to call "clean" phase for buildpkgonly mode
5382 - portage.elog.elog_process(self.pkg.cpv, self.settings)
5383 - phase = "clean"
5384 - clean_phase = EbuildPhase(background=self.background,
5385 - pkg=self.pkg, phase=phase,
5386 - scheduler=self.scheduler, settings=self.settings,
5387 - tree=self._tree)
5388 - self._start_task(clean_phase, self._clean_exit)
5389 - return
5390 -
5391 - # Continue holding the builddir lock until
5392 - # after the package has been installed.
5393 - self._current_task = None
5394 - self.returncode = packager.returncode
5395 - self.wait()
5396 -
5397 - def _clean_exit(self, clean_phase):
5398 - if self._final_exit(clean_phase) != os.EX_OK or \
5399 - self.opts.buildpkgonly:
5400 - self._unlock_builddir()
5401 - self.wait()
5402 -
5403 - def install(self):
5404 - """
5405 - Install the package and then clean up and release locks.
5406 - Only call this after the build has completed successfully
5407 - and neither fetchonly nor buildpkgonly mode are enabled.
5408 - """
5409 -
5410 - find_blockers = self.find_blockers
5411 - ldpath_mtimes = self.ldpath_mtimes
5412 - logger = self.logger
5413 - pkg = self.pkg
5414 - pkg_count = self.pkg_count
5415 - settings = self.settings
5416 - world_atom = self.world_atom
5417 - ebuild_path = self._ebuild_path
5418 - tree = self._tree
5419 -
5420 - merge = EbuildMerge(find_blockers=self.find_blockers,
5421 - ldpath_mtimes=ldpath_mtimes, logger=logger, pkg=pkg,
5422 - pkg_count=pkg_count, pkg_path=ebuild_path,
5423 - scheduler=self.scheduler,
5424 - settings=settings, tree=tree, world_atom=world_atom)
5425 -
5426 - msg = " === (%s of %s) Merging (%s::%s)" % \
5427 - (pkg_count.curval, pkg_count.maxval,
5428 - pkg.cpv, ebuild_path)
5429 - short_msg = "emerge: (%s of %s) %s Merge" % \
5430 - (pkg_count.curval, pkg_count.maxval, pkg.cpv)
5431 - logger.log(msg, short_msg=short_msg)
5432 -
5433 - try:
5434 - rval = merge.execute()
5435 - finally:
5436 - self._unlock_builddir()
5437 -
5438 - return rval
5439 -
5440 -class EbuildExecuter(CompositeTask):
5441 -
5442 - __slots__ = ("pkg", "scheduler", "settings") + ("_tree",)
5443 -
5444 - _phases = ("prepare", "configure", "compile", "test", "install")
5445 -
5446 - _live_eclasses = frozenset([
5447 - "bzr",
5448 - "cvs",
5449 - "darcs",
5450 - "git",
5451 - "mercurial",
5452 - "subversion"
5453 - ])
5454 -
5455 - def _start(self):
5456 - self._tree = "porttree"
5457 - pkg = self.pkg
5458 - phase = "clean"
5459 - clean_phase = EbuildPhase(background=self.background, pkg=pkg, phase=phase,
5460 - scheduler=self.scheduler, settings=self.settings, tree=self._tree)
5461 - self._start_task(clean_phase, self._clean_phase_exit)
5462 -
5463 - def _clean_phase_exit(self, clean_phase):
5464 -
5465 - if self._default_exit(clean_phase) != os.EX_OK:
5466 - self.wait()
5467 - return
5468 -
5469 - pkg = self.pkg
5470 - scheduler = self.scheduler
5471 - settings = self.settings
5472 - cleanup = 1
5473 -
5474 - # This initializes PORTAGE_LOG_FILE.
5475 - portage.prepare_build_dirs(pkg.root, settings, cleanup)
5476 -
5477 - setup_phase = EbuildPhase(background=self.background,
5478 - pkg=pkg, phase="setup", scheduler=scheduler,
5479 - settings=settings, tree=self._tree)
5480 -
5481 - setup_phase.addExitListener(self._setup_exit)
5482 - self._current_task = setup_phase
5483 - self.scheduler.scheduleSetup(setup_phase)
5484 -
5485 - def _setup_exit(self, setup_phase):
5486 -
5487 - if self._default_exit(setup_phase) != os.EX_OK:
5488 - self.wait()
5489 - return
5490 -
5491 - unpack_phase = EbuildPhase(background=self.background,
5492 - pkg=self.pkg, phase="unpack", scheduler=self.scheduler,
5493 - settings=self.settings, tree=self._tree)
5494 -
5495 - if self._live_eclasses.intersection(self.pkg.inherited):
5496 - # Serialize $DISTDIR access for live ebuilds since
5497 - # otherwise they can interfere with eachother.
5498 -
5499 - unpack_phase.addExitListener(self._unpack_exit)
5500 - self._current_task = unpack_phase
5501 - self.scheduler.scheduleUnpack(unpack_phase)
5502 -
5503 - else:
5504 - self._start_task(unpack_phase, self._unpack_exit)
5505 -
5506 - def _unpack_exit(self, unpack_phase):
5507 -
5508 - if self._default_exit(unpack_phase) != os.EX_OK:
5509 - self.wait()
5510 - return
5511 -
5512 - ebuild_phases = TaskSequence(scheduler=self.scheduler)
5513 -
5514 - pkg = self.pkg
5515 - phases = self._phases
5516 - eapi = pkg.metadata["EAPI"].replace("prefix", "").strip()
5517 - if eapi in ("0", "1"):
5518 - # skip src_prepare and src_configure
5519 - phases = phases[2:]
5520 -
5521 - for phase in phases:
5522 - ebuild_phases.add(EbuildPhase(background=self.background,
5523 - pkg=self.pkg, phase=phase, scheduler=self.scheduler,
5524 - settings=self.settings, tree=self._tree))
5525 -
5526 - self._start_task(ebuild_phases, self._default_final_exit)
5527 -
5528 -class EbuildMetadataPhase(SubProcess):
5529 -
5530 - """
5531 - Asynchronous interface for the ebuild "depend" phase which is
5532 - used to extract metadata from the ebuild.
5533 - """
5534 -
5535 - __slots__ = ("cpv", "ebuild_path", "fd_pipes", "metadata_callback",
5536 - "ebuild_mtime", "metadata", "portdb", "repo_path", "settings") + \
5537 - ("_raw_metadata",)
5538 -
5539 - _file_names = ("ebuild",)
5540 - _files_dict = slot_dict_class(_file_names, prefix="")
5541 - _metadata_fd = 9
5542 -
5543 - def _start(self):
5544 - settings = self.settings
5545 - settings.setcpv(self.cpv)
5546 - ebuild_path = self.ebuild_path
5547 -
5548 - eapi = None
5549 - if 'parse-eapi-glep-55' in settings.features:
5550 - pf, eapi = portage._split_ebuild_name_glep55(
5551 - os.path.basename(ebuild_path))
5552 - if eapi is None and \
5553 - 'parse-eapi-ebuild-head' in settings.features:
5554 - eapi = portage._parse_eapi_ebuild_head(codecs.open(ebuild_path,
5555 - mode='r', encoding='utf_8', errors='replace'))
5556 -
5557 - if eapi is not None:
5558 - if not portage.eapi_is_supported(eapi):
5559 - self.metadata_callback(self.cpv, self.ebuild_path,
5560 - self.repo_path, {'EAPI' : eapi}, self.ebuild_mtime)
5561 - self.returncode = os.EX_OK
5562 - self.wait()
5563 - return
5564 -
5565 - settings.configdict['pkg']['EAPI'] = eapi
5566 -
5567 - debug = settings.get("PORTAGE_DEBUG") == "1"
5568 - master_fd = None
5569 - slave_fd = None
5570 - fd_pipes = None
5571 - if self.fd_pipes is not None:
5572 - fd_pipes = self.fd_pipes.copy()
5573 - else:
5574 - fd_pipes = {}
5575 -
5576 - fd_pipes.setdefault(0, sys.stdin.fileno())
5577 - fd_pipes.setdefault(1, sys.stdout.fileno())
5578 - fd_pipes.setdefault(2, sys.stderr.fileno())
5579 -
5580 - # flush any pending output
5581 - for fd in fd_pipes.itervalues():
5582 - if fd == sys.stdout.fileno():
5583 - sys.stdout.flush()
5584 - if fd == sys.stderr.fileno():
5585 - sys.stderr.flush()
5586 -
5587 - fd_pipes_orig = fd_pipes.copy()
5588 - self._files = self._files_dict()
5589 - files = self._files
5590 -
5591 - master_fd, slave_fd = os.pipe()
5592 - fcntl.fcntl(master_fd, fcntl.F_SETFL,
5593 - fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
5594 -
5595 - fd_pipes[self._metadata_fd] = slave_fd
5596 -
5597 - self._raw_metadata = []
5598 - files.ebuild = os.fdopen(master_fd, 'r')
5599 - self._reg_id = self.scheduler.register(files.ebuild.fileno(),
5600 - self._registered_events, self._output_handler)
5601 - self._registered = True
5602 -
5603 - retval = portage.doebuild(ebuild_path, "depend",
5604 - settings["ROOT"], settings, debug,
5605 - mydbapi=self.portdb, tree="porttree",
5606 - fd_pipes=fd_pipes, returnpid=True)
5607 -
5608 - os.close(slave_fd)
5609 -
5610 - if isinstance(retval, int):
5611 - # doebuild failed before spawning
5612 - self._unregister()
5613 - self.returncode = retval
5614 - self.wait()
5615 - return
5616 -
5617 - self.pid = retval[0]
5618 - portage.process.spawned_pids.remove(self.pid)
5619 -
5620 - def _output_handler(self, fd, event):
5621 -
5622 - if event & PollConstants.POLLIN:
5623 - self._raw_metadata.append(self._files.ebuild.read())
5624 - if not self._raw_metadata[-1]:
5625 - self._unregister()
5626 - self.wait()
5627 -
5628 - self._unregister_if_appropriate(event)
5629 - return self._registered
5630 -
5631 - def _set_returncode(self, wait_retval):
5632 - SubProcess._set_returncode(self, wait_retval)
5633 - if self.returncode == os.EX_OK:
5634 - metadata_lines = "".join(self._raw_metadata).splitlines()
5635 - if len(portage.auxdbkeys) != len(metadata_lines):
5636 - # Don't trust bash's returncode if the
5637 - # number of lines is incorrect.
5638 - self.returncode = 1
5639 - else:
5640 - metadata = izip(portage.auxdbkeys, metadata_lines)
5641 - self.metadata = self.metadata_callback(self.cpv,
5642 - self.ebuild_path, self.repo_path, metadata,
5643 - self.ebuild_mtime)
5644 -
5645 -class EbuildProcess(SpawnProcess):
5646 -
5647 - __slots__ = ("phase", "pkg", "settings", "tree")
5648 -
5649 - def _start(self):
5650 - # Don't open the log file during the clean phase since the
5651 - # open file can result in an nfs lock on $T/build.log which
5652 - # prevents the clean phase from removing $T.
5653 - if self.phase not in ("clean", "cleanrm"):
5654 - self.logfile = self.settings.get("PORTAGE_LOG_FILE")
5655 - SpawnProcess._start(self)
5656 -
5657 - def _pipe(self, fd_pipes):
5658 - stdout_pipe = fd_pipes.get(1)
5659 - got_pty, master_fd, slave_fd = \
5660 - portage._create_pty_or_pipe(copy_term_size=stdout_pipe)
5661 - return (master_fd, slave_fd)
5662 -
5663 - def _spawn(self, args, **kwargs):
5664 -
5665 - root_config = self.pkg.root_config
5666 - tree = self.tree
5667 - mydbapi = root_config.trees[tree].dbapi
5668 - settings = self.settings
5669 - ebuild_path = settings["EBUILD"]
5670 - debug = settings.get("PORTAGE_DEBUG") == "1"
5671 -
5672 - rval = portage.doebuild(ebuild_path, self.phase,
5673 - root_config.root, settings, debug,
5674 - mydbapi=mydbapi, tree=tree, **kwargs)
5675 -
5676 - return rval
5677 -
5678 - def _set_returncode(self, wait_retval):
5679 - SpawnProcess._set_returncode(self, wait_retval)
5680 -
5681 - if self.phase not in ("clean", "cleanrm"):
5682 - self.returncode = portage._doebuild_exit_status_check_and_log(
5683 - self.settings, self.phase, self.returncode)
5684 -
5685 - if self.phase == "test" and self.returncode != os.EX_OK and \
5686 - "test-fail-continue" in self.settings.features:
5687 - self.returncode = os.EX_OK
5688 -
5689 - portage._post_phase_userpriv_perms(self.settings)
5690 -
5691 -class EbuildPhase(CompositeTask):
5692 -
5693 - __slots__ = ("background", "pkg", "phase",
5694 - "scheduler", "settings", "tree")
5695 -
5696 - _post_phase_cmds = portage._post_phase_cmds
5697 -
5698 - def _start(self):
5699 -
5700 - ebuild_process = EbuildProcess(background=self.background,
5701 - pkg=self.pkg, phase=self.phase, scheduler=self.scheduler,
5702 - settings=self.settings, tree=self.tree)
5703 -
5704 - self._start_task(ebuild_process, self._ebuild_exit)
5705 -
5706 - def _ebuild_exit(self, ebuild_process):
5707 -
5708 - if self.phase == "install":
5709 - out = None
5710 - log_path = self.settings.get("PORTAGE_LOG_FILE")
5711 - log_file = None
5712 - if self.background and log_path is not None:
5713 - log_file = open(log_path, 'a')
5714 - out = log_file
5715 - try:
5716 - portage._check_build_log(self.settings, out=out)
5717 - finally:
5718 - if log_file is not None:
5719 - log_file.close()
5720 -
5721 - if self._default_exit(ebuild_process) != os.EX_OK:
5722 - self.wait()
5723 - return
5724 -
5725 - settings = self.settings
5726 -
5727 - if self.phase == "install":
5728 - portage._post_src_install_chost_fix(settings)
5729 - portage._post_src_install_uid_fix(settings)
5730 -
5731 - post_phase_cmds = self._post_phase_cmds.get(self.phase)
5732 - if post_phase_cmds is not None:
5733 - post_phase = MiscFunctionsProcess(background=self.background,
5734 - commands=post_phase_cmds, phase=self.phase, pkg=self.pkg,
5735 - scheduler=self.scheduler, settings=settings)
5736 - self._start_task(post_phase, self._post_phase_exit)
5737 - return
5738 -
5739 - self.returncode = ebuild_process.returncode
5740 - self._current_task = None
5741 - self.wait()
5742 -
5743 - def _post_phase_exit(self, post_phase):
5744 - if self._final_exit(post_phase) != os.EX_OK:
5745 - writemsg("!!! post %s failed; exiting.\n" % self.phase,
5746 - noiselevel=-1)
5747 - self._current_task = None
5748 - self.wait()
5749 - return
5750 -
5751 -class EbuildBinpkg(EbuildProcess):
5752 - """
5753 - This assumes that src_install() has successfully completed.
5754 - """
5755 - __slots__ = ("_binpkg_tmpfile",)
5756 -
5757 - def _start(self):
5758 - self.phase = "package"
5759 - self.tree = "porttree"
5760 - pkg = self.pkg
5761 - root_config = pkg.root_config
5762 - portdb = root_config.trees["porttree"].dbapi
5763 - bintree = root_config.trees["bintree"]
5764 - ebuild_path = portdb.findname(self.pkg.cpv)
5765 - settings = self.settings
5766 - debug = settings.get("PORTAGE_DEBUG") == "1"
5767 -
5768 - bintree.prevent_collision(pkg.cpv)
5769 - binpkg_tmpfile = os.path.join(bintree.pkgdir,
5770 - pkg.cpv + ".tbz2." + str(os.getpid()))
5771 - self._binpkg_tmpfile = binpkg_tmpfile
5772 - settings["PORTAGE_BINPKG_TMPFILE"] = binpkg_tmpfile
5773 - settings.backup_changes("PORTAGE_BINPKG_TMPFILE")
5774 -
5775 - try:
5776 - EbuildProcess._start(self)
5777 - finally:
5778 - settings.pop("PORTAGE_BINPKG_TMPFILE", None)
5779 -
5780 - def _set_returncode(self, wait_retval):
5781 - EbuildProcess._set_returncode(self, wait_retval)
5782 -
5783 - pkg = self.pkg
5784 - bintree = pkg.root_config.trees["bintree"]
5785 - binpkg_tmpfile = self._binpkg_tmpfile
5786 - if self.returncode == os.EX_OK:
5787 - bintree.inject(pkg.cpv, filename=binpkg_tmpfile)
5788 -
5789 -class EbuildMerge(SlotObject):
5790 -
5791 - __slots__ = ("find_blockers", "logger", "ldpath_mtimes",
5792 - "pkg", "pkg_count", "pkg_path", "pretend",
5793 - "scheduler", "settings", "tree", "world_atom")
5794 -
5795 - def execute(self):
5796 - root_config = self.pkg.root_config
5797 - settings = self.settings
5798 - retval = portage.merge(settings["CATEGORY"],
5799 - settings["PF"], settings["D"],
5800 - os.path.join(settings["PORTAGE_BUILDDIR"],
5801 - "build-info"), root_config.root, settings,
5802 - myebuild=settings["EBUILD"],
5803 - mytree=self.tree, mydbapi=root_config.trees[self.tree].dbapi,
5804 - vartree=root_config.trees["vartree"],
5805 - prev_mtimes=self.ldpath_mtimes,
5806 - scheduler=self.scheduler,
5807 - blockers=self.find_blockers)
5808 -
5809 - if retval == os.EX_OK:
5810 - self.world_atom(self.pkg)
5811 - self._log_success()
5812 -
5813 - return retval
5814 -
5815 - def _log_success(self):
5816 - pkg = self.pkg
5817 - pkg_count = self.pkg_count
5818 - pkg_path = self.pkg_path
5819 - logger = self.logger
5820 - if "noclean" not in self.settings.features:
5821 - short_msg = "emerge: (%s of %s) %s Clean Post" % \
5822 - (pkg_count.curval, pkg_count.maxval, pkg.cpv)
5823 - logger.log((" === (%s of %s) " + \
5824 - "Post-Build Cleaning (%s::%s)") % \
5825 - (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path),
5826 - short_msg=short_msg)
5827 - logger.log(" ::: completed emerge (%s of %s) %s to %s" % \
5828 - (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg.root))
5829 -
5830 class PackageUninstall(AsynchronousTask):
5831
5832 __slots__ = ("ldpath_mtimes", "opts", "pkg", "scheduler", "settings")
5833 @@ -3441,534 +1501,6 @@
5834 finally:
5835 f.close()
5836
5837 -class Binpkg(CompositeTask):
5838 -
5839 - __slots__ = ("find_blockers",
5840 - "ldpath_mtimes", "logger", "opts",
5841 - "pkg", "pkg_count", "prefetcher", "settings", "world_atom") + \
5842 - ("_bintree", "_build_dir", "_ebuild_path", "_fetched_pkg",
5843 - "_image_dir", "_infloc", "_pkg_path", "_tree", "_verify")
5844 -
5845 - def _writemsg_level(self, msg, level=0, noiselevel=0):
5846 -
5847 - if not self.background:
5848 - portage.util.writemsg_level(msg,
5849 - level=level, noiselevel=noiselevel)
5850 -
5851 - log_path = self.settings.get("PORTAGE_LOG_FILE")
5852 - if log_path is not None:
5853 - f = open(log_path, 'a')
5854 - try:
5855 - f.write(msg)
5856 - finally:
5857 - f.close()
5858 -
5859 - def _start(self):
5860 -
5861 - pkg = self.pkg
5862 - settings = self.settings
5863 - settings.setcpv(pkg)
5864 - self._tree = "bintree"
5865 - self._bintree = self.pkg.root_config.trees[self._tree]
5866 - self._verify = not self.opts.pretend
5867 -
5868 - dir_path = os.path.join(settings["PORTAGE_TMPDIR"],
5869 - "portage", pkg.category, pkg.pf)
5870 - self._build_dir = EbuildBuildDir(dir_path=dir_path,
5871 - pkg=pkg, settings=settings)
5872 - self._image_dir = os.path.join(dir_path, "image")
5873 - self._infloc = os.path.join(dir_path, "build-info")
5874 - self._ebuild_path = os.path.join(self._infloc, pkg.pf + ".ebuild")
5875 - settings["EBUILD"] = self._ebuild_path
5876 - debug = settings.get("PORTAGE_DEBUG") == "1"
5877 - portage.doebuild_environment(self._ebuild_path, "setup",
5878 - settings["ROOT"], settings, debug, 1, self._bintree.dbapi)
5879 - settings.configdict["pkg"]["EMERGE_FROM"] = pkg.type_name
5880 -
5881 - # The prefetcher has already completed or it
5882 - # could be running now. If it's running now,
5883 - # wait for it to complete since it holds
5884 - # a lock on the file being fetched. The
5885 - # portage.locks functions are only designed
5886 - # to work between separate processes. Since
5887 - # the lock is held by the current process,
5888 - # use the scheduler and fetcher methods to
5889 - # synchronize with the fetcher.
5890 - prefetcher = self.prefetcher
5891 - if prefetcher is None:
5892 - pass
5893 - elif not prefetcher.isAlive():
5894 - prefetcher.cancel()
5895 - elif prefetcher.poll() is None:
5896 -
5897 - waiting_msg = ("Fetching '%s' " + \
5898 - "in the background. " + \
5899 - "To view fetch progress, run `tail -f " + \
5900 - "/var/log/emerge-fetch.log` in another " + \
5901 - "terminal.") % prefetcher.pkg_path
5902 - msg_prefix = colorize("GOOD", " * ")
5903 - from textwrap import wrap
5904 - waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \
5905 - for line in wrap(waiting_msg, 65))
5906 - if not self.background:
5907 - writemsg(waiting_msg, noiselevel=-1)
5908 -
5909 - self._current_task = prefetcher
5910 - prefetcher.addExitListener(self._prefetch_exit)
5911 - return
5912 -
5913 - self._prefetch_exit(prefetcher)
5914 -
5915 - def _prefetch_exit(self, prefetcher):
5916 -
5917 - pkg = self.pkg
5918 - pkg_count = self.pkg_count
5919 - if not (self.opts.pretend or self.opts.fetchonly):
5920 - self._build_dir.lock()
5921 - # If necessary, discard old log so that we don't
5922 - # append to it.
5923 - self._build_dir.clean_log()
5924 - # Initialze PORTAGE_LOG_FILE.
5925 - portage.prepare_build_dirs(self.settings["ROOT"], self.settings, 1)
5926 - fetcher = BinpkgFetcher(background=self.background,
5927 - logfile=self.settings.get("PORTAGE_LOG_FILE"), pkg=self.pkg,
5928 - pretend=self.opts.pretend, scheduler=self.scheduler)
5929 - pkg_path = fetcher.pkg_path
5930 - self._pkg_path = pkg_path
5931 -
5932 - if self.opts.getbinpkg and self._bintree.isremote(pkg.cpv):
5933 -
5934 - msg = " --- (%s of %s) Fetching Binary (%s::%s)" %\
5935 - (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path)
5936 - short_msg = "emerge: (%s of %s) %s Fetch" % \
5937 - (pkg_count.curval, pkg_count.maxval, pkg.cpv)
5938 - self.logger.log(msg, short_msg=short_msg)
5939 - self._start_task(fetcher, self._fetcher_exit)
5940 - return
5941 -
5942 - self._fetcher_exit(fetcher)
5943 -
5944 - def _fetcher_exit(self, fetcher):
5945 -
5946 - # The fetcher only has a returncode when
5947 - # --getbinpkg is enabled.
5948 - if fetcher.returncode is not None:
5949 - self._fetched_pkg = True
5950 - if self._default_exit(fetcher) != os.EX_OK:
5951 - self._unlock_builddir()
5952 - self.wait()
5953 - return
5954 -
5955 - if self.opts.pretend:
5956 - self._current_task = None
5957 - self.returncode = os.EX_OK
5958 - self.wait()
5959 - return
5960 -
5961 - verifier = None
5962 - if self._verify:
5963 - logfile = None
5964 - if self.background:
5965 - logfile = self.settings.get("PORTAGE_LOG_FILE")
5966 - verifier = BinpkgVerifier(background=self.background,
5967 - logfile=logfile, pkg=self.pkg)
5968 - self._start_task(verifier, self._verifier_exit)
5969 - return
5970 -
5971 - self._verifier_exit(verifier)
5972 -
5973 - def _verifier_exit(self, verifier):
5974 - if verifier is not None and \
5975 - self._default_exit(verifier) != os.EX_OK:
5976 - self._unlock_builddir()
5977 - self.wait()
5978 - return
5979 -
5980 - logger = self.logger
5981 - pkg = self.pkg
5982 - pkg_count = self.pkg_count
5983 - pkg_path = self._pkg_path
5984 -
5985 - if self._fetched_pkg:
5986 - self._bintree.inject(pkg.cpv, filename=pkg_path)
5987 -
5988 - if self.opts.fetchonly:
5989 - self._current_task = None
5990 - self.returncode = os.EX_OK
5991 - self.wait()
5992 - return
5993 -
5994 - msg = " === (%s of %s) Merging Binary (%s::%s)" % \
5995 - (pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path)
5996 - short_msg = "emerge: (%s of %s) %s Merge Binary" % \
5997 - (pkg_count.curval, pkg_count.maxval, pkg.cpv)
5998 - logger.log(msg, short_msg=short_msg)
5999 -
6000 - phase = "clean"
6001 - settings = self.settings
6002 - ebuild_phase = EbuildPhase(background=self.background,
6003 - pkg=pkg, phase=phase, scheduler=self.scheduler,
6004 - settings=settings, tree=self._tree)
6005 -
6006 - self._start_task(ebuild_phase, self._clean_exit)
6007 -
6008 - def _clean_exit(self, clean_phase):
6009 - if self._default_exit(clean_phase) != os.EX_OK:
6010 - self._unlock_builddir()
6011 - self.wait()
6012 - return
6013 -
6014 - dir_path = self._build_dir.dir_path
6015 -
6016 - infloc = self._infloc
6017 - pkg = self.pkg
6018 - pkg_path = self._pkg_path
6019 -
6020 - dir_mode = 0755
6021 - for mydir in (dir_path, self._image_dir, infloc):
6022 - portage.util.ensure_dirs(mydir, uid=portage.data.portage_uid,
6023 - gid=portage.data.portage_gid, mode=dir_mode)
6024 -
6025 - # This initializes PORTAGE_LOG_FILE.
6026 - portage.prepare_build_dirs(self.settings["ROOT"], self.settings, 1)
6027 - self._writemsg_level(">>> Extracting info\n")
6028 -
6029 - pkg_xpak = portage.xpak.tbz2(self._pkg_path)
6030 - check_missing_metadata = ("CATEGORY", "PF")
6031 - missing_metadata = set()
6032 - for k in check_missing_metadata:
6033 - v = pkg_xpak.getfile(k)
6034 - if not v:
6035 - missing_metadata.add(k)
6036 -
6037 - pkg_xpak.unpackinfo(infloc)
6038 - for k in missing_metadata:
6039 - if k == "CATEGORY":
6040 - v = pkg.category
6041 - elif k == "PF":
6042 - v = pkg.pf
6043 - else:
6044 - continue
6045 -
6046 - f = open(os.path.join(infloc, k), 'wb')
6047 - try:
6048 - f.write(v + "\n")
6049 - finally:
6050 - f.close()
6051 -
6052 - # Store the md5sum in the vdb.
6053 - f = open(os.path.join(infloc, "BINPKGMD5"), "w")
6054 - try:
6055 - f.write(str(portage.checksum.perform_md5(pkg_path)) + "\n")
6056 - finally:
6057 - f.close()
6058 -
6059 - # This gives bashrc users an opportunity to do various things
6060 - # such as remove binary packages after they're installed.
6061 - settings = self.settings
6062 - settings.setcpv(self.pkg)
6063 - settings["PORTAGE_BINPKG_FILE"] = pkg_path
6064 - settings.backup_changes("PORTAGE_BINPKG_FILE")
6065 -
6066 - phase = "setup"
6067 - setup_phase = EbuildPhase(background=self.background,
6068 - pkg=self.pkg, phase=phase, scheduler=self.scheduler,
6069 - settings=settings, tree=self._tree)
6070 -
6071 - setup_phase.addExitListener(self._setup_exit)
6072 - self._current_task = setup_phase
6073 - self.scheduler.scheduleSetup(setup_phase)
6074 -
6075 - def _setup_exit(self, setup_phase):
6076 - if self._default_exit(setup_phase) != os.EX_OK:
6077 - self._unlock_builddir()
6078 - self.wait()
6079 - return
6080 -
6081 - extractor = BinpkgExtractorAsync(background=self.background,
6082 - image_dir=self._image_dir,
6083 - pkg=self.pkg, pkg_path=self._pkg_path, scheduler=self.scheduler)
6084 - self._writemsg_level(">>> Extracting %s\n" % self.pkg.cpv)
6085 - self._start_task(extractor, self._extractor_exit)
6086 -
6087 - def _extractor_exit(self, extractor):
6088 - if self._final_exit(extractor) != os.EX_OK:
6089 - self._unlock_builddir()
6090 - writemsg("!!! Error Extracting '%s'\n" % self._pkg_path,
6091 - noiselevel=-1)
6092 - self.wait()
6093 -
6094 - def _unlock_builddir(self):
6095 - if self.opts.pretend or self.opts.fetchonly:
6096 - return
6097 - portage.elog.elog_process(self.pkg.cpv, self.settings)
6098 - self._build_dir.unlock()
6099 -
6100 - def install(self):
6101 -
6102 - # This gives bashrc users an opportunity to do various things
6103 - # such as remove binary packages after they're installed.
6104 - settings = self.settings
6105 - settings["PORTAGE_BINPKG_FILE"] = self._pkg_path
6106 - settings.backup_changes("PORTAGE_BINPKG_FILE")
6107 -
6108 - merge = EbuildMerge(find_blockers=self.find_blockers,
6109 - ldpath_mtimes=self.ldpath_mtimes, logger=self.logger,
6110 - pkg=self.pkg, pkg_count=self.pkg_count,
6111 - pkg_path=self._pkg_path, scheduler=self.scheduler,
6112 - settings=settings, tree=self._tree, world_atom=self.world_atom)
6113 -
6114 - try:
6115 - retval = merge.execute()
6116 - finally:
6117 - settings.pop("PORTAGE_BINPKG_FILE", None)
6118 - self._unlock_builddir()
6119 - return retval
6120 -
6121 -class BinpkgFetcher(SpawnProcess):
6122 -
6123 - __slots__ = ("pkg", "pretend",
6124 - "locked", "pkg_path", "_lock_obj")
6125 -
6126 - def __init__(self, **kwargs):
6127 - SpawnProcess.__init__(self, **kwargs)
6128 - pkg = self.pkg
6129 - self.pkg_path = pkg.root_config.trees["bintree"].getname(pkg.cpv)
6130 -
6131 - def _start(self):
6132 -
6133 - if self.cancelled:
6134 - return
6135 -
6136 - pkg = self.pkg
6137 - pretend = self.pretend
6138 - bintree = pkg.root_config.trees["bintree"]
6139 - settings = bintree.settings
6140 - use_locks = "distlocks" in settings.features
6141 - pkg_path = self.pkg_path
6142 -
6143 - if not pretend:
6144 - portage.util.ensure_dirs(os.path.dirname(pkg_path))
6145 - if use_locks:
6146 - self.lock()
6147 - exists = os.path.exists(pkg_path)
6148 - resume = exists and os.path.basename(pkg_path) in bintree.invalids
6149 - if not (pretend or resume):
6150 - # Remove existing file or broken symlink.
6151 - try:
6152 - os.unlink(pkg_path)
6153 - except OSError:
6154 - pass
6155 -
6156 - # urljoin doesn't work correctly with
6157 - # unrecognized protocols like sftp
6158 - if bintree._remote_has_index:
6159 - rel_uri = bintree._remotepkgs[pkg.cpv].get("PATH")
6160 - if not rel_uri:
6161 - rel_uri = pkg.cpv + ".tbz2"
6162 - uri = bintree._remote_base_uri.rstrip("/") + \
6163 - "/" + rel_uri.lstrip("/")
6164 - else:
6165 - uri = settings["PORTAGE_BINHOST"].rstrip("/") + \
6166 - "/" + pkg.pf + ".tbz2"
6167 -
6168 - if pretend:
6169 - portage.writemsg_stdout("\n%s\n" % uri, noiselevel=-1)
6170 - self.returncode = os.EX_OK
6171 - self.wait()
6172 - return
6173 -
6174 - protocol = urlparse.urlparse(uri)[0]
6175 - fcmd_prefix = "FETCHCOMMAND"
6176 - if resume:
6177 - fcmd_prefix = "RESUMECOMMAND"
6178 - fcmd = settings.get(fcmd_prefix + "_" + protocol.upper())
6179 - if not fcmd:
6180 - fcmd = settings.get(fcmd_prefix)
6181 -
6182 - fcmd_vars = {
6183 - "DISTDIR" : os.path.dirname(pkg_path),
6184 - "URI" : uri,
6185 - "FILE" : os.path.basename(pkg_path)
6186 - }
6187 -
6188 - fetch_env = dict(settings.iteritems())
6189 - fetch_args = [portage.util.varexpand(x, mydict=fcmd_vars) \
6190 - for x in shlex.split(fcmd)]
6191 -
6192 - if self.fd_pipes is None:
6193 - self.fd_pipes = {}
6194 - fd_pipes = self.fd_pipes
6195 -
6196 - # Redirect all output to stdout since some fetchers like
6197 - # wget pollute stderr (if portage detects a problem then it
6198 - # can send it's own message to stderr).
6199 - fd_pipes.setdefault(0, sys.stdin.fileno())
6200 - fd_pipes.setdefault(1, sys.stdout.fileno())
6201 - fd_pipes.setdefault(2, sys.stdout.fileno())
6202 -
6203 - self.args = fetch_args
6204 - self.env = fetch_env
6205 - SpawnProcess._start(self)
6206 -
6207 - def _set_returncode(self, wait_retval):
6208 - SpawnProcess._set_returncode(self, wait_retval)
6209 - if self.returncode == os.EX_OK:
6210 - # If possible, update the mtime to match the remote package if
6211 - # the fetcher didn't already do it automatically.
6212 - bintree = self.pkg.root_config.trees["bintree"]
6213 - if bintree._remote_has_index:
6214 - remote_mtime = bintree._remotepkgs[self.pkg.cpv].get("MTIME")
6215 - if remote_mtime is not None:
6216 - try:
6217 - remote_mtime = long(remote_mtime)
6218 - except ValueError:
6219 - pass
6220 - else:
6221 - try:
6222 - local_mtime = long(os.stat(self.pkg_path).st_mtime)
6223 - except OSError:
6224 - pass
6225 - else:
6226 - if remote_mtime != local_mtime:
6227 - try:
6228 - os.utime(self.pkg_path,
6229 - (remote_mtime, remote_mtime))
6230 - except OSError:
6231 - pass
6232 -
6233 - if self.locked:
6234 - self.unlock()
6235 -
6236 - def lock(self):
6237 - """
6238 - This raises an AlreadyLocked exception if lock() is called
6239 - while a lock is already held. In order to avoid this, call
6240 - unlock() or check whether the "locked" attribute is True
6241 - or False before calling lock().
6242 - """
6243 - if self._lock_obj is not None:
6244 - raise self.AlreadyLocked((self._lock_obj,))
6245 -
6246 - self._lock_obj = portage.locks.lockfile(
6247 - self.pkg_path, wantnewlockfile=1)
6248 - self.locked = True
6249 -
6250 - class AlreadyLocked(portage.exception.PortageException):
6251 - pass
6252 -
6253 - def unlock(self):
6254 - if self._lock_obj is None:
6255 - return
6256 - portage.locks.unlockfile(self._lock_obj)
6257 - self._lock_obj = None
6258 - self.locked = False
6259 -
6260 -class BinpkgVerifier(AsynchronousTask):
6261 - __slots__ = ("logfile", "pkg",)
6262 -
6263 - def _start(self):
6264 - """
6265 - Note: Unlike a normal AsynchronousTask.start() method,
6266 - this one does all work is synchronously. The returncode
6267 - attribute will be set before it returns.
6268 - """
6269 -
6270 - pkg = self.pkg
6271 - root_config = pkg.root_config
6272 - bintree = root_config.trees["bintree"]
6273 - rval = os.EX_OK
6274 - stdout_orig = sys.stdout
6275 - stderr_orig = sys.stderr
6276 - log_file = None
6277 - if self.background and self.logfile is not None:
6278 - log_file = open(self.logfile, 'a')
6279 - try:
6280 - if log_file is not None:
6281 - sys.stdout = log_file
6282 - sys.stderr = log_file
6283 - try:
6284 - bintree.digestCheck(pkg)
6285 - except portage.exception.FileNotFound:
6286 - writemsg("!!! Fetching Binary failed " + \
6287 - "for '%s'\n" % pkg.cpv, noiselevel=-1)
6288 - rval = 1
6289 - except portage.exception.DigestException, e:
6290 - writemsg("\n!!! Digest verification failed:\n",
6291 - noiselevel=-1)
6292 - writemsg("!!! %s\n" % e.value[0],
6293 - noiselevel=-1)
6294 - writemsg("!!! Reason: %s\n" % e.value[1],
6295 - noiselevel=-1)
6296 - writemsg("!!! Got: %s\n" % e.value[2],
6297 - noiselevel=-1)
6298 - writemsg("!!! Expected: %s\n" % e.value[3],
6299 - noiselevel=-1)
6300 - rval = 1
6301 - if rval != os.EX_OK:
6302 - pkg_path = bintree.getname(pkg.cpv)
6303 - head, tail = os.path.split(pkg_path)
6304 - temp_filename = portage._checksum_failure_temp_file(head, tail)
6305 - writemsg("File renamed to '%s'\n" % (temp_filename,),
6306 - noiselevel=-1)
6307 - finally:
6308 - sys.stdout = stdout_orig
6309 - sys.stderr = stderr_orig
6310 - if log_file is not None:
6311 - log_file.close()
6312 -
6313 - self.returncode = rval
6314 - self.wait()
6315 -
6316 -class BinpkgPrefetcher(CompositeTask):
6317 -
6318 - __slots__ = ("pkg",) + \
6319 - ("pkg_path", "_bintree",)
6320 -
6321 - def _start(self):
6322 - self._bintree = self.pkg.root_config.trees["bintree"]
6323 - fetcher = BinpkgFetcher(background=self.background,
6324 - logfile=self.scheduler.fetch.log_file, pkg=self.pkg,
6325 - scheduler=self.scheduler)
6326 - self.pkg_path = fetcher.pkg_path
6327 - self._start_task(fetcher, self._fetcher_exit)
6328 -
6329 - def _fetcher_exit(self, fetcher):
6330 -
6331 - if self._default_exit(fetcher) != os.EX_OK:
6332 - self.wait()
6333 - return
6334 -
6335 - verifier = BinpkgVerifier(background=self.background,
6336 - logfile=self.scheduler.fetch.log_file, pkg=self.pkg)
6337 - self._start_task(verifier, self._verifier_exit)
6338 -
6339 - def _verifier_exit(self, verifier):
6340 - if self._default_exit(verifier) != os.EX_OK:
6341 - self.wait()
6342 - return
6343 -
6344 - self._bintree.inject(self.pkg.cpv, filename=self.pkg_path)
6345 -
6346 - self._current_task = None
6347 - self.returncode = os.EX_OK
6348 - self.wait()
6349 -
6350 -class BinpkgExtractorAsync(SpawnProcess):
6351 -
6352 - __slots__ = ("image_dir", "pkg", "pkg_path")
6353 -
6354 - _shell_binary = portage.const.BASH_BINARY
6355 -
6356 - def _start(self):
6357 - self.args = [self._shell_binary, "-c",
6358 - "bzip2 -dqc -- %s | tar -xp -C %s -f -" % \
6359 - (portage._shell_quote(self.pkg_path),
6360 - portage._shell_quote(self.image_dir))]
6361 -
6362 - self.env = self.pkg.root_config.settings.environ()
6363 - SpawnProcess._start(self)
6364 -
6365 class MergeListItem(CompositeTask):
6366
6367 """
6368 @@ -4106,247 +1638,6 @@
6369 retval = self._install_task.install()
6370 return retval
6371
6372 -class PackageMerge(AsynchronousTask):
6373 - """
6374 - TODO: Implement asynchronous merge so that the scheduler can
6375 - run while a merge is executing.
6376 - """
6377 -
6378 - __slots__ = ("merge",)
6379 -
6380 - def _start(self):
6381 -
6382 - pkg = self.merge.pkg
6383 - pkg_count = self.merge.pkg_count
6384 -
6385 - if pkg.installed:
6386 - action_desc = "Uninstalling"
6387 - preposition = "from"
6388 - counter_str = ""
6389 - else:
6390 - action_desc = "Installing"
6391 - preposition = "to"
6392 - counter_str = "(%s of %s) " % \
6393 - (colorize("MERGE_LIST_PROGRESS", str(pkg_count.curval)),
6394 - colorize("MERGE_LIST_PROGRESS", str(pkg_count.maxval)))
6395 -
6396 - msg = "%s %s%s" % \
6397 - (action_desc,
6398 - counter_str,
6399 - colorize("GOOD", pkg.cpv))
6400 -
6401 - if pkg.root != "/":
6402 - msg += " %s %s" % (preposition, pkg.root)
6403 -
6404 - if not self.merge.build_opts.fetchonly and \
6405 - not self.merge.build_opts.pretend and \
6406 - not self.merge.build_opts.buildpkgonly:
6407 - self.merge.statusMessage(msg)
6408 -
6409 - self.returncode = self.merge.merge()
6410 - self.wait()
6411 -
6412 -class DependencyArg(object):
6413 - def __init__(self, arg=None, root_config=None):
6414 - self.arg = arg
6415 - self.root_config = root_config
6416 -
6417 - def __str__(self):
6418 - return str(self.arg)
6419 -
6420 -class AtomArg(DependencyArg):
6421 - def __init__(self, atom=None, **kwargs):
6422 - DependencyArg.__init__(self, **kwargs)
6423 - self.atom = atom
6424 - if not isinstance(self.atom, portage.dep.Atom):
6425 - self.atom = portage.dep.Atom(self.atom)
6426 - self.set = (self.atom, )
6427 -
6428 -class PackageArg(DependencyArg):
6429 - def __init__(self, package=None, **kwargs):
6430 - DependencyArg.__init__(self, **kwargs)
6431 - self.package = package
6432 - self.atom = portage.dep.Atom("=" + package.cpv)
6433 - self.set = (self.atom, )
6434 -
6435 -class SetArg(DependencyArg):
6436 - def __init__(self, set=None, **kwargs):
6437 - DependencyArg.__init__(self, **kwargs)
6438 - self.set = set
6439 - self.name = self.arg[len(SETPREFIX):]
6440 -
6441 -class Dependency(SlotObject):
6442 - __slots__ = ("atom", "blocker", "depth",
6443 - "parent", "onlydeps", "priority", "root")
6444 - def __init__(self, **kwargs):
6445 - SlotObject.__init__(self, **kwargs)
6446 - if self.priority is None:
6447 - self.priority = DepPriority()
6448 - if self.depth is None:
6449 - self.depth = 0
6450 -
6451 -class BlockerCache(portage.cache.mappings.MutableMapping):
6452 - """This caches blockers of installed packages so that dep_check does not
6453 - have to be done for every single installed package on every invocation of
6454 - emerge. The cache is invalidated whenever it is detected that something
6455 - has changed that might alter the results of dep_check() calls:
6456 - 1) the set of installed packages (including COUNTER) has changed
6457 - 2) the old-style virtuals have changed
6458 - """
6459 -
6460 - # Number of uncached packages to trigger cache update, since
6461 - # it's wasteful to update it for every vdb change.
6462 - _cache_threshold = 5
6463 -
6464 - class BlockerData(object):
6465 -
6466 - __slots__ = ("__weakref__", "atoms", "counter")
6467 -
6468 - def __init__(self, counter, atoms):
6469 - self.counter = counter
6470 - self.atoms = atoms
6471 -
6472 - def __init__(self, myroot, vardb):
6473 - self._vardb = vardb
6474 - self._virtuals = vardb.settings.getvirtuals()
6475 - self._cache_filename = os.path.join(myroot,
6476 - portage.CACHE_PATH.lstrip(os.path.sep), "vdb_blockers.pickle")
6477 - self._cache_version = "1"
6478 - self._cache_data = None
6479 - self._modified = set()
6480 - self._load()
6481 -
6482 - def _load(self):
6483 - try:
6484 - f = open(self._cache_filename, mode='rb')
6485 - mypickle = pickle.Unpickler(f)
6486 - try:
6487 - mypickle.find_global = None
6488 - except AttributeError:
6489 - # TODO: If py3k, override Unpickler.find_class().
6490 - pass
6491 - self._cache_data = mypickle.load()
6492 - f.close()
6493 - del f
6494 - except (IOError, OSError, EOFError, ValueError, pickle.UnpicklingError), e:
6495 - if isinstance(e, pickle.UnpicklingError):
6496 - writemsg("!!! Error loading '%s': %s\n" % \
6497 - (self._cache_filename, str(e)), noiselevel=-1)
6498 - del e
6499 -
6500 - cache_valid = self._cache_data and \
6501 - isinstance(self._cache_data, dict) and \
6502 - self._cache_data.get("version") == self._cache_version and \
6503 - isinstance(self._cache_data.get("blockers"), dict)
6504 - if cache_valid:
6505 - # Validate all the atoms and counters so that
6506 - # corruption is detected as soon as possible.
6507 - invalid_items = set()
6508 - for k, v in self._cache_data["blockers"].iteritems():
6509 - if not isinstance(k, basestring):
6510 - invalid_items.add(k)
6511 - continue
6512 - try:
6513 - if portage.catpkgsplit(k) is None:
6514 - invalid_items.add(k)
6515 - continue
6516 - except portage.exception.InvalidData:
6517 - invalid_items.add(k)
6518 - continue
6519 - if not isinstance(v, tuple) or \
6520 - len(v) != 2:
6521 - invalid_items.add(k)
6522 - continue
6523 - counter, atoms = v
6524 - if not isinstance(counter, (int, long)):
6525 - invalid_items.add(k)
6526 - continue
6527 - if not isinstance(atoms, (list, tuple)):
6528 - invalid_items.add(k)
6529 - continue
6530 - invalid_atom = False
6531 - for atom in atoms:
6532 - if not isinstance(atom, basestring):
6533 - invalid_atom = True
6534 - break
6535 - if atom[:1] != "!" or \
6536 - not portage.isvalidatom(
6537 - atom, allow_blockers=True):
6538 - invalid_atom = True
6539 - break
6540 - if invalid_atom:
6541 - invalid_items.add(k)
6542 - continue
6543 -
6544 - for k in invalid_items:
6545 - del self._cache_data["blockers"][k]
6546 - if not self._cache_data["blockers"]:
6547 - cache_valid = False
6548 -
6549 - if not cache_valid:
6550 - self._cache_data = {"version":self._cache_version}
6551 - self._cache_data["blockers"] = {}
6552 - self._cache_data["virtuals"] = self._virtuals
6553 - self._modified.clear()
6554 -
6555 - def flush(self):
6556 - """If the current user has permission and the internal blocker cache
6557 - been updated, save it to disk and mark it unmodified. This is called
6558 - by emerge after it has proccessed blockers for all installed packages.
6559 - Currently, the cache is only written if the user has superuser
6560 - privileges (since that's required to obtain a lock), but all users
6561 - have read access and benefit from faster blocker lookups (as long as
6562 - the entire cache is still valid). The cache is stored as a pickled
6563 - dict object with the following format:
6564 -
6565 - {
6566 - version : "1",
6567 - "blockers" : {cpv1:(counter,(atom1, atom2...)), cpv2...},
6568 - "virtuals" : vardb.settings.getvirtuals()
6569 - }
6570 - """
6571 - if len(self._modified) >= self._cache_threshold and \
6572 - secpass >= 2:
6573 - try:
6574 - f = portage.util.atomic_ofstream(self._cache_filename, mode='wb')
6575 - pickle.dump(self._cache_data, f, protocol=2)
6576 - f.close()
6577 - portage.util.apply_secpass_permissions(
6578 - self._cache_filename, gid=portage.portage_gid, mode=0644)
6579 - except (IOError, OSError), e:
6580 - pass
6581 - self._modified.clear()
6582 -
6583 - def __setitem__(self, cpv, blocker_data):
6584 - """
6585 - Update the cache and mark it as modified for a future call to
6586 - self.flush().
6587 -
6588 - @param cpv: Package for which to cache blockers.
6589 - @type cpv: String
6590 - @param blocker_data: An object with counter and atoms attributes.
6591 - @type blocker_data: BlockerData
6592 - """
6593 - self._cache_data["blockers"][cpv] = \
6594 - (blocker_data.counter, tuple(str(x) for x in blocker_data.atoms))
6595 - self._modified.add(cpv)
6596 -
6597 - def __iter__(self):
6598 - if self._cache_data is None:
6599 - # triggered by python-trace
6600 - return iter([])
6601 - return iter(self._cache_data["blockers"])
6602 -
6603 - def __delitem__(self, cpv):
6604 - del self._cache_data["blockers"][cpv]
6605 -
6606 - def __getitem__(self, cpv):
6607 - """
6608 - @rtype: BlockerData
6609 - @returns: An object with counter and atoms attributes.
6610 - """
6611 - return self.BlockerData(*self._cache_data["blockers"][cpv])
6612 -
6613 class BlockerDB(object):
6614
6615 def __init__(self, root_config):
6616 @@ -4482,139 +1773,6 @@
6617 msg2 = "".join("%s\n" % line for line in textwrap.wrap("".join(msg), 72))
6618 writemsg_level(msg1 + msg2, level=logging.ERROR, noiselevel=-1)
6619
6620 -class PackageVirtualDbapi(portage.dbapi):
6621 - """
6622 - A dbapi-like interface class that represents the state of the installed
6623 - package database as new packages are installed, replacing any packages
6624 - that previously existed in the same slot. The main difference between
6625 - this class and fakedbapi is that this one uses Package instances
6626 - internally (passed in via cpv_inject() and cpv_remove() calls).
6627 - """
6628 - def __init__(self, settings):
6629 - portage.dbapi.__init__(self)
6630 - self.settings = settings
6631 - self._match_cache = {}
6632 - self._cp_map = {}
6633 - self._cpv_map = {}
6634 -
6635 - def clear(self):
6636 - """
6637 - Remove all packages.
6638 - """
6639 - if self._cpv_map:
6640 - self._clear_cache()
6641 - self._cp_map.clear()
6642 - self._cpv_map.clear()
6643 -
6644 - def copy(self):
6645 - obj = PackageVirtualDbapi(self.settings)
6646 - obj._match_cache = self._match_cache.copy()
6647 - obj._cp_map = self._cp_map.copy()
6648 - for k, v in obj._cp_map.iteritems():
6649 - obj._cp_map[k] = v[:]
6650 - obj._cpv_map = self._cpv_map.copy()
6651 - return obj
6652 -
6653 - def __iter__(self):
6654 - return self._cpv_map.itervalues()
6655 -
6656 - def __contains__(self, item):
6657 - existing = self._cpv_map.get(item.cpv)
6658 - if existing is not None and \
6659 - existing == item:
6660 - return True
6661 - return False
6662 -
6663 - def get(self, item, default=None):
6664 - cpv = getattr(item, "cpv", None)
6665 - if cpv is None:
6666 - if len(item) != 4:
6667 - return default
6668 - type_name, root, cpv, operation = item
6669 -
6670 - existing = self._cpv_map.get(cpv)
6671 - if existing is not None and \
6672 - existing == item:
6673 - return existing
6674 - return default
6675 -
6676 - def match_pkgs(self, atom):
6677 - return [self._cpv_map[cpv] for cpv in self.match(atom)]
6678 -
6679 - def _clear_cache(self):
6680 - if self._categories is not None:
6681 - self._categories = None
6682 - if self._match_cache:
6683 - self._match_cache = {}
6684 -
6685 - def match(self, origdep, use_cache=1):
6686 - result = self._match_cache.get(origdep)
6687 - if result is not None:
6688 - return result[:]
6689 - result = portage.dbapi.match(self, origdep, use_cache=use_cache)
6690 - self._match_cache[origdep] = result
6691 - return result[:]
6692 -
6693 - def cpv_exists(self, cpv):
6694 - return cpv in self._cpv_map
6695 -
6696 - def cp_list(self, mycp, use_cache=1):
6697 - cachelist = self._match_cache.get(mycp)
6698 - # cp_list() doesn't expand old-style virtuals
6699 - if cachelist and cachelist[0].startswith(mycp):
6700 - return cachelist[:]
6701 - cpv_list = self._cp_map.get(mycp)
6702 - if cpv_list is None:
6703 - cpv_list = []
6704 - else:
6705 - cpv_list = [pkg.cpv for pkg in cpv_list]
6706 - self._cpv_sort_ascending(cpv_list)
6707 - if not (not cpv_list and mycp.startswith("virtual/")):
6708 - self._match_cache[mycp] = cpv_list
6709 - return cpv_list[:]
6710 -
6711 - def cp_all(self):
6712 - return list(self._cp_map)
6713 -
6714 - def cpv_all(self):
6715 - return list(self._cpv_map)
6716 -
6717 - def cpv_inject(self, pkg):
6718 - cp_list = self._cp_map.get(pkg.cp)
6719 - if cp_list is None:
6720 - cp_list = []
6721 - self._cp_map[pkg.cp] = cp_list
6722 - e_pkg = self._cpv_map.get(pkg.cpv)
6723 - if e_pkg is not None:
6724 - if e_pkg == pkg:
6725 - return
6726 - self.cpv_remove(e_pkg)
6727 - for e_pkg in cp_list:
6728 - if e_pkg.slot_atom == pkg.slot_atom:
6729 - if e_pkg == pkg:
6730 - return
6731 - self.cpv_remove(e_pkg)
6732 - break
6733 - cp_list.append(pkg)
6734 - self._cpv_map[pkg.cpv] = pkg
6735 - self._clear_cache()
6736 -
6737 - def cpv_remove(self, pkg):
6738 - old_pkg = self._cpv_map.get(pkg.cpv)
6739 - if old_pkg != pkg:
6740 - raise KeyError(pkg)
6741 - self._cp_map[pkg.cp].remove(pkg)
6742 - del self._cpv_map[pkg.cpv]
6743 - self._clear_cache()
6744 -
6745 - def aux_get(self, cpv, wants):
6746 - metadata = self._cpv_map[cpv].metadata
6747 - return [metadata.get(x, "") for x in wants]
6748 -
6749 - def aux_update(self, cpv, values):
6750 - self._cpv_map[cpv].metadata.update(values)
6751 - self._clear_cache()
6752 -
6753 class depgraph(object):
6754
6755 pkg_tree_map = RootConfig.pkg_tree_map
6756 @@ -6285,10 +3443,11 @@
6757 print "!!! One of the following masked packages is required to complete your request:"
6758 have_eapi_mask = show_masked_packages(masked_packages)
6759 if have_eapi_mask:
6760 + print
6761 msg = ("The current version of portage supports " + \
6762 "EAPI '%s'. You must upgrade to a newer version" + \
6763 " of portage before EAPI masked packages can" + \
6764 - " be installed.") % (portage.const.EAPI)
6765 + " be installed.") % portage.const.EAPI
6766 from textwrap import wrap
6767 for line in wrap(msg, 75):
6768 print line
6769 @@ -9321,70 +6480,6 @@
6770 metadata = self._cpv_pkg_map[cpv].metadata
6771 return [metadata.get(x, "") for x in wants]
6772
6773 -class RepoDisplay(object):
6774 - def __init__(self, roots):
6775 - self._shown_repos = {}
6776 - self._unknown_repo = False
6777 - repo_paths = set()
6778 - for root_config in roots.itervalues():
6779 - portdir = root_config.settings.get("PORTDIR")
6780 - if portdir:
6781 - repo_paths.add(portdir)
6782 - overlays = root_config.settings.get("PORTDIR_OVERLAY")
6783 - if overlays:
6784 - repo_paths.update(overlays.split())
6785 - repo_paths = list(repo_paths)
6786 - self._repo_paths = repo_paths
6787 - self._repo_paths_real = [ os.path.realpath(repo_path) \
6788 - for repo_path in repo_paths ]
6789 -
6790 - if root_config.settings.get("PORTAGE_BINHOST"):
6791 - binhost = root_config.settings.get("PORTAGE_BINHOST")
6792 - self._repo_paths.append(binhost)
6793 - self._repo_paths_real.append(binhost)
6794 -
6795 - # pre-allocate index for PORTDIR so that it always has index 0.
6796 - for root_config in roots.itervalues():
6797 - portdb = root_config.trees["porttree"].dbapi
6798 - portdir = portdb.porttree_root
6799 - if portdir:
6800 - self.repoStr(portdir)
6801 -
6802 - def repoStr(self, repo_path_real):
6803 - real_index = -1
6804 - if repo_path_real:
6805 - real_index = self._repo_paths_real.index(repo_path_real)
6806 - if real_index == -1:
6807 - s = "?"
6808 - self._unknown_repo = True
6809 - else:
6810 - shown_repos = self._shown_repos
6811 - repo_paths = self._repo_paths
6812 - repo_path = repo_paths[real_index]
6813 - index = shown_repos.get(repo_path)
6814 - if index is None:
6815 - index = len(shown_repos)
6816 - shown_repos[repo_path] = index
6817 - s = str(index)
6818 - return s
6819 -
6820 - def __str__(self):
6821 - output = []
6822 - shown_repos = self._shown_repos
6823 - unknown_repo = self._unknown_repo
6824 - if shown_repos or self._unknown_repo:
6825 - output.append("Portage tree and overlays:\n")
6826 - show_repo_paths = list(shown_repos)
6827 - for repo_path, repo_index in shown_repos.iteritems():
6828 - show_repo_paths[repo_index] = repo_path
6829 - if show_repo_paths:
6830 - for index, repo_path in enumerate(show_repo_paths):
6831 - output.append(" "+teal("["+str(index)+"]")+" %s\n" % repo_path)
6832 - if unknown_repo:
6833 - output.append(" "+teal("[?]") + \
6834 - " indicates that the source repository could not be determined\n")
6835 - return "".join(output)
6836 -
6837 class PackageCounters(object):
6838
6839 def __init__(self):
6840 @@ -9457,196 +6552,7 @@
6841 (self.blocks - self.blocks_satisfied))
6842 return "".join(myoutput)
6843
6844 -class UseFlagDisplay(object):
6845
6846 - __slots__ = ('name', 'enabled', 'forced')
6847 -
6848 - def __init__(self, name, enabled, forced):
6849 - self.name = name
6850 - self.enabled = enabled
6851 - self.forced = forced
6852 -
6853 - def __str__(self):
6854 - s = self.name
6855 - if self.enabled:
6856 - s = red(s)
6857 - else:
6858 - s = '-' + s
6859 - s = blue(s)
6860 - if self.forced:
6861 - s = '(%s)' % s
6862 - return s
6863 -
6864 - def _cmp_combined(a, b):
6865 - """
6866 - Sort by name, combining enabled and disabled flags.
6867 - """
6868 - return (a.name > b.name) - (a.name < b.name)
6869 -
6870 - sort_combined = cmp_sort_key(_cmp_combined)
6871 - del _cmp_combined
6872 -
6873 - def _cmp_separated(a, b):
6874 - """
6875 - Sort by name, separating enabled flags from disabled flags.
6876 - """
6877 - enabled_diff = b.enabled - a.enabled
6878 - if enabled_diff:
6879 - return enabled_diff
6880 - return (a.name > b.name) - (a.name < b.name)
6881 -
6882 - sort_separated = cmp_sort_key(_cmp_separated)
6883 - del _cmp_separated
6884 -
6885 -class PollSelectAdapter(PollConstants):
6886 -
6887 - """
6888 - Use select to emulate a poll object, for
6889 - systems that don't support poll().
6890 - """
6891 -
6892 - def __init__(self):
6893 - self._registered = {}
6894 - self._select_args = [[], [], []]
6895 -
6896 - def register(self, fd, *args):
6897 - """
6898 - Only POLLIN is currently supported!
6899 - """
6900 - if len(args) > 1:
6901 - raise TypeError(
6902 - "register expected at most 2 arguments, got " + \
6903 - repr(1 + len(args)))
6904 -
6905 - eventmask = PollConstants.POLLIN | \
6906 - PollConstants.POLLPRI | PollConstants.POLLOUT
6907 - if args:
6908 - eventmask = args[0]
6909 -
6910 - self._registered[fd] = eventmask
6911 - self._select_args = None
6912 -
6913 - def unregister(self, fd):
6914 - self._select_args = None
6915 - del self._registered[fd]
6916 -
6917 - def poll(self, *args):
6918 - if len(args) > 1:
6919 - raise TypeError(
6920 - "poll expected at most 2 arguments, got " + \
6921 - repr(1 + len(args)))
6922 -
6923 - timeout = None
6924 - if args:
6925 - timeout = args[0]
6926 -
6927 - select_args = self._select_args
6928 - if select_args is None:
6929 - select_args = [self._registered.keys(), [], []]
6930 -
6931 - if timeout is not None:
6932 - select_args = select_args[:]
6933 - # Translate poll() timeout args to select() timeout args:
6934 - #
6935 - # | units | value(s) for indefinite block
6936 - # ---------|--------------|------------------------------
6937 - # poll | milliseconds | omitted, negative, or None
6938 - # ---------|--------------|------------------------------
6939 - # select | seconds | omitted
6940 - # ---------|--------------|------------------------------
6941 -
6942 - if timeout is not None and timeout < 0:
6943 - timeout = None
6944 - if timeout is not None:
6945 - select_args.append(timeout / 1000)
6946 -
6947 - select_events = select.select(*select_args)
6948 - poll_events = []
6949 - for fd in select_events[0]:
6950 - poll_events.append((fd, PollConstants.POLLIN))
6951 - return poll_events
6952 -
6953 -class SequentialTaskQueue(SlotObject):
6954 -
6955 - __slots__ = ("max_jobs", "running_tasks") + \
6956 - ("_dirty", "_scheduling", "_task_queue")
6957 -
6958 - def __init__(self, **kwargs):
6959 - SlotObject.__init__(self, **kwargs)
6960 - self._task_queue = deque()
6961 - self.running_tasks = set()
6962 - if self.max_jobs is None:
6963 - self.max_jobs = 1
6964 - self._dirty = True
6965 -
6966 - def add(self, task):
6967 - self._task_queue.append(task)
6968 - self._dirty = True
6969 -
6970 - def addFront(self, task):
6971 - self._task_queue.appendleft(task)
6972 - self._dirty = True
6973 -
6974 - def schedule(self):
6975 -
6976 - if not self._dirty:
6977 - return False
6978 -
6979 - if not self:
6980 - return False
6981 -
6982 - if self._scheduling:
6983 - # Ignore any recursive schedule() calls triggered via
6984 - # self._task_exit().
6985 - return False
6986 -
6987 - self._scheduling = True
6988 -
6989 - task_queue = self._task_queue
6990 - running_tasks = self.running_tasks
6991 - max_jobs = self.max_jobs
6992 - state_changed = False
6993 -
6994 - while task_queue and \
6995 - (max_jobs is True or len(running_tasks) < max_jobs):
6996 - task = task_queue.popleft()
6997 - cancelled = getattr(task, "cancelled", None)
6998 - if not cancelled:
6999 - running_tasks.add(task)
7000 - task.addExitListener(self._task_exit)
7001 - task.start()
7002 - state_changed = True
7003 -
7004 - self._dirty = False
7005 - self._scheduling = False
7006 -
7007 - return state_changed
7008 -
7009 - def _task_exit(self, task):
7010 - """
7011 - Since we can always rely on exit listeners being called, the set of
7012 - running tasks is always pruned automatically and there is never any need
7013 - to actively prune it.
7014 - """
7015 - self.running_tasks.remove(task)
7016 - if self._task_queue:
7017 - self._dirty = True
7018 -
7019 - def clear(self):
7020 - self._task_queue.clear()
7021 - running_tasks = self.running_tasks
7022 - while running_tasks:
7023 - task = running_tasks.pop()
7024 - task.removeExitListener(self._task_exit)
7025 - task.cancel()
7026 - self._dirty = False
7027 -
7028 - def __nonzero__(self):
7029 - return bool(self._task_queue or self.running_tasks)
7030 -
7031 - def __len__(self):
7032 - return len(self._task_queue) + len(self.running_tasks)
7033 -
7034 _can_poll_device = None
7035
7036 def can_poll_device():
7037 @@ -10251,24 +7157,6 @@
7038 if self.xterm_titles:
7039 xtermTitle(" ".join(plain_output.split()))
7040
7041 -class ProgressHandler(object):
7042 - def __init__(self):
7043 - self.curval = 0
7044 - self.maxval = 0
7045 - self._last_update = 0
7046 - self.min_latency = 0.2
7047 -
7048 - def onProgress(self, maxval, curval):
7049 - self.maxval = maxval
7050 - self.curval = curval
7051 - cur_time = time.time()
7052 - if cur_time - self._last_update >= self.min_latency:
7053 - self._last_update = cur_time
7054 - self.display()
7055 -
7056 - def display(self):
7057 - raise NotImplementedError(self)
7058 -
7059 class Scheduler(PollScheduler):
7060
7061 _opts_ignore_blockers = \
7062 @@ -12532,7 +9420,7 @@
7063
7064 def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
7065
7066 - if os.path.exists(EPREFIX+"/usr/bin/install-info"):
7067 + if os.path.exists(EPREFIX + "/usr/bin/install-info"):
7068 out = portage.output.EOutput()
7069 regen_infodirs=[]
7070 for z in infodirs:
7071 @@ -12592,7 +9480,7 @@
7072 raise
7073 del e
7074 processed_count += 1
7075 - myso=commands.getstatusoutput("LANG=C LANGUAGE=C "+EPREFIX+"/usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1]
7076 + myso=commands.getstatusoutput("LANG=C LANGUAGE=C " + EPREFIX + "/usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1]
7077 existsstr="already exists, for file `"
7078 if myso!="":
7079 if re.search(existsstr,myso):
7080 @@ -13034,7 +9922,7 @@
7081 "control (contains %s).\n!!! Aborting rsync sync.\n") % \
7082 (myportdir, vcs_dir), level=logging.ERROR, noiselevel=-1)
7083 return 1
7084 - if not os.path.exists(EPREFIX+"/usr/bin/rsync"):
7085 + if not os.path.exists(EPREFIX + "/usr/bin/rsync"):
7086 print "!!! /usr/bin/rsync does not exist, so rsync support is disabled."
7087 print "!!! Type \"emerge net-misc/rsync\" to enable rsync support."
7088 sys.exit(1)
7089 @@ -13206,7 +10094,7 @@
7090 if mytimestamp != 0 and "--quiet" not in myopts:
7091 print ">>> Checking server timestamp ..."
7092
7093 - rsynccommand = [EPREFIX+"/usr/bin/rsync"] + rsync_opts + extra_rsync_opts
7094 + rsynccommand = [EPREFIX + "/usr/bin/rsync"] + rsync_opts + extra_rsync_opts
7095
7096 if "--debug" in myopts:
7097 print rsynccommand
7098 @@ -13357,7 +10245,7 @@
7099 out.eerror(line)
7100 sys.exit(exitcode)
7101 elif syncuri[:6]=="cvs://":
7102 - if not os.path.exists(EPREFIX+"/usr/bin/cvs"):
7103 + if not os.path.exists(EPREFIX + "/usr/bin/cvs"):
7104 print "!!! cvs does not exist, so CVS support is disabled."
7105 print "!!! Type \"emerge dev-util/cvs\" to enable CVS support."
7106 sys.exit(1)
7107 @@ -13391,7 +10279,8 @@
7108 sys.exit(retval)
7109 dosyncuri = syncuri
7110 elif syncuri[:11]=="svn+http://" or syncuri[:6]=="svn://" or syncuri[:12]=="svn+https://":
7111 - if not os.path.exists(EPREFIX+"/usr/bin/svn"):
7112 + # Prefix hardcoded case
7113 + if not os.path.exists(EPREFIX + "/usr/bin/svn"):
7114 print "!!! svn does not exist, so SVN support is disabled."
7115 print "!!! Type \"emerge dev-util/subversion\" to enable SVN support."
7116 sys.exit(1)
7117 @@ -13480,7 +10369,7 @@
7118 [os.path.join('/', EPREFIX_LSTRIP, portage.USER_CONFIG_PATH.lstrip(os.path.sep), "bin", "post_sync"),
7119 dosyncuri], env=settings.environ())
7120 if retval != os.EX_OK:
7121 - print red(" * ")+bold("spawn failed of "+ EPREFIX + portage.USER_CONFIG_PATH + "/bin/post_sync")
7122 + print red(" * ")+bold("spawn failed of " + EPREFIX + portage.USER_CONFIG_PATH + "/bin/post_sync")
7123
7124 if(mybestpv != mypvs) and not "--quiet" in myopts:
7125 print
7126
7127 Modified: main/branches/prefix/pym/_emerge/help.py
7128 ===================================================================
7129 --- main/branches/prefix/pym/_emerge/help.py 2009-06-26 23:38:01 UTC (rev 13703)
7130 +++ main/branches/prefix/pym/_emerge/help.py 2009-06-27 12:51:25 UTC (rev 13704)
7131 @@ -2,8 +2,6 @@
7132 # Distributed under the terms of the GNU General Public License v2
7133 # $Id$
7134
7135 -
7136 -import os,sys
7137 from portage.output import bold, turquoise, green
7138
7139 def shorthelp():