"""
A simple non-interactive policy.

This module provides a simple policy that will select, download and run a suitable set of
implementations. It is not interactive. This is the policy used when you run B{0launch -c}, and
is also the policy used to run the injector's GUI.
"""

# Copyright (C) 2006, Thomas Leonard
# See the README file for details, or visit http://0install.net.

import os
from logging import debug, info

from zeroinstall.injector import model, policy, run, handler
from zeroinstall import NeedDownload

class AutoPolicy(policy.Policy):
	__slots__ = ['allow_downloads', 'download_only', 'dry_run']

	def __init__(self, interface_uri, download_only = False, dry_run = False, src = False):
		policy.Policy.__init__(self, interface_uri, handler.Handler(), src = src)
		self.dry_run = dry_run
		self.allow_downloads = not dry_run
		self.download_only = download_only
		self.dry_run = dry_run

	def need_download(self):
		"""Decide whether we need to download anything (but don't do it!)
		@return: true if we MUST download something (interfaces or implementations)
		@rtype: bool
		@postcondition: if we return False, self.stale_feeds contains any feeds which SHOULD be updated
		"""
		old = self.allow_downloads
		self.allow_downloads = False
		try:
			try:
				self.recalculate(fetch_stale_interfaces = False)
				debug("Recalculated: ready = %s; %d stale feeds", self.ready, len(self.stale_feeds))
				if not self.ready: return False
				self.start_downloading_impls()
			except NeedDownload:
				return True
			return False
		finally:
			self.allow_downloads = old
	
	def begin_iface_download(self, interface, force = False):
		if self.dry_run or not self.allow_downloads:
			raise NeedDownload(interface.uri)
		else:
			policy.Policy.begin_iface_download(self, interface, force)

	def start_downloading_impls(self):
		for iface, impl in self.get_uncached_implementations():
			debug("start_downloading_impls: for %s get %s", iface, impl)
			source = self.get_best_source(impl)
			if not source:
				raise model.SafeException("Implementation " + impl.id + " of "
					"interface " + iface.get_name() + " cannot be "
					"downloaded (no download locations given in "
					"interface!)")
			self.begin_impl_download(impl, source)

	def begin_archive_download(self, download_source, success_callback, force = False):
		if self.dry_run or not self.allow_downloads:
			raise NeedDownload(download_source.url)
		return policy.Policy.begin_archive_download(self, download_source, success_callback, force = force)

	def execute(self, prog_args, main = None, wrapper = None):
		self.start_downloading_impls()
		self.handler.wait_for_downloads()
		if not self.download_only:
			run.execute(self, prog_args, dry_run = self.dry_run, main = main, wrapper = wrapper)
		else:
			info("Downloads done (download-only mode)")
	
	def recalculate_with_dl(self):
		self.recalculate()
		while self.handler.monitored_downloads:
			self.handler.wait_for_downloads()
			self.recalculate()
	
	def download_and_execute(self, prog_args, refresh = False, main = None):
		self.recalculate_with_dl()
		if refresh:
			self.refresh_all(False)
			self.recalculate_with_dl()
		if not self.ready:
			raise model.SafeException("Can't find all required implementations:\n" +
				'\n'.join(["- %s -> %s" % (iface, self.implementation[iface])
					   for iface  in self.implementation]))
		self.execute(prog_args, main = main)


syntax highlighted by Code2HTML, v. 0.9.1