(self.type_name, self.root, self.cpv, self.operation)
return self._hash_key
- def __cmp__(self, other):
- if self > other:
- return 1
- elif self < other:
- return -1
- return 0
-
def __lt__(self, other):
if other.cp != self.cp:
return False
files = self._files
self._raw_metadata.append(files.ebuild.read())
if not self._raw_metadata[-1]:
+ # Split lines here so they can be counted inside _set_returncode().
+ self._raw_metadata = "".join(self._raw_metadata).splitlines()
self._unregister()
self.wait()
if self.returncode == os.EX_OK:
- metadata = izip(portage.auxdbkeys,
- "".join(self._raw_metadata).splitlines())
+ metadata = izip(portage.auxdbkeys, self._raw_metadata)
self.metadata_callback(self.cpv, self.ebuild_path,
self.repo_path, metadata, self.ebuild_mtime)
return self._registered
+ def _set_returncode(self, wait_retval):
+ SubProcess._set_returncode(self, wait_retval)
+ if self.returncode == os.EX_OK and \
+ len(portage.auxdbkeys) != len(self._raw_metadata):
+ # Don't trust bash's returncode if the
+ # number of lines is incorrect.
+ self.returncode = 1
+
class EbuildProcess(SpawnProcess):
__slots__ = ("phase", "pkg", "settings", "tree")
settings.setcpv(pkg)
self._tree = "bintree"
self._bintree = self.pkg.root_config.trees[self._tree]
- self._verify = "strict" in self.settings.features and \
- not self.opts.pretend
+ self._verify = not self.opts.pretend
dir_path = os.path.join(settings["PORTAGE_TMPDIR"],
"portage", pkg.category, pkg.pf)
self._image_dir = os.path.join(dir_path, "image")
self._infloc = os.path.join(dir_path, "build-info")
self._ebuild_path = os.path.join(self._infloc, pkg.pf + ".ebuild")
+ settings["EBUILD"] = self._ebuild_path
+ debug = settings.get("PORTAGE_DEBUG") == "1"
+ portage.doebuild_environment(self._ebuild_path, "setup",
+ settings["ROOT"], settings, debug, 1, self._bintree.dbapi)
# The prefetcher has already completed or it
# could be running now. If it's running now,
pkg = self.pkg
pkg_count = self.pkg_count
+ if not self.opts.fetchonly:
+ self._build_dir.lock()
+ try:
+ shutil.rmtree(self._build_dir.dir_path)
+ except EnvironmentError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ portage.prepare_build_dirs(self.settings["ROOT"], self.settings, 1)
fetcher = BinpkgFetcher(background=self.background,
- logfile=self.scheduler.fetch.log_file, pkg=self.pkg,
+ logfile=self.settings.get("PORTAGE_LOG_FILE"), pkg=self.pkg,
scheduler=self.scheduler)
pkg_path = fetcher.pkg_path
self._pkg_path = pkg_path
short_msg = "emerge: (%s of %s) %s Fetch" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv)
self.logger.log(msg, short_msg=short_msg)
-
- if self.background:
- fetcher.addExitListener(self._fetcher_exit)
- self._current_task = fetcher
- self.scheduler.fetch.schedule(fetcher)
- else:
- self._start_task(fetcher, self._fetcher_exit)
+ self._start_task(fetcher, self._fetcher_exit)
return
self._fetcher_exit(fetcher)
# --getbinpkg is enabled.
if fetcher.returncode is not None:
self._fetched_pkg = True
- if self.opts.fetchonly:
- self._final_exit(fetcher)
- self.wait()
- return
- elif self._default_exit(fetcher) != os.EX_OK:
+ if self._default_exit(fetcher) != os.EX_OK:
+ self._unlock_builddir()
self.wait()
return
verifier = None
if self._verify:
- verifier = BinpkgVerifier(background=self.background,
- logfile=self.scheduler.fetch.log_file, pkg=self.pkg)
-
+ logfile = None
if self.background:
- verifier.addExitListener(self._verifier_exit)
- self._current_task = verifier
- self.scheduler.fetch.schedule(verifier)
- else:
- self._start_task(verifier, self._verifier_exit)
+ logfile = self.settings.get("PORTAGE_LOG_FILE")
+ verifier = BinpkgVerifier(background=self.background,
+ logfile=logfile, pkg=self.pkg)
+ self._start_task(verifier, self._verifier_exit)
return
self._verifier_exit(verifier)
def _verifier_exit(self, verifier):
if verifier is not None and \
self._default_exit(verifier) != os.EX_OK:
+ self._unlock_builddir()
self.wait()
return
if self._fetched_pkg:
self._bintree.inject(pkg.cpv, filename=pkg_path)
+ if self.opts.fetchonly:
+ self._current_task = None
+ self.returncode = os.EX_OK
+ self.wait()
+ return
+
msg = " === (%s of %s) Merging Binary (%s::%s)" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv, pkg_path)
short_msg = "emerge: (%s of %s) %s Merge Binary" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv)
logger.log(msg, short_msg=short_msg)
- self._build_dir.lock()
-
phase = "clean"
settings = self.settings
- settings.setcpv(pkg)
- settings["EBUILD"] = self._ebuild_path
ebuild_phase = EbuildPhase(background=self.background,
pkg=pkg, phase=phase, scheduler=self.scheduler,
settings=settings, tree=self._tree)
self.wait()
def _unlock_builddir(self):
+ if self.opts.fetchonly:
+ return
portage.elog.elog_process(self.pkg.cpv, self.settings)
self._build_dir.unlock()
writemsg("!!! Expected: %s\n" % e.value[3],
noiselevel=-1)
rval = 1
+ if rval != os.EX_OK:
+ pkg_path = bintree.getname(pkg.cpv)
+ head, tail = os.path.split(pkg_path)
+ temp_filename = portage._checksum_failure_temp_file(head, tail)
+ writemsg("File renamed to '%s'\n" % (temp_filename,),
+ noiselevel=-1)
finally:
sys.stdout = stdout_orig
sys.stderr = stderr_orig
self.returncode = rval
self.wait()
+class BinpkgPrefetcher(CompositeTask):
+
+ __slots__ = ("pkg",) + \
+ ("pkg_path", "_bintree",)
+
+ def _start(self):
+ self._bintree = self.pkg.root_config.trees["bintree"]
+ fetcher = BinpkgFetcher(background=self.background,
+ logfile=self.scheduler.fetch.log_file, pkg=self.pkg,
+ scheduler=self.scheduler)
+ self.pkg_path = fetcher.pkg_path
+ self._start_task(fetcher, self._fetcher_exit)
+
+ def _fetcher_exit(self, fetcher):
+
+ if self._default_exit(fetcher) != os.EX_OK:
+ self.wait()
+ return
+
+ verifier = BinpkgVerifier(background=self.background,
+ logfile=self.scheduler.fetch.log_file, pkg=self.pkg)
+ self._start_task(verifier, self._verifier_exit)
+
+ def _verifier_exit(self, verifier):
+ if self._default_exit(verifier) != os.EX_OK:
+ self.wait()
+ return
+
+ self._bintree.inject(self.pkg.cpv, filename=self.pkg_path)
+
+ self._current_task = None
+ self.returncode = os.EX_OK
+ self.wait()
+
class BinpkgExtractorAsync(SpawnProcess):
__slots__ = ("image_dir", "pkg", "pkg_path")
self._process_slot_conflicts()
def _serialize_tasks(self):
+
+ if "--debug" in self.myopts:
+ writemsg("\ndigraph:\n\n", noiselevel=-1)
+ self.digraph.debug_print()
+ writemsg("\n", noiselevel=-1)
+
scheduler_graph = self.digraph.copy()
mygraph=self.digraph.copy()
# Prune "nomerge" root nodes if nothing depends on them, since
"--getbinpkg" in self.myopts and \
pkg.root_config.trees["bintree"].isremote(pkg.cpv):
- prefetcher = BinpkgFetcher(background=True,
- logfile=self._fetch_log, pkg=pkg,
- scheduler=self._sched_iface)
+ prefetcher = BinpkgPrefetcher(background=True,
+ pkg=pkg, scheduler=self._sched_iface)
return prefetcher
portage.match_from_list(
portage.const.PORTAGE_PACKAGE_ATOM, [pkg]):
if self._running_portage:
- return cmp(pkg, self._running_portage) != 0
+ return pkg.cpv != self._running_portage.cpv
return True
return False
len(self.order)
def debug_print(self):
+ def output(s):
+ writemsg(s, noiselevel=-1)
for node in self.nodes:
- print node,
+ output("%s " % (node,))
if self.nodes[node][0]:
- print "depends on"
+ output("depends on\n")
else:
- print "(no children)"
+ output("(no children)\n")
for child in self.nodes[node][0]:
- print " ",child,
- print "(%s)" % self.nodes[node][0][child]
+ output(" %s (%s)\n" % \
+ (child, self.nodes[node][0][child],))
#parse /etc/env.d and generate /etc/profile.env
required_hash_types.add("size")
required_hash_types.add(portage.const.MANIFEST2_REQUIRED_HASH)
dist_hashes = mf.fhashdict.get("DIST", {})
- missing_hashes = set()
+
+ # To avoid accidental regeneration of digests with the incorrect
+ # files (such as partially downloaded files), trigger the fetch
+ # code if the file exists and it's size doesn't match the current
+ # manifest entry. If there really is a legitimate reason for the
+ # digest to change, `ebuild --force digest` can be used to avoid
+ # triggering this code (or else the old digests can be manually
+ # removed from the Manifest).
+ missing_files = []
for myfile in distfiles_map:
myhashes = dist_hashes.get(myfile)
if not myhashes:
- missing_hashes.add(myfile)
- continue
- if required_hash_types.difference(myhashes):
- missing_hashes.add(myfile)
+ missing_files.append(myfile)
continue
- if myhashes["size"] == 0:
- missing_hashes.add(myfile)
- if missing_hashes:
- missing_files = []
- for myfile in missing_hashes:
- try:
- st = os.stat(os.path.join(mysettings["DISTDIR"], myfile))
- except OSError, e:
- if e.errno != errno.ENOENT:
- raise
- del e
+ size = myhashes.get("size")
+
+ try:
+ st = os.stat(os.path.join(mysettings["DISTDIR"], myfile))
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ del e
+ if size == 0:
missing_files.append(myfile)
- else:
- # If the file is empty then it's obviously invalid.
- if st.st_size == 0:
- missing_files.append(myfile)
- if missing_files:
+ continue
+ if required_hash_types.difference(myhashes):
+ missing_files.append(myfile)
+ continue
+ else:
+ if st.st_size == 0 or size is not None and size != st.st_size:
+ missing_files.append(myfile)
+ continue
+
+ if missing_files:
mytree = os.path.realpath(os.path.dirname(
os.path.dirname(mysettings["O"])))
fetch_settings = config(clone=mysettings)
# shift in order to distinguish it from a return value. (just
# like portage.process.spawn() would do).
if retval & 0xff:
- return (retval & 0xff) << 8
- # Otherwise, return its exit code.
- return retval >> 8
+ retval = (retval & 0xff) << 8
+ else:
+ # Otherwise, return its exit code.
+ retval = retval >> 8
+ if retval == os.EX_OK and len(dbkey) != len(auxdbkeys):
+ # Don't trust bash's returncode if the
+ # number of lines is incorrect.
+ retval = 1
+ return retval
elif dbkey:
mysettings["dbkey"] = dbkey
else: