# GLINT graphical package management
# Copyright (C) 1995 Red Hat, Inc
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

import string
import os
import signal
from fcntl import *
import FCNTL

rherror = 'Error in rhutil'

# this is a mkdir that won't fail if a directory already exists and will
# happily make all of the directories leading up to it. However, it better

def rhmkdir(dir):
    if (os.path.isdir(dir)): return
    elements = string.splitfields(dir, "/")

    if (len(elements[0])):
	which = 1
	path = elements[0] 
    else:
	which = 2
	path = "/" + elements[1]

    if (not os.path.isdir(path)): 
	os.mkdir(path, 0755)

    while (which < len(elements)):
	path = path + "/" + elements[which]
	which = which + 1
	
	if (not os.path.isdir(path)): 
	    os.mkdir(path, 0755)

# does a fork, and (exec, wait)
# a lot like python's builtin, but it doesn't search the path which can be
# a security hole
def rhsystem(program, args, test = 0):
    args = (program,) + args
    if (test):
	print "exec of: ", program, args	
    else:
	childpid = os.fork()
	if (not childpid):
	    os.execv(program, (args))
	    raise rherror, "exec of " + program + " " + args + " failed"
	
	res = os.waitpid(childpid, 0)

# runs a program, and returns stdout and stderr as single strings
# the return code for the program is returned as well
def rhrun(program, args, callbackInfo = None, test = 0):
    global CHILDPID, CHILDSTATUS

    args = (program, ) + args
    if (test):
	print "running: ", program, args
    else:
	(stdoutOut, stdoutIn) = os.pipe()
	(stderrOut, stderrIn) = os.pipe()

	if (callbackInfo):
	    (callBack, cbArgs) = callbackInfo
	else:
	    callBack = None

	# set's the stdout and stderr pipes to be nonblocking
	fcntl(stdoutOut, FCNTL.F_SETFL, FCNTL.O_NONBLOCK)
	fcntl(stderrOut, FCNTL.F_SETFL, FCNTL.O_NONBLOCK)

	err = ""
	out = ""
	
	childpid = os.fork()
	if (not childpid):
	    os.close(stdoutOut)
	    os.close(stderrOut)
	    os.dup2(stdoutIn, 1)
	    os.dup2(stderrIn, 2)

	    os.execv(program, (args))
	    raise rherror, "exec of " + program + " " + args + " failed"

	os.close(stdoutIn)
	os.close(stderrIn)

	# Python doesn't support a proper wait() command (it still needs
	# WNOHANG). As a work around, grab SIGCHLD and set a pair of global 
	# variables when it's triggered. 

	signal.signal(signal.SIGCHLD, sigchildHandler)	

	CHILDPID = 0
	overflow = ""
	done = 0
	while (not done):
	    # putting this test inside the loop forces a final read after
	    # the child dies
	    if (CHILDPID == childpid):
		done = 1

	    try:
		s = ""
		s = os.read(stdoutOut, 10000)
		while (len(s)):
		    out = out + s
		    if (callBack):
			lines = string.splitfields(overflow + s, "\n")
			numLines = len(lines)
			count = 1
			for line in lines:
			    if (count == numLines):
				overflow = line
			    else:
				callBack(cbArgs, line)

			    count = count + 1
		    s = ""
		    s = os.read(stdoutOut, 10000)
			    
	    except os.error, message:
		s = ""
		(code, text) = message
		if (code != 11):
		    raise os.error, message

	    try:
		s = os.read(stderrOut, 10000)
		while (len(s)):
		    err = err + s
		    s = os.read(stderrOut, 10000)
	    except os.error, message:
		s = ""
		(code, text) = message
		if (code != 11):
		    raise os.error, message

	signal.signal(signal.SIGCHLD, signal.SIG_DFL)

	# if the last character is a newline, chop it off
	if (string.rfind(out, "\n") == (len(out) - 1)):
	    out = out[0:len(out) - 1]
	if (string.rfind(err, "\n") == (len(err) - 1)):
	    err = err[0:len(err) - 1]

	return (CHILDSTATUS, out, err)

    return (0, "", "")

def sigchildHandler(sig, frame):
    global CHILDPID, CHILDSTATUS

    (CHILDPID, CHILDSTATUS) = os.wait() 

def chop(string):
    string = string[0:len(string) - 1]
    return string
