#!/usr/bin/env python

""" The Commands Plus module

Usage instructions:

If you have used commands.getstatusoutput before, you probably know
it's a matter of impossibility to tell standard output from standard error
output in the return value of the function.  This module provides a
getstatusoutputerror function which returns the exit status, standard
output and standard error as separate items, therefore eliminating.
the known problem with getstatusoutput.

> import commandsplus

> print commandsplus.getstatusoutputerror("ls -lr")
(0,"something...","")
"""

__all__ = [ "shell_escape", "getstatusoutputerror" ]

def shell_escape(string):
	"""Return an escaped string suitable for passing as a parameter
	in a BASH shell command line.
	
	Say you have a file named "A*Teens - Mamma mia.mp3", with
	an actual asterisk in the name.  This should work properly:
	
	from commandsplus import shell_escape,getstatusoutputerror
	filename = "A*Teens - Mamma mia.mp3"
	print getstatusoutputerror("rm -f %s"%shell_escape(filename))
	"""
	unallowed_chars = "\$`\\\""
	deststring = ""
	
	for char in string:
		if char in unallowed_chars: newchar = "\\"+char
		else: newchar = char
		deststring = deststring + newchar
	return '"' + deststring + '"'
		
def getstatusoutputerror(cmd):
	"""See the getstatusoutput documentation in the
	commands module for a more through explanation
	of what this does.  In the meantime, think of this
	function as a getstatusoutput with the ability to
	return a separate standard error output.

	Note that standard output and standard error will
	have a final carriage return, if the invoked program
	emitted a final carriage return, which is usually the
	case with command line programs.  You will have to
	use the strip() method in the returned string if
	you want the behavior of bash backticks `ls -l` style
	"""

	import popen2
	from threading import Thread,currentThread
	object = popen2.Popen3(cmd,capturestderr=True)
	def getall(fileobject):
		currentThread().result = "".join(fileobject.readlines())
	stdout_t = Thread(target=getall,args=(object.fromchild,))
	stderr_t = Thread(target=getall,args=(object.childerr,))
	stdout_t.start()
	stderr_t.start()
	status = object.wait()
	stdout_t.join()
	stderr_t.join()
	return status,stdout_t.result,stderr_t.result