# Copyright 1999-2009 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id: EbuildFetcher.py 14530 2009-10-09 20:28:30Z zmedico $

from _emerge.SpawnProcess import SpawnProcess
from _emerge.EbuildBuildDir import EbuildBuildDir
import sys
import portage
from portage import os
from portage import _encodings
from portage import _unicode_encode
import codecs
from portage.elog.messages import eerror

class EbuildFetcher(SpawnProcess):

	__slots__ = ("config_pool", "fetchonly", "fetchall", "pkg", "prefetch") + \
		("_build_dir",)

	def _start(self):

		root_config = self.pkg.root_config
		portdb = root_config.trees["porttree"].dbapi
		ebuild_path = portdb.findname(self.pkg.cpv)
		if ebuild_path is None:
			raise AssertionError("ebuild not found for '%s'" % self.pkg.cpv)
		settings = self.config_pool.allocate()
		settings.setcpv(self.pkg)

		# In prefetch mode, logging goes to emerge-fetch.log and the builddir
		# should not be touched since otherwise it could interfere with
		# another instance of the same cpv concurrently being built for a
		# different $ROOT (currently, builds only cooperate with prefetchers
		# that are spawned for the same $ROOT).
		if not self.prefetch:
			self._build_dir = EbuildBuildDir(pkg=self.pkg, settings=settings)
			self._build_dir.lock()
			self._build_dir.clean_log()
			portage.prepare_build_dirs(self.pkg.root, self._build_dir.settings, 0)
			if self.logfile is None:
				self.logfile = settings.get("PORTAGE_LOG_FILE")

		phase = "fetch"
		if self.fetchall:
			phase = "fetchall"

		# If any incremental variables have been overridden
		# via the environment, those values need to be passed
		# along here so that they are correctly considered by
		# the config instance in the subproccess.
		fetch_env = os.environ.copy()

		nocolor = settings.get("NOCOLOR")
		if nocolor is not None:
			fetch_env["NOCOLOR"] = nocolor

		fetch_env["PORTAGE_NICENESS"] = "0"
		if self.prefetch:
			fetch_env["PORTAGE_PARALLEL_FETCHONLY"] = "1"

		ebuild_binary = os.path.join(
			settings["PORTAGE_BIN_PATH"], "ebuild")

		fetch_args = [ebuild_binary, ebuild_path, phase]
		debug = settings.get("PORTAGE_DEBUG") == "1"
		if debug:
			fetch_args.append("--debug")

		if not self.background and nocolor not in ('yes', 'true'):
			# Force consistent color output, in case we are capturing fetch
			# output through a normal pipe due to unavailability of ptys.
			fetch_args.append('--color=y')

		self.args = fetch_args
		self.env = fetch_env
		SpawnProcess._start(self)

	def _pipe(self, fd_pipes):
		"""When appropriate, use a pty so that fetcher progress bars,
		like wget has, will work properly."""
		if self.background or not sys.stdout.isatty():
			# When the output only goes to a log file,
			# there's no point in creating a pty.
			return os.pipe()
		stdout_pipe = fd_pipes.get(1)
		got_pty, master_fd, slave_fd = \
			portage._create_pty_or_pipe(copy_term_size=stdout_pipe)
		return (master_fd, slave_fd)

	def _set_returncode(self, wait_retval):
		SpawnProcess._set_returncode(self, wait_retval)
		# Collect elog messages that might have been
		# created by the pkg_nofetch phase.
		if self._build_dir is not None:
			# Skip elog messages for prefetch, in order to avoid duplicates.
			if not self.prefetch and self.returncode != os.EX_OK:
				elog_out = None
				if self.logfile is not None:
					if self.background:
						elog_out = codecs.open(_unicode_encode(self.logfile,
							encoding=_encodings['fs'], errors='strict'),
							mode='a', encoding=_encodings['content'], errors='replace')
				msg = "Fetch failed for '%s'" % (self.pkg.cpv,)
				if self.logfile is not None:
					msg += ", Log file:"
				eerror(msg, phase="unpack", key=self.pkg.cpv, out=elog_out)
				if self.logfile is not None:
					eerror(" '%s'" % (self.logfile,),
						phase="unpack", key=self.pkg.cpv, out=elog_out)
				if elog_out is not None:
					elog_out.close()
			if not self.prefetch:
				portage.elog.elog_process(self.pkg.cpv, self._build_dir.settings)
			features = self._build_dir.settings.features
			if self.returncode == os.EX_OK:
				self._build_dir.clean_log()
			self._build_dir.unlock()
			self.config_pool.deallocate(self._build_dir.settings)
			self._build_dir = None

