# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

import functools

from _emerge.AsynchronousLock import AsynchronousLock

import portage
from portage import os
from portage.exception import PortageException
from portage.util.SlotObject import SlotObject

class EbuildBuildDir(SlotObject):

	__slots__ = ("scheduler", "settings",
		"locked", "_catdir", "_lock_obj")

	def __init__(self, **kwargs):
		SlotObject.__init__(self, **kwargs)
		self.locked = False

	def _assert_lock(self, async_lock):
		if async_lock.returncode != os.EX_OK:
			# TODO: create a better way to propagate this error to the caller
			raise AssertionError("AsynchronousLock failed with returncode %s" \
				% (async_lock.returncode,))

	def clean_log(self):
		"""Discard existing log. The log will not be be discarded
		in cases when it would not make sense, like when FEATURES=keepwork
		is enabled."""
		settings = self.settings
		if 'keepwork' in settings.features:
			return
		log_file = settings.get('PORTAGE_LOG_FILE')
		if log_file is not None and os.path.isfile(log_file):
			try:
				os.unlink(log_file)
			except OSError:
				pass

	def async_lock(self):
		"""
		Acquire the lock asynchronously. Notification is available
		via the add_done_callback method of the returned Future instance.

		This raises an AlreadyLocked exception if async_lock() is called
		while a lock is already held. In order to avoid this, call
		async_unlock() or check whether the "locked" attribute is True
		or False before calling async_lock().

		@returns: Future, result is None
		"""
		if self._lock_obj is not None:
			raise self.AlreadyLocked((self._lock_obj,))

		dir_path = self.settings.get('PORTAGE_BUILDDIR')
		if not dir_path:
			raise AssertionError('PORTAGE_BUILDDIR is unset')
		catdir = os.path.dirname(dir_path)
		self._catdir = catdir
		catdir_lock = AsynchronousLock(path=catdir, scheduler=self.scheduler)
		builddir_lock = AsynchronousLock(path=dir_path, scheduler=self.scheduler)
		result = self.scheduler.create_future()

		def catdir_locked(catdir_lock):
			try:
				self._assert_lock(catdir_lock)
			except AssertionError as e:
				result.set_exception(e)
				return

			try:
				portage.util.ensure_dirs(catdir,
					gid=portage.portage_gid,
					mode=0o70, mask=0)
			except PortageException as e:
				if not os.path.isdir(catdir):
					result.set_exception(e)
					return

			builddir_lock.addExitListener(builddir_locked)
			builddir_lock.start()

		def builddir_locked(builddir_lock):
			try:
				self._assert_lock(builddir_lock)
			except AssertionError as e:
				catdir_lock.async_unlock.add_done_callback(
					functools.partial(catdir_unlocked, exception=e))
				return

			self._lock_obj = builddir_lock
			self.locked = True
			self.settings['PORTAGE_BUILDDIR_LOCKED'] = '1'
			catdir_lock.async_unlock().add_done_callback(catdir_unlocked)

		def catdir_unlocked(future, exception=None):
			if not (exception is None and future.exception() is None):
				result.set_exception(exception or future.exception())
			else:
				result.set_result(None)

		try:
			portage.util.ensure_dirs(os.path.dirname(catdir),
				gid=portage.portage_gid,
				mode=0o70, mask=0)
		except PortageException:
			if not os.path.isdir(os.path.dirname(catdir)):
				raise

		catdir_lock.addExitListener(catdir_locked)
		catdir_lock.start()
		return result

	def async_unlock(self):
		"""
		Release the lock asynchronously. Release notification is available
		via the add_done_callback method of the returned Future instance.

		@returns: Future, result is None
		"""
		result = self.scheduler.create_future()

		def builddir_unlocked(future):
			if future.exception() is not None:
				result.set_exception(future.exception())
			else:
				self._lock_obj = None
				self.locked = False
				self.settings.pop('PORTAGE_BUILDDIR_LOCKED', None)
				catdir_lock = AsynchronousLock(
					path=self._catdir, scheduler=self.scheduler)
				catdir_lock.addExitListener(catdir_locked)
				catdir_lock.start()

		def catdir_locked(catdir_lock):
			if catdir_lock.wait() != os.EX_OK:
				result.set_result(None)
			else:
				try:
					os.rmdir(self._catdir)
				except OSError:
					pass
				catdir_lock.async_unlock().add_done_callback(catdir_unlocked)

		def catdir_unlocked(future):
			if future.exception() is None:
				result.set_result(None)
			else:
				result.set_exception(future.exception())

		if self._lock_obj is None:
			self.scheduler.call_soon(result.set_result, None)
		else:
			self._lock_obj.async_unlock().add_done_callback(builddir_unlocked)
		return result

	class AlreadyLocked(portage.exception.PortageException):
		pass

