blob: 543fb1b03def414048cb21c7f5ec9f984503740f [file] [log] [blame]
# Copyright 1999-2009 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$
from _emerge.EbuildExecuter import EbuildExecuter
from _emerge.EbuildPhase import EbuildPhase
from _emerge.EbuildBinpkg import EbuildBinpkg
from _emerge.EbuildFetcher import EbuildFetcher
from _emerge.CompositeTask import CompositeTask
from _emerge.EbuildMerge import EbuildMerge
from _emerge.EbuildFetchonly import EbuildFetchonly
from _emerge.EbuildBuildDir import EbuildBuildDir
from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
from portage.util import writemsg
import portage
from portage import os
from portage import _encodings
from portage import _unicode_encode
import codecs
from portage.output import colorize
class EbuildBuild(CompositeTask):
__slots__ = ("args_set", "config_pool", "find_blockers",
"ldpath_mtimes", "logger", "opts", "pkg", "pkg_count",
"prefetcher", "settings", "world_atom") + \
("_build_dir", "_buildpkg", "_ebuild_path", "_issyspkg", "_tree")
def _start(self):
logger = self.logger
opts = self.opts
pkg = self.pkg
settings = self.settings
world_atom = self.world_atom
root_config = pkg.root_config
tree = "porttree"
self._tree = tree
portdb = root_config.trees[tree].dbapi
settings.setcpv(pkg)
settings.configdict["pkg"]["EMERGE_FROM"] = pkg.type_name
ebuild_path = portdb.findname(pkg.cpv)
if ebuild_path is None:
raise AssertionError("ebuild not found for '%s'" % pkg.cpv)
self._ebuild_path = ebuild_path
prefetcher = self.prefetcher
if prefetcher is None:
pass
elif not prefetcher.isAlive():
prefetcher.cancel()
elif prefetcher.poll() is None:
waiting_msg = "Fetching files " + \
"in the background. " + \
"To view fetch progress, run `tail -f " + \
"/var/log/emerge-fetch.log` in another " + \
"terminal."
msg_prefix = colorize("GOOD", " * ")
from textwrap import wrap
waiting_msg = "".join("%s%s\n" % (msg_prefix, line) \
for line in wrap(waiting_msg, 65))
if not self.background:
writemsg(waiting_msg, noiselevel=-1)
self._current_task = prefetcher
prefetcher.addExitListener(self._prefetch_exit)
return
self._prefetch_exit(prefetcher)
def _prefetch_exit(self, prefetcher):
opts = self.opts
pkg = self.pkg
settings = self.settings
if opts.fetchonly:
fetcher = EbuildFetchonly(
fetch_all=opts.fetch_all_uri,
pkg=pkg, pretend=opts.pretend,
settings=settings)
retval = fetcher.execute()
self.returncode = retval
self.wait()
return
fetcher = EbuildFetcher(config_pool=self.config_pool,
fetchall=opts.fetch_all_uri,
fetchonly=opts.fetchonly,
background=self.background,
pkg=pkg, scheduler=self.scheduler)
self._start_task(fetcher, self._fetch_exit)
def _fetch_exit(self, fetcher):
opts = self.opts
pkg = self.pkg
fetch_failed = False
if opts.fetchonly:
fetch_failed = self._final_exit(fetcher) != os.EX_OK
else:
fetch_failed = self._default_exit(fetcher) != os.EX_OK
if fetch_failed and fetcher.logfile is not None and \
os.path.exists(fetcher.logfile):
self.settings["PORTAGE_LOG_FILE"] = fetcher.logfile
if not fetch_failed and fetcher.logfile is not None:
# Fetch was successful, so remove the fetch log.
try:
os.unlink(fetcher.logfile)
except OSError:
pass
if fetch_failed or opts.fetchonly:
self.wait()
return
logger = self.logger
opts = self.opts
pkg_count = self.pkg_count
scheduler = self.scheduler
settings = self.settings
features = settings.features
ebuild_path = self._ebuild_path
system_set = pkg.root_config.sets["system"]
self._build_dir = EbuildBuildDir(pkg=pkg, settings=settings)
self._build_dir.lock()
# Cleaning is triggered before the setup
# phase, in portage.doebuild().
msg = " === (%s of %s) Cleaning (%s::%s)" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
short_msg = "emerge: (%s of %s) %s Clean" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv)
logger.log(msg, short_msg=short_msg)
#buildsyspkg: Check if we need to _force_ binary package creation
self._issyspkg = "buildsyspkg" in features and \
system_set.findAtomForPackage(pkg) and \
not opts.buildpkg
if opts.buildpkg or self._issyspkg:
self._buildpkg = True
msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
short_msg = "emerge: (%s of %s) %s Compile" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv)
logger.log(msg, short_msg=short_msg)
else:
msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv, ebuild_path)
short_msg = "emerge: (%s of %s) %s Compile" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv)
logger.log(msg, short_msg=short_msg)
build = EbuildExecuter(background=self.background, pkg=pkg,
scheduler=scheduler, settings=settings)
self._start_task(build, self._build_exit)
def _unlock_builddir(self):
portage.elog.elog_process(self.pkg.cpv, self.settings)
self._build_dir.unlock()
def _build_exit(self, build):
if self._default_exit(build) != os.EX_OK:
self._unlock_builddir()
self.wait()
return
opts = self.opts
buildpkg = self._buildpkg
if not buildpkg:
self._final_exit(build)
self.wait()
return
if self._issyspkg:
msg = ">>> This is a system package, " + \
"let's pack a rescue tarball.\n"
log_path = self.settings.get("PORTAGE_LOG_FILE")
if log_path is not None:
log_file = codecs.open(_unicode_encode(log_path,
encoding=_encodings['fs'], errors='strict'),
mode='a', encoding=_encodings['content'], errors='replace')
try:
log_file.write(msg)
finally:
log_file.close()
if not self.background:
portage.writemsg_stdout(msg, noiselevel=-1)
packager = EbuildBinpkg(background=self.background, pkg=self.pkg,
scheduler=self.scheduler, settings=self.settings)
self._start_task(packager, self._buildpkg_exit)
def _buildpkg_exit(self, packager):
"""
Released build dir lock when there is a failure or
when in buildpkgonly mode. Otherwise, the lock will
be released when merge() is called.
"""
if self._default_exit(packager) != os.EX_OK:
self._unlock_builddir()
self.wait()
return
if self.opts.buildpkgonly:
phase = 'success_hooks'
success_hooks = MiscFunctionsProcess(
background=self.background,
commands=[phase], phase=phase, pkg=self.pkg,
scheduler=self.scheduler, settings=self.settings)
self._start_task(success_hooks,
self._buildpkgonly_success_hook_exit)
return
# Continue holding the builddir lock until
# after the package has been installed.
self._current_task = None
self.returncode = packager.returncode
self.wait()
def _buildpkgonly_success_hook_exit(self, success_hooks):
self._default_exit(success_hooks)
self.returncode = None
# Need to call "clean" phase for buildpkgonly mode
portage.elog.elog_process(self.pkg.cpv, self.settings)
phase = 'clean'
clean_phase = EbuildPhase(background=self.background,
pkg=self.pkg, phase=phase,
scheduler=self.scheduler, settings=self.settings,
tree=self._tree)
self._start_task(clean_phase, self._clean_exit)
def _clean_exit(self, clean_phase):
if self._final_exit(clean_phase) != os.EX_OK or \
self.opts.buildpkgonly:
self._unlock_builddir()
self.wait()
def install(self):
"""
Install the package and then clean up and release locks.
Only call this after the build has completed successfully
and neither fetchonly nor buildpkgonly mode are enabled.
"""
find_blockers = self.find_blockers
ldpath_mtimes = self.ldpath_mtimes
logger = self.logger
pkg = self.pkg
pkg_count = self.pkg_count
settings = self.settings
world_atom = self.world_atom
ebuild_path = self._ebuild_path
tree = self._tree
merge = EbuildMerge(find_blockers=self.find_blockers,
ldpath_mtimes=ldpath_mtimes, logger=logger, pkg=pkg,
pkg_count=pkg_count, pkg_path=ebuild_path,
scheduler=self.scheduler,
settings=settings, tree=tree, world_atom=world_atom)
msg = " === (%s of %s) Merging (%s::%s)" % \
(pkg_count.curval, pkg_count.maxval,
pkg.cpv, ebuild_path)
short_msg = "emerge: (%s of %s) %s Merge" % \
(pkg_count.curval, pkg_count.maxval, pkg.cpv)
logger.log(msg, short_msg=short_msg)
try:
rval = merge.execute()
finally:
self._unlock_builddir()
return rval