# Copyright 2010-2011 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

import array
import fcntl
import platform
import pty
import select
import sys
import termios

from portage import os, _unicode_decode, _unicode_encode
from portage.output import get_term_size, set_term_size
from portage.process import spawn_bash
from portage.util import writemsg

def _can_test_pty_eof():
	"""
	The _test_pty_eof() function seems to hang on most
	kernels other than Linux.
	This was reported for the following kernels which used to work fine
	without this EOF test: Darwin, AIX, FreeBSD.  They seem to hang on
	the slave_file.close() call.  Note that Python's implementation of
	openpty on Solaris already caused random hangs without this EOF test
	and hence is globally disabled.
	@rtype: bool
	@returns: True if _test_pty_eof() won't hang, False otherwise.
	"""
	return platform.system() in ("Linux",)

def _test_pty_eof(fdopen_buffered=False):
	"""
	Returns True if this issues is fixed for the currently
	running version of python: http://bugs.python.org/issue5380
	Raises an EnvironmentError from openpty() if it fails.

	NOTE: This issue is only problematic when array.fromfile()
	is used, rather than os.read(). However, array.fromfile()
	is preferred since it is approximately 10% faster.

	New development: It appears that array.fromfile() is usable
	with python3 as long as fdopen is called with a bufsize
	argument of 0.
	"""

	use_fork = False

	test_string = 2 * "blah blah blah\n"
	test_string = _unicode_decode(test_string,
		encoding='utf_8', errors='strict')

	# may raise EnvironmentError
	master_fd, slave_fd = pty.openpty()

	# Non-blocking mode is required for Darwin kernel.
	fcntl.fcntl(master_fd, fcntl.F_SETFL,
		fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)

	# Disable post-processing of output since otherwise weird
	# things like \n -> \r\n transformations may occur.
	mode = termios.tcgetattr(slave_fd)
	mode[1] &= ~termios.OPOST
	termios.tcsetattr(slave_fd, termios.TCSANOW, mode)

	# Simulate a subprocess writing some data to the
	# slave end of the pipe, and then exiting.
	pid = None
	if use_fork:
		pids = spawn_bash(_unicode_encode("echo -n '%s'" % test_string,
			encoding='utf_8', errors='strict'), env=os.environ,
			fd_pipes={0:sys.stdin.fileno(), 1:slave_fd, 2:slave_fd},
			returnpid=True)
		if isinstance(pids, int):
			os.close(master_fd)
			os.close(slave_fd)
			raise EnvironmentError('spawn failed')
		pid = pids[0]
	else:
		os.write(slave_fd, _unicode_encode(test_string,
			encoding='utf_8', errors='strict'))
	os.close(slave_fd)

	# If using a fork, we must wait for the child here,
	# in order to avoid a race condition that would
	# lead to inconsistent results.
	if pid is not None:
		os.waitpid(pid, 0)

	if fdopen_buffered:
		master_file = os.fdopen(master_fd, 'rb')
	else:
		master_file = os.fdopen(master_fd, 'rb', 0)
	eof = False
	data = []
	iwtd = [master_file]
	owtd = []
	ewtd = []

	while not eof:

		events = select.select(iwtd, owtd, ewtd)
		if not events[0]:
			eof = True
			break

		buf = array.array('B')
		try:
			buf.fromfile(master_file, 1024)
		except (EOFError, IOError):
			eof = True

		if not buf:
			eof = True
		else:
			data.append(_unicode_decode(buf.tostring(),
				encoding='utf_8', errors='strict'))

	master_file.close()

	return test_string == ''.join(data)

# If _test_pty_eof() can't be used for runtime detection of
# http://bugs.python.org/issue5380, openpty can't safely be used
# unless we can guarantee that the current version of python has
# been fixed (affects all current versions of python3). When
# this issue is fixed in python3, we can add another sys.hexversion
# conditional to enable openpty support in the fixed versions.
if sys.hexversion >= 0x3000000 and not _can_test_pty_eof():
	_disable_openpty = True
else:
	# Disable the use of openpty on Solaris as it seems Python's openpty
	# implementation doesn't play nice on Solaris with Portage's
	# behaviour causing hangs/deadlocks.
	# Additional note for the future: on Interix, pipes do NOT work, so
	# _disable_openpty on Interix must *never* be True
	_disable_openpty = platform.system() in ("SunOS",)
_tested_pty = False

if not _can_test_pty_eof():
	# Skip _test_pty_eof() on systems where it hangs.
	_tested_pty = True

_fbsd_test_pty = platform.system() == 'FreeBSD'

def _create_pty_or_pipe(copy_term_size=None):
	"""
	Try to create a pty and if then fails then create a normal
	pipe instead.

	@param copy_term_size: If a tty file descriptor is given
		then the term size will be copied to the pty.
	@type copy_term_size: int
	@rtype: tuple
	@returns: A tuple of (is_pty, master_fd, slave_fd) where
		is_pty is True if a pty was successfully allocated, and
		False if a normal pipe was allocated.
	"""

	got_pty = False

	global _disable_openpty, _fbsd_test_pty, _tested_pty
	if not (_tested_pty or _disable_openpty):
		try:
			if not _test_pty_eof():
				_disable_openpty = True
		except EnvironmentError as e:
			_disable_openpty = True
			writemsg("openpty failed: '%s'\n" % str(e),
				noiselevel=-1)
			del e
		_tested_pty = True

	if _fbsd_test_pty and not _disable_openpty:
		# Test for python openpty breakage after freebsd7 to freebsd8
		# upgrade, which results in a 'Function not implemented' error
		# and the process being killed.
		pid = os.fork()
		if pid == 0:
			pty.openpty()
			os._exit(os.EX_OK)
		pid, status = os.waitpid(pid, 0)
		if (status & 0xff) == 140:
			_disable_openpty = True
		_fbsd_test_pty = False

	if _disable_openpty:
		master_fd, slave_fd = os.pipe()
	else:
		try:
			master_fd, slave_fd = pty.openpty()
			got_pty = True
		except EnvironmentError as e:
			_disable_openpty = True
			writemsg("openpty failed: '%s'\n" % str(e),
				noiselevel=-1)
			del e
			master_fd, slave_fd = os.pipe()

	if got_pty:
		# Disable post-processing of output since otherwise weird
		# things like \n -> \r\n transformations may occur.
		mode = termios.tcgetattr(slave_fd)
		mode[1] &= ~termios.OPOST
		termios.tcsetattr(slave_fd, termios.TCSANOW, mode)

	if got_pty and \
		copy_term_size is not None and \
		os.isatty(copy_term_size):
		rows, columns = get_term_size()
		set_term_size(rows, columns, slave_fd)

	return (got_pty, master_fd, slave_fd)
