# Copyright 2010-2019 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

import tempfile

import portage
from portage import os
from portage import shutil
from portage.const import EBUILD_PHASES
from portage.elog import elog_process
from portage.package.ebuild.config import config
from portage.package.ebuild.doebuild import doebuild_environment
from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
from portage.util.futures import asyncio
from portage.util._async.SchedulerInterface import SchedulerInterface
from portage.util._eventloop.EventLoop import EventLoop
from portage.util._eventloop.global_event_loop import global_event_loop
from _emerge.CompositeTask import CompositeTask
from _emerge.EbuildPhase import EbuildPhase


class SpawnNofetchWithoutBuilddir(CompositeTask):
	"""
	This spawns pkg_nofetch if appropriate, while avoiding the
	need to lock a global build directory. The settings parameter
	is useful only if setcpv has already been called in order
	to cache metadata. It will be cloned internally, in order to
	prevent any changes from interfering with the calling code.
	If settings is None then a suitable config instance will be
	acquired from the given portdbapi instance. Do not use the
	settings parameter unless setcpv has been called on the given
	instance, since otherwise it's possible to trigger issues like
	bug #408817 due to fragile assumptions involving the config
	state inside doebuild_environment().

	A private PORTAGE_BUILDDIR will be created and cleaned up, in
	order to avoid any interference with any other processes.
	If PORTAGE_TMPDIR is writable, that will be used, otherwise
	the default directory for the tempfile module will be used.

	We only call the pkg_nofetch phase if either RESTRICT=fetch
	is set or the package has explicitly overridden the default
	pkg_nofetch implementation. This allows specialized messages
	to be displayed for problematic packages even though they do
	not set RESTRICT=fetch (bug #336499).

	This class does nothing if the PORTAGE_PARALLEL_FETCHONLY
	variable is set in the config instance.
	"""
	__slots__ = ('ebuild_path', 'fd_pipes', 'portdb', 'settings',
		'_private_tmpdir')

	def _start(self):
		settings = self.settings
		if settings is None:
			settings = self.portdb.settings

		if 'PORTAGE_PARALLEL_FETCHONLY' in settings:
			# parallel-fetch mode
			self.returncode = os.EX_OK
			self._async_wait()
			return

		# Prevent temporary config changes from interfering
		# with config instances that are reused.
		settings = self.settings = config(clone=settings)

		# We must create our private PORTAGE_TMPDIR before calling
		# doebuild_environment(), since lots of variables such
		# as PORTAGE_BUILDDIR refer to paths inside PORTAGE_TMPDIR.
		portage_tmpdir = settings.get('PORTAGE_TMPDIR')
		if not portage_tmpdir or not os.access(portage_tmpdir, os.W_OK):
			portage_tmpdir = None
		private_tmpdir = self._private_tmpdir = tempfile.mkdtemp(
			dir=portage_tmpdir)
		settings['PORTAGE_TMPDIR'] = private_tmpdir
		settings.backup_changes('PORTAGE_TMPDIR')
		# private temp dir was just created, so it's not locked yet
		settings.pop('PORTAGE_BUILDDIR_LOCKED', None)

		doebuild_environment(self.ebuild_path, 'nofetch',
			settings=settings, db=self.portdb)
		restrict = settings['PORTAGE_RESTRICT'].split()
		defined_phases = settings['DEFINED_PHASES'].split()
		if not defined_phases:
			# When DEFINED_PHASES is undefined, assume all
			# phases are defined.
			defined_phases = EBUILD_PHASES

		if 'fetch' not in restrict and \
			'nofetch' not in defined_phases:
			self.returncode = os.EX_OK
			self._async_wait()
			return

		prepare_build_dirs(settings=settings)

		ebuild_phase = EbuildPhase(background=self.background,
			phase='nofetch',
			scheduler=self.scheduler,
			fd_pipes=self.fd_pipes, settings=settings)

		self._start_task(ebuild_phase, self._nofetch_exit)

	def _nofetch_exit(self, ebuild_phase):
		self._final_exit(ebuild_phase)
		elog_process(self.settings.mycpv, self.settings)
		shutil.rmtree(self._private_tmpdir)
		self._async_wait()


def spawn_nofetch(portdb, ebuild_path, settings=None, fd_pipes=None):
	"""
	Create a NofetchPrivateTmpdir instance, and execute it synchronously.
	This function must not be called from asynchronous code, since it will
	trigger event loop recursion which is incompatible with asyncio.
	"""
	nofetch = SpawnNofetchWithoutBuilddir(background=False,
		portdb=portdb,
		ebuild_path=ebuild_path,
		scheduler=SchedulerInterface(asyncio._safe_loop()),
		fd_pipes=fd_pipes, settings=settings)

	nofetch.start()
	return nofetch.wait()
