#!/usr/bin/env python

# ************************************************
#
# Python script for compiling and installing
# a KDE package.
#
# written by Lotzi Boloni, 2000, 2001
#
# ************************************************

import sys
import os
import re
import time
import pickle

## Configuration class

class Config:
    # these will be saved in the config file

    configfile = "~/.kdecompile"

    verbose = 1
    noOptimizations = 0
    useEnableFinal = 0
    installWithoutAsking = 0
    noDebug = 0
    removeAdminDir = 0
    RunConfigure = 1
    RunCVSCheckOut = 1
    RunCompile = 1
    installDir = "/opt/kde"
    cvsRoot = os.environ['CVSROOT']
    xmessage = "kmessage"
    kdepackages=["kdesupport", "kdelibs", "kdebase", "kdeutils",
                 "kdenetwork","kdemultimedia", "kdegraphics",
                 "kdepim", "kdeadmin", "kdebindings",
                 "kdetoys", "kdegames", "koffice",
                 "kdevelop", "kdesdk",
                 "quanta", "kdeartwork", "kdeaddons"
                ]

    # these wont
    packagename = ""

    def interactive(self):
        print "Interactive configuration. "
        print "Please answer the following questions:\n"
	sys.stdout.write("Your CVS access string ["+self.cvsRoot+"]:")
        x = sys.stdin.readline()
        if (x=="\n"):
            print "keep the old"
        else:
            self.cvsRoot = x[:-1]
            print self.cvsRoot
        

    def load(self):
	try:
	    filetoload = open(self.configfile)
	    configs = pickle.load(filetoload)
	    # print configs
	except:
	    print "Could not load config from "+self.configfile
	try:
	    self.noOptimizations = configs["noOptimizations"]
            self.useEnableFinal = configs["useEnableFinal"]
	    self.installWithoutAsking = configs["installWithoutAsking"]
	    self.noDebug = configs["noDebug"]
	    self.removeAdminDir = configs["removeAdminDir"]
	    self.RunConfigure = configs["RunConfigure"]
	    self.RunCVSCheckout = configs["RunCVSCheckout"]
	    self.installDir = configs["installDir"]
	    self.cvsRoot = configs["cvsRoot"]
	except:
	    print "Some fields were not present in the config file."
	    pass


    def save(self):
	configs = {}
	configs["noOptimizations"] = self.noOptimizations
        configs["useEnableFinal"] = self.useEnableFinal
	configs["installWithoutAsking"] = self.installWithoutAsking
	configs["noDebug"] = self.noDebug
	configs["removeAdminDir"] = self.removeAdminDir
	configs["RunConfigure"] = self.RunConfigure
	configs["RunCVSCheckout"] = self.RunCompile
	configs["installDir"] = self.installDir
	configs["cvsRoot"] = self.cvsRoot

	try:
            filetosave = open(self.configfile ,"w")
	    pickle.dump(configs, filetosave)
	except:
	    print "Could not save!"
	    pass

	print "Here comes the config"
	# sys.stdout.writeLines(configlist)



	# hmm? why do i need the z here
    def parseArguments(self):
        readpackage = 0
	for x in sys.argv[1:]:
	    if (x == "-h") or (x == "--help"):
		self.printHelp()
		sys.exit(0)
                continue
            if x == "-i":
                self.interactive()
                continue
	    if x == "--install":
		print "Will install without asking"
		self.installWithoutAsking = 1
                continue
	    if x == "-d":
		print "Will compile without debug info"
		self.noDebug = 1
                continue
	    if x == "--enable-final":
		print "\t-compile with enable final"
		self.useEnableFinal = 1
                continue
	    if x == "--disable-final":
		print "\t-compile without enable final"
		self.useEnableFinal = 1
                continue
	    if x == "-o":		
		print "Optimizations enabled"
		self.noOptimizations = 0
                continue
	    if x == "--remove-admin-dir":
		print "Will remove admin dir before cvs checkout"
		self.removeAdminDir = 1
                continue
	    if x == "--no-cvs-checkout":
		print "Will not do CVS checkout"
		self.RunCVSCheckOut = 0
                continue
	    if x == "--no-configure":
		print "Will not run configure"
		self.RunConfigure = 0
                continue
	    if x == "--disable-compile":
		print "Compilation disabled"
		self.RunCompile = 0
                continue
            self.packagename = x
            print "Package is:"+self.packagename

    def printHelp(self):
          print "\nSyntax: kdecompile [options] [packagename]"
	  print "\t-h, --help\t\tPrint this help"
	  print "\t--install\t\tInstall without asking"
	  print "\t-d\t\t\tDisable debug info"
	  print "\t-o\t\t\tEnable optimization"
	  print "\t-f\t\t\tCompile with --enable-final "
	  print "\t--remove-admin-dir\tRemove the admin dir before cvs checkout"
	  print "\t--no-cvs-checkout\tDo not do cvs checkout"
	  print "\t--no-configure\t\tDo not run configure"    
	  print "\t--disable-compile\tDo not compile"
          print ""

## end of configuration class 


#
#  Checking out the package from the cvs
#
def runCVSCheckOut(parentdir, packagename):
    # set the environment
    if (config.verbose):
        print "Checking out from the CVS"
    os.putenv ("CVSROOT", config.cvsRoot)
    currdir = os.getcwd()
    os.chdir(parentdir)
    # delete the admin dir
    if config.removeAdminDir:
        print "Removing the admin dir, as always makes problems..."
        value = os.system("rm -r "+packagename+"/admin")
        print "Done."
    value = os.system("cvs -q checkout "+packagename)
    if (value != 0):
        print "CVS checkout was not successfull."
	print "The compilation will continue in 10 seconds. "
	print "Press Ctrl-C now, if you don't want to continue."
	time.sleep(10)
	return 
    if (config.verbose):
        print "CVS checkout done."
    os.chdir(currdir)


#
#  The make Makefile.cvs  
#
def runAutoConf(parentdir):
    if (config.verbose):
        print "Doing the Makefile.cvs stuff"
    currdir = os.getcwd()
    os.chdir(parentdir)
    value = os.system("make -f Makefile.cvs")
    if (value != 0):
        print "Autoconf was not successful"
        exit(1);
    if (config.verbose):
        print "Makefile.cvs stuff done."
    os.chdir(currdir)


#
#  Running configure
#
def runConfigure(compiledir, packagename, kdedir="/opt/kde"):
    if (config.verbose):
        print "Running configure"
    currdir = os.getcwd()
    os.chdir(compiledir)
    commandline = "../../"+packagename+"/configure --prefix="+kdedir
    if config.noDebug:
	commandline = commandline + " --disable-debug"
    if config.useEnableFinal:
	commandline = commandline + " --enable-final"

    value = os.system(commandline)
    if (value != 0):
        print "Configuration was not successful. Aborting"
        sys.exit(1);
    if (config.verbose):
        print "Configuration was done."
    os.chdir(currdir)


#
#  This function removes the -02 from the makefiles
#
def runRemoveO2(compiledir):
    print "Removing the optimization from the makefiles"
    currdir = os.getcwd()
    os.chdir(compiledir)
    os.system("find . -name Makefile >listofmakefiles")
    listfile = open("listofmakefiles")
    #    makefiles = listfile.readlines()
    for x in listfile.readlines():
        currentfile = x[:-1]
        sedline = "sed s/-O2// %s >%s.2" % (currentfile , currentfile)
        #print sedline
        os.system(sedline)
        mvline = "cp %s.2 %s" % (currentfile, currentfile)
        #print mvline
        os.system(mvline)
    os.chdir(currdir)


#
#  Compiling the package
#
def runCompile(compiledir):
    if (config.verbose):
        print "Now compiling the package"
    currdir = os.getcwd()
    os.chdir(compiledir)
    value = os.system("make -k >logfile")
    if (value != 0):
        print "There was a compilation error."
    if (config.verbose):
        print "Compilation went fine."
    os.chdir(currdir)
    return value

#
#  Compiling the package in a separate thread
#
def runCompileThread(compiledir):
    if (config.verbose):
        print "Now compiling the package the multithread way"
    pid =0
    pid2 = 0
    pid = os.fork()
    os.chdir(compiledir)
    if (pid == 0):
        # the compilation thread
        currdir = os.getcwd()
        value = os.system("make -k >logfile 2>errorfile")
        if (value != 0):
            print "There was a compilation error."
            if (config.verbose):
                print "Compilation went fine."
                os.chdir(currdir)		
        sys.exit(0)
    else:
        pid2 = os.fork()
        if pid2 == 0:
            # the grep thread
            while 1:
                time.sleep(10)
                ParseLogfile()
        else:
            os.wait(pid,0)
            os.kill(pid2,9)

#
#   Parsing the logfile!!!
#
def ParseLogfile():
#  print "."
  try:
#      os.system("ls -l logfile* >x")
# using a fast system command to do most of the search for us.
      os.system("grep Leaving logfile >logfile.2")
      logfile = open("logfile.2", "r")
  except IOError:
      print "Cannot open logfile... "
      return
  except:
      print "Unexpected exception"
  searchstring = re.compile("Leaving directory")
  while 1:
      temp = logfile.readline()
      if temp == "":
          break      
      if searchstring.search(temp):
          #print temp
          fnd = re.compile("`.*'").search(temp)
          if (fnd):
             value = temp[fnd.start()+1:fnd.end()-1]
             #print value
             alreadythere = 0
             for a in compileddirs:
                 if a==value:
                     alreadythere = 1
                     break
             if alreadythere == 0:
                 compileddirs.append(value)
                 print "( %d / %d ) - compiled %s" % (len(compileddirs), len(compileDirsPre), value)
  logfile.close()

#
#  Count directories
#
def countDirs(cvsdir):
    if config.verbose:
        print "Reading the directories to compile..."
    currdir = os.getcwd()
    try:
	os.chdir(cvsdir)
    except:
	print "The source directory does not exists. We exit now because "
	print "the compilation will fail anyhow here."
	sys.exit(1)
# Fixme use tmp file here, or a pipe
    os.system("find -name Makefile.am >x")
    dirsfile = open("x", "r")
    countdirs = 0
    while 1:
        temp = dirsfile.readline()
        if temp == "":
            break      
        countdirs = countdirs+1
        compileDirsPre.append(temp[:-1])
    os.chdir(currdir)
    

#
#  Installing the package
#
def runInstall(compiledir):
    if (config.verbose):
        print "Now proceeding with the installation"
    currdir = os.getcwd()
    os.chdir(compiledir)
    value = os.system("make -k install >logfile.install")
    if (value != 0):
        print "There was a compilation error."
    if (config.verbose):
        print "Installation went fine."
    os.chdir(currdir)


#
#   Version
#
def version():
    return "kdecompile v.0.3.12 as of April 15, 2001"

#
#  Wrapper arount the creation of a directory
#
def createDir(dir):
    try:
        os.mkdir(dir)
    except:
        pass


#
#  Perform the compilation process
#
def doAll(packagename, currdir, cvsdir):
    createDir(currdir)
    if config.RunCVSCheckOut:
	runCVSCheckOut(cvsdir, packagename)
    if config.RunConfigure:
	runAutoConf(cvsdir+"/"+packagename)
    runConfigure(currdir, packagename, config.installDir)
    countDirs(cvsdir+"/"+packagename)
    if config.noOptimizations:
	runRemoveO2(currdir)
    #runCompile(currdir);
    if config.RunCompile:
	runCompileThread(currdir)
    else:
	print "Package "+packagename+" was checked out and configured"


#
#   Function for putting up a choice
#
def visualMessage(text):
   programs = ("kmessage", "xmessage")
   # xmess = config.xmessage
   execline = "kmessage"
   for execline in programs:
      messageline = execline + " "+text
      print messageline
      choice = os.system(messageline)
      if (choice != 32512): # seems this is what the shell says
         return choice
   print "\n\n"+text+"\n\n";
   #    system.beep()
   return 32512


#
# And here comes the main function
#

#visualMessage("Hello")
# system.exit(0)

print version()
config=Config()
# config.interactive()
compileddirs = []
compileDirsPre = []
config.load()
config.parseArguments()
config.save()

# find the directories

if config.packagename=="":
    # guess the packagename from the current dir
    currdir = os.getcwd()
    direlems = re.split("/", currdir)
    if (direlems[-2] != "compile"):
        print "You are not in the compile directory!"
        # let's attempt to move there:
        # FIXME: what if I am not in the source dir either?
        packagename = direlems[-1]

        try:
            config.kdepackages.index(packagename)
        except:
            visualMessage("You are neither in the compile, neither in the source directory!")
            sys.exit(1)
        temp = ""
        for x in direlems[1:-1]:
                temp = temp + "/"+x
        cvsdir = temp
        currdir = temp + "/compile/" + packagename
        print "currdir="+currdir + " cvsdir " + cvsdir
        try:
                os.chdir(currdir)
        except:
                createDir(currdir)
                os.chdir(currdir) # this time it must succeed
    else:
        newdir = direlems[1:-2] #+ direlems[-2:]
        cvsdir = ""
        packagename = direlems[-1]
        for x in newdir:
                cvsdir = cvsdir + "/"+x
else:
    packagename = config.packagename;
    currdir = os.getcwd()+"/"+packagename
    direlems = re.split("/", currdir)
    if (direlems[-2] != "compile") :
	print "You are not in the compile directory!"+currdir
	sys.exit(2)
    newdir = direlems[1:-2] #+ direlems[-2:]
    cvsdir = ""
    packagename = direlems[-1]
    for x in newdir:
	cvsdir = cvsdir + "/"+x



print "\n\nCompiling package: "+packagename
print "Compilation directory: "+currdir
print "Source directory: "+cvsdir
print "\n"

doAll(packagename, currdir, cvsdir)


logfile = open("../compile_log", "a+")
currenttime = time.strftime("%B %d, %Y %H:%M", time.localtime(time.time()))
logfile.write(packagename+" compiled on "+currenttime+"\n")
logfile.close();

if (config.installWithoutAsking):
    runInstall(currdir)
else:
     xmessline = "\"Compilation of " + packagename + " terminated\""
     choice = visualMessage(xmessline)
print "That's it for now."


