Gentoo Archives: gentoo-commits

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