Files
entropy/libraries/enzymeTools.py
2007-08-13 16:44:41 +00:00

1209 lines
45 KiB
Python

#!/usr/bin/python
'''
# DESCRIPTION:
# generic tools for enzyme application
Copyright (C) 2007 Fabio Erculiani
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
'''
# Never do "import portage" here, please use entropyTools binding
from portageTools import *
from entropyConstants import *
from serverConstants import *
from entropyTools import *
import sys
import os
import commands
import string
# Logging initialization
import logTools
enzymeLog = logTools.LogFile(level=etpConst['enzymeloglevel'],filename = etpConst['enzymelogfile'], header = "[Enzyme]")
# example: enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"testFuncton: called.")
# EXIT STATUSES: 200-299
def getSyncTime():
"""gets and returns the timestamp info saved during
the last portage tree sync"""
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"getSyncTime: called.")
lastSync = None
try:
f = open(etpConst['portagetreedir'] + "/metadata/timestamp")
data = f.read()
f.close()
if data:
try:
lastSync = (str(data).decode('utf_8').encode("utf_8",'replace'))
except:
try:
lastSync = (str(data).decode('iso-8859-1').encode('utf_8', 'replace'))
except:
print_warning("getSyncTime(): unknown encoding")
else:
print_warning("getSyncTime(): nothing to read")
except:
print_warning("getSyncTime(): empty Portage tree (first run?) or no timestamp to read")
# NOTE: this function does not directly check if
# layman is installed !!!!
def listOverlays():
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"listOverlays: called.")
lst = etpConst['overlays'].split()
return lst
# fetch the latest updates from Gentoo rsync mirrors
def sync(options):
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"sync: called with options -> "+str(options))
myopts = options[1:]
enzymeNoSyncBack = True
enzymeOnlySyncBack = False
enzymeNoOverlaySync = False
syncMiscRedirect = "> /dev/null"
# check if rsync is installed
rsync = commands.getoutput("which rsync")
if (not rsync.startswith("/")):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"sync: rsync not found.")
print_error(red(bold("net-misc/rsync is not installed. Please install.")))
sys.exit(200)
for i in myopts:
if ( i == "--verbose" ) or ( i == "-v" ):
syncMiscRedirect = None
elif ( i == "--sync-back" ):
enzymeNoSyncBack = False
elif ( i == "--only-sync-back" ):
enzymeOnlySyncBack = True
elif ( i == "--no-overlay-sync" ):
enzymeNoOverlaySync = True
if (not enzymeOnlySyncBack):
print_info(green("Syncing Entropy Portage Tree at: "+etpConst['portagetreedir']))
rc = spawnCommand(vdbPORTDIR+"="+etpConst['portagetreedir']+" "+cdbEMERGE+" --sync ", redirect = syncMiscRedirect) # redirect = "/dev/null"
if (rc != 0):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"sync: an error occoured while syncing the Portage tree. Are you sure that your Internet connection works?")
print_error(red("an error occoured while syncing the Portage tree. Are you sure that your Internet connection works?"))
sys.exit(201)
if (not enzymeNoOverlaySync):
# syncing overlays
rc = overlay(['overlay','sync'])
if (not rc):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"sync: an error occoured while syncing the overlays. Please check if it's all fine.")
print_warning(red("an error occoured while syncing the overlays. Please check if it's all fine."))
else:
print_info(green("Not syncing Entropy Portage Tree at: "+etpConst['portagetreedir']))
if (not enzymeNoSyncBack):
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"sync: Syncing back Entropy Portage Tree at: "+etpConst['portagetreedir']+" to the official Portage Tree.")
print_info(green("Syncing back Entropy Portage Tree at: ")+bold(etpConst['portagetreedir'])+green(" to the official Portage Tree"))
# sync back to /usr/portage, but firstly, get user's PORTDIR
if os.path.isfile("/etc/make.conf"):
f = open("/etc/make.conf","r")
makeConf = f.readlines()
f.close()
officialPortageTreeDir = "/usr/portage"
for line in makeConf:
if line.startswith("PORTDIR="):
# found it !
line = line.strip()
officialPortageTreeDir = line.split('PORTDIR=')[1]
# remove quotes
if officialPortageTreeDir.startswith('"') and officialPortageTreeDir.endswith('"'):
officialPortageTreeDir = officialPortageTreeDir.split('"')[1]
if officialPortageTreeDir.startswith("'") and officialPortageTreeDir.endswith("'"):
officialPortageTreeDir = officialPortageTreeDir.split("'")[1]
else:
officialPortageTreeDir = "/usr/portage"
# officialPortageTreeDir must not end with /
if officialPortageTreeDir.endswith("/"):
officialPortageTreeDir = officialPortageTreeDir[:len(officialPortageTreeDir)-1]
# sync back
# FIXME: anything better?
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"sync: spawning rsync...")
rc = spawnCommand("rsync --recursive --links --safe-links --perms --times --force --whole-file --delete --delete-after --exclude=/distfiles --exclude=/packages "+etpConst['portagetreedir']+" "+officialPortageTreeDir, redirect = syncMiscRedirect)
if (rc != 0):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"sync: an error occoured while syncing back the official Portage Tree.")
print_error(red("an error occoured while syncing back the official Portage Tree."))
sys.exit(201)
def build(atoms):
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"build: called with parameters -> "+str(atoms))
enzymeRequestVerbose = False
enzymeRequestForceRepackage = False
enzymeRequestForceRebuild = False
enzymeRequestDeep = False
enzymeRequestNodeps = False
enzymeRequestUse = False
enzymeRequestPretendAll = False
enzymeRequestAsk = False
enzymeRequestIgnoreConflicts = False
enzymeRequestInteraction = True
enzymeRequestSimulation = False
enzymeRequestSkipfirst = False
enzymeRequestSkipN = False
enzymeRequestNoSync = False
_atoms = []
for i in atoms:
if ( i == "--verbose" ) or ( i == "-v" ):
enzymeRequestVerbose = True
elif ( i == "--force-repackage" ):
enzymeRequestForceRepackage = True
elif ( i == "--force-rebuild" ):
enzymeRequestForceRebuild = True
elif ( i == "--ignore-conflicts" ):
enzymeRequestIgnoreConflicts = True
elif ( i == "--pretend" ):
enzymeRequestPretendAll = True
elif ( i == "--nodeps" ):
enzymeRequestNodeps = True
elif ( i == "--ask" ):
enzymeRequestAsk = True
elif ( i == "--deep" ):
enzymeRequestDeep = True
enzymeRequestForceRebuild = True
elif ( i == "--use" ):
enzymeRequestUse = True
elif ( i == "--nosync" ):
enzymeRequestNoSync = True
elif ( i == "--skipfirst" ):
enzymeRequestSkipfirst = True
elif ( i.startswith("--skip=") ):
enzymeRequestSkipN = True
skip_number = i.split("--skip=")[len(i.split("--skip="))-1]
try:
skipN = int(skip_number)
except:
skipN = 1
elif ( i == "--no-interaction" ):
enzymeRequestInteraction = False
elif ( i == "--simulate-building" ):
enzymeRequestSimulation = True
else:
_atoms.append(i)
atoms = _atoms
validAtoms = []
for i in atoms:
if (enzymeRequestVerbose): print_info(i+" is valid?: "+str(checkAtom(i)))
if (checkAtom(i)):
validAtoms.append(i)
else:
enzymeLog.log(ETP_LOGPRI_WARNING,ETP_LOGLEVEL_NORMAL,"build: "+str(i)+" -> is not a valid atom, it's masked or its name conflicts with something else.")
print_warning(red("* >>> ")+yellow(i)+" is not a valid atom, it's masked or its name conflicts with something else.")
if getBestAtom(i) == "!!conflicts":
# it conflicts with something
enzymeLog.log(ETP_LOGPRI_WARNING,ETP_LOGLEVEL_NORMAL,"build: "+str(i)+" -> Ambiguous package name. Please add category.")
print_warning(red("* ^^^ ")+"Ambiguous package name. Please add category.")
if validAtoms == []:
print_error(red(bold("no valid package names specified.")))
sys.exit(202)
# resolve atom name with the best package available
_validAtoms = []
for i in validAtoms:
_validAtoms.append(getBestAtom(i))
validAtoms = _validAtoms
buildCmd = None
toBeBuilt = []
PackagesDependencies = []
PackagesConflicting = []
PackagesQuickpkg = []
if (not enzymeRequestNodeps) and (not enzymeRequestIgnoreConflicts):
# Check if a .tbz2 has already been done
# control if --force-rebuild or --force-repackage has been provided
# and filter the packages list accordingly to line 1
for atom in validAtoms:
# let's dance !!
isAvailable = getInstalledAtom("="+atom)
if (enzymeRequestVerbose): print_info("testing atom: "+atom)
if (isAvailable is not None) and (not enzymeRequestForceRepackage):
# package is available on the system
if (enzymeRequestVerbose): print_info("I'd like to keep a current copy of binary package "+atom+" but first I need to check if even this step has been already done")
tbz2Available = isTbz2PackageAvailable(atom, enzymeRequestVerbose)
if (tbz2Available == False) or (enzymeRequestForceRebuild):
if (enzymeRequestVerbose): print_info("Adding "+bold(atom)+" to the build list")
toBeBuilt.append(atom)
else:
# no action needed, but showing for consistence
PackagesQuickpkg.append("avail|"+atom)
if (enzymeRequestVerbose): print_info("This "+bold(atom)+" has already been built here: "+tbz2Available)
else:
if (enzymeRequestVerbose): print_info("I have to compile or quickpkg "+atom+" by myself...")
toBeBuilt.append(atom)
# Check if they conflicts each others
if len(toBeBuilt) > 1:
cleanatomlist = []
for atom in toBeBuilt:
if (not atom.startswith(">")) and (not atom.startswith("<")) and (not atom.startswith("~")) and (not atom.startswith("=")) and (not isjustname(atom)):
cleanatomlist.append("="+atom)
else:
cleanatomlist.append(atom)
atoms = string.join(cleanatomlist," ")
else:
if atoms[0].startswith(">") or atoms[0].startswith("<") or atoms[0].startswith("~") or atoms[0].startswith("=") or isjustname(atoms[0]):
atoms = atoms[0]
else:
atoms = "="+atoms[0]
if (not enzymeRequestForceRepackage):
print_info(green(" Checking packages..."))
atomdeps, atomconflicts = calculateFullAtomsDependencies(atoms,enzymeRequestDeep)
for conflict in atomconflicts:
if getInstalledAtom(conflict) is not None:
# damn, it's installed
PackagesConflicting.append(conflict)
if PackagesConflicting != []:
print_info(red(" *")+" These are the conflicting packages:")
for i in PackagesConflicting:
print_warning(red(" *")+bold(" [CONFL] ")+i)
if (not enzymeRequestIgnoreConflicts):
print_error(red(" ***")+" Sorry, I can't continue. To force this, add --ignore-conflicts at your own risk.")
sys.exit(101)
else:
import time
print_warning((" ***")+" You are using --ignore-conflicts at your own risk.")
time.sleep(5)
else:
toBeBuilt = validAtoms
for atom in toBeBuilt:
print_info(" Analyzing package "+bold(atom)+" ...",back = True)
if (not enzymeRequestNodeps): atomdeps, atomconflicts = calculateFullAtomsDependencies("="+atom,enzymeRequestDeep)
if(enzymeRequestVerbose): print_info(" Analyzing package: "+bold(atom))
if(enzymeRequestVerbose):
if (getPackageSlot("="+atom) is None):
print_info(" Current installed release: "+bold(str(getInstalledAtom(dep_getkey(atom)))))
else:
print_info(" Current installed release: "+bold(str(getInstalledAtom("="+atom))))
if(enzymeRequestVerbose): print_info("\tfiltering "+atom+" related packages...")
if (not enzymeRequestNodeps):
for dep in atomdeps:
dep = dep.split()[0]
dep = "="+dep
if(enzymeRequestVerbose): print_info("\tchecking for: "+red(dep[1:]))
wantedAtom = getBestAtom(dep)
if(enzymeRequestVerbose): print_info("\t\tI want: "+yellow(wantedAtom))
if (getPackageSlot(dep) is None):
installedAtom = getInstalledAtom(dep_getkey(dep))
else:
installedAtom = getInstalledAtom(dep)
if(enzymeRequestVerbose): print_info("\t\tIs installed: "+green(str(installedAtom)))
if ( installedAtom is None ) or (enzymeRequestForceRebuild):
# then append - because it's not installed !
if(enzymeRequestVerbose) and (installedAtom is None): print_info("\t\t"+dep+" is not installed, adding")
if(enzymeRequestVerbose) and (enzymeRequestForceRebuild): print_info("\t\t"+dep+" - rebuild forced")
PackagesDependencies.append(dep[1:])
else:
if (wantedAtom == installedAtom):
if (isTbz2PackageAvailable(installedAtom) == False) or (enzymeRequestForceRepackage):
PackagesQuickpkg.append("quick|"+installedAtom)
if(enzymeRequestVerbose) and (enzymeRequestForceRepackage): print_info("\t\t"+dep+" versions match, repackaging")
if(enzymeRequestVerbose) and (not enzymeRequestForceRepackage): print_info("\t\t"+dep+" versions match, adding to the quickpkg list")
else:
# adding to the build list
if(enzymeRequestVerbose): print_info("\t\t"+dep+" versions not match, adding")
PackagesDependencies.append(dep[1:])
# Clean out toBeBuilt by removing entries that are in PackagesQuickpkg
_toBeBuilt = []
for i in toBeBuilt:
_tbbfound = False
for x in PackagesQuickpkg:
if (i == x):
_tbbfound = True
if (not _tbbfound):
_toBeBuilt.append(i)
toBeBuilt = _toBeBuilt
else:
PackagesDependencies = toBeBuilt
if (PackagesDependencies != []) or (PackagesQuickpkg != []):
# workout the skipfirst and skip=N request
_PackagesDependencies = PackagesDependencies
if (enzymeRequestSkipfirst):
_PackagesDependencies = _PackagesDependencies[1:]
elif (enzymeRequestSkipN):
_PackagesDependencies = _PackagesDependencies[skipN:]
PackagesDependencies = _PackagesDependencies
# Filter duplicates without messing the order
#print PackagesDependencies
PackagesDependencies = filterDuplicatedEntries(PackagesDependencies)
#print PackagesDependencies
ebuildOverlays = []
overlaysCounter = 1
print_info(yellow(" *")+" These are the actions that will be taken, in order:")
for i in PackagesDependencies:
useflags = ""
if enzymeRequestUse: useflags = bold(" [")+yellow("USE: ")+calculateAtomUSEFlags("="+i)+bold("]")
pkgstatus = "[?]"
if (getPackageSlot("="+i) is None):
pkg = dep_getkey(i)
slotprintout = " "
else:
pkg = "="+i
slotprintout = "S"
if (getInstalledAtom(pkg) == None):
pkgstatus = green("[N"+slotprintout+"]")
elif (compareAtoms(i,getInstalledAtom(pkg)) == 0):
pkgstatus = yellow("[R"+slotprintout+"]")
elif (compareAtoms(i,getInstalledAtom(pkg)) > 0):
# check if the package is slotted
pkgstatus = blue("[U"+slotprintout+"]")
elif (compareAtoms(i,getInstalledAtom(pkg)) < 0):
pkgstatus = darkblue("[D"+slotprintout+"]")
# from which place?
overlayinfo = ""
myEbuildPath = getEbuildTreePath(i)
for overlay in etpConst['overlays'].split():
if myEbuildPath.startswith(overlay):
overlayinfo = blue("[overlay: ")+bold(str(overlaysCounter))+blue(" ]")
# overlay found
# find an associable number
for x in ebuildOverlays:
if x.find(overlay) == -1:
overlaysCounter += 1
ebuildOverlays.append(str(overlaysCounter)+" "+overlay)
print_info(red(" *")+bold(" [")+red("BUILD")+bold("] ")+pkgstatus+" "+i+useflags+" "+overlayinfo)
for i in PackagesQuickpkg:
useflags = ""
if enzymeRequestUse: useflags = bold(" [")+yellow("USE: ")+calculateAtomUSEFlags("="+i)+bold("]")
if i.startswith("quick|"):
print_info(green(" *")+bold(" [")+green("QUICK")+bold("] ")+yellow("[R ] ") +i.split("quick|")[len(i.split("quick|"))-1])
elif i.startswith("avail|"):
print_info(yellow(" *")+bold(" [")+yellow("NOACT")+bold("] ")+yellow("[R ] ")+i.split("avail|")[len(i.split("avail|"))-1])
else:
# I should never get here
print_info(green(" *")+bold(" [?????] ")+i+useflags)
ebuildOverlays = list(set(ebuildOverlays))
if (ebuildOverlays != []):
print_info("")
print_info(" Overlays legend:")
for ov in ebuildOverlays:
print_info(" ["+bold(ov.split()[0])+"] "+blue(ov.split()[1]))
else:
print_info(green(" *")+" Nothing to do...")
if (enzymeRequestPretendAll):
sys.exit(0)
elif (enzymeRequestAsk):
rc = askquestion("\n Would you like to run the steps above ?")
if rc == "No":
sys.exit(0)
# sync binary packages repository
if (not enzymeRequestNoSync):
import activatorTools
if (enzymeRequestInteraction):
activatorTools.packages(["sync" , "--ask"])
else:
activatorTools.packages(["sync"])
# when the compilation ends, enzyme runs reagent
packagesPaths = []
# filter duplicates from PackagesDependencies
# FIXME, it changes the dependency order, filtering for now
#PackagesDependencies = list(set(PackagesDependencies))
compileError = False
PackagesDependenciesCounter = 0
PackagesDependenciesLength = len(PackagesDependencies)
if PackagesDependencies != []:
#print
print_info(yellow(" *")+" Building packages...")
for dep in PackagesDependencies:
outfile = etpConst['packagestmpdir']+"/.emerge-"+dep.split("/")[len(dep.split("/"))-1]+"-"+str(getRandomNumber())
PackagesDependenciesCounter += 1
print_info(green(" * ")+bold("(")+blue(str(PackagesDependenciesCounter))+green("/")+red(str(PackagesDependenciesLength))+bold(")")+" Compiling: "+red(dep)+" ... ")
mountProc()
if (not enzymeRequestVerbose):
pkgBinaryFiles = []
# collect libraries info for the current installed package, if any
if (getPackageSlot("="+atom) is None):
pkgquestion = dep_getkey(atom)
else:
pkgquestion = "="+atom
if (getInstalledAtom(pkgquestion) is not None):
# collect them!
pkgBinaryFiles = collectBinaryFilesForInstalledPackage(getInstalledAtom(pkgquestion))
print_info(yellow(" *")+" redirecting output to: "+green(outfile))
rc, outfile = emerge("="+dep, odbNodeps, outfile, "&>", enzymeRequestSimulation)
# after install, check for changes
newPkgBinaryFiles = []
# collect libraries info for the current installed package, if any
if (getPackageSlot("="+atom) is None):
pkgquestion = dep_getkey(atom)
else:
pkgquestion = "="+atom
if (getInstalledAtom(pkgquestion) is not None):
# collect them!
newPkgBinaryFiles = collectBinaryFilesForInstalledPackage(getInstalledAtom(pkgquestion))
brokenBinariesList = compareLibraryLists(pkgBinaryFiles,newPkgBinaryFiles)
if brokenBinariesList != []:
# FIXME: make this warning fatal?
print_warning(yellow(" * ")+red("ATTENTION: Package ")+bold(dep)+red(" caused an API breakage:"))
for i in brokenBinariesList:
print_warning(yellow(" * ")+green("Previous library: ")+yellow(i[0])+bold(" -- became --> ")+red(i[1])+" (now installed)")
import time
time.sleep(30)
# parse the elog file, if one
einfo = parseElogFile(dep)
for info in einfo:
print_info(green(" * ")+red("[")+yellow("i")+red("] ")+green(info))
else:
rc, outfile = emerge("="+dep,odbNodeps,None,None, enzymeRequestSimulation)
#umountProc()
if (not rc):
# compilation is fine
print_info(green(" *")+" Compiled successfully")
PackagesQuickpkg.append("quick|"+dep)
if os.path.isfile(outfile): os.remove(outfile)
else:
print_error(red(" *")+" Compile error")
if (not enzymeRequestVerbose): print_info(red(" *")+" Log file at: "+outfile)
if os.path.isfile(outfile):
f = open(outfile,"r")
errorlog = f.readlines()
f.close()
errorlinesnumber = len(errorlog)
if errorlinesnumber > 50:
errorlinesfrom = errorlinesnumber - 50
else:
errorlinesfrom = 0
for number in range(errorlinesfrom,errorlinesnumber):
print_error(" "+errorlog[number].strip())
#print
#print
print_error(red(" ***")+" Cannot continue")
compileError = True
break
if (enzymeRequestInteraction):
# interaction needed
print_info(green(" *")+" Running etc-update...")
spawnCommand("etc-update")
else:
print_info(green(" *")+" Auto-running etc-update...")
spawnCommand("echo -5 | etc-update")
# remove avail| packages from the list
_PackagesQuickpkg = []
for i in PackagesQuickpkg:
if not i.startswith("avail|"):
_PackagesQuickpkg.append(i)
PackagesQuickpkg = _PackagesQuickpkg
if (PackagesQuickpkg != []):
print_info(green(" *")+" Compressing installed packages...")
for dep in PackagesQuickpkg:
dep = dep.split("|")[len(dep.split("|"))-1]
print_info(green(" *")+" Compressing: "+red(dep))
rc = quickpkg(dep,etpConst['packagesstoredir'])
if (rc is not None):
packagesPaths.append(rc)
else:
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"build: (PackagesQuickpkg) "+str(dep)+" -> quickpkg error. Cannot continue.")
print_error(red(" *")+" quickpkg error for "+red(dep))
print_error(red(" ***")+" Fatal error, cannot continue")
sys.exit(251)
if packagesPaths != []:
#print
print_info(red(" *")+" These are the binary packages created:")
for pkg in packagesPaths:
print_info(green(" * ")+red(pkg))
return packagesPaths
# World update tool
# FIXME: integrate --ask --pretend
def world(options):
myopts = options[1:]
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"world: called with options -> "+str(options))
# FIXME: are --pretend and --ask useful here?
enzymeRequestDeep = False
enzymeRequestVerbose = False
enzymeRequestRebuild = False
enzymeRequestAsk = False
enzymeRequestPretend = False
enzymeRequestJustRepackageWorld = False
enzymeRequestSkipfirst = False
enzymeRequestSkipN = False
enzymeRequestNoSync = False
for i in myopts:
if ( i == "--verbose" ) or ( i == "-v" ):
enzymeRequestVerbose = True
elif ( i == "--empty-tree" ):
enzymeRequestRebuild = True
elif ( i == "--ask" ):
enzymeRequestAsk = True
elif ( i == "--pretend" ):
enzymeRequestPretend = True
elif ( i == "--nosync" ):
enzymeRequestPretend = True
elif ( i == "--skipfirst" ):
enzymeRequestNoSync = True
elif ( i.startswith("--skip=") ):
enzymeRequestSkipN = True
skip_number = i.split("--skip=")[len(i.split("--skip="))-1]
try:
skipN = int(skip_number)
except:
skipN = 1
elif ( i == "--repackage-installed" ):
enzymeRequestJustRepackageWorld = True
elif ( i == "--deep" ):
enzymeRequestDeep = True
else:
print red(" ***")+" Wrong parameters specified."
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"world: Wrong parameters specified.")
sys.exit(201)
if (enzymeRequestJustRepackageWorld):
# create the list of installed packages
print_info(green(" * ")+red("Scanning system database..."),back = True)
installedPackages, pkgsnumber = getInstalledPackages()
print_info(green(" * ")+red("System database: ")+bold(str(pkgsnumber))+red(" installed packages"))
if pkgsnumber > 0:
print_info(green(" * ")+red("Starting to build binaries..."))
else:
print_error(red(" * ")+red("No detected packages??? Are you serious?"))
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"world: No detected packages??? Are you serious? Are you sure that you are running a Gentoo based distribution?")
sys.exit(231)
localcount = 0
for pkg in installedPackages:
localcount += 1
print_info(" "+red("(")+green(str(localcount))+yellow("/")+blue(str(pkgsnumber))+red(")")+red(" Compressing... ")+bold(pkg),back = True)
rc = quickpkg(pkg,etpConst['packagesstoredir'])
if (rc is None):
print_warning(red(" * ")+yellow(" quickpkg problem for ")+red(pkg))
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"world: (installedPackages) quickpkg problem for"+str(pkg))
sys.exit(232)
writechar("\n")
print_info(green(" * ")+red("All packages have been generates successfully"))
return 0
# elif...
# classical world, trapping --deep if necessary
else:
emergeopts = " -u "
if (enzymeRequestDeep): emergeopts += " -D"
if (enzymeRequestRebuild) and (not enzymeRequestDeep): emergeopts += " -e"
print_info(green(" * ")+red("Scanning tree for ")+bold("updates")+red("..."))
deplist, blocklist = calculateFullAtomsDependencies("world",False,emergeopts)
if blocklist != []:
# FIXME: this part needs some polishing
print blocklist
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"world: error there is something that is blocking all this shit "+str(blocklist))
print_error(red(" * ")+" Error there is something that is blocking all this shit")
sys.exit(233)
if (enzymeRequestSkipfirst):
deplist = deplist[1:]
elif (enzymeRequestSkipN):
deplist = deplist[skipN:]
# composing the request
atoms = []
for atom in deplist:
atoms.append("="+atom)
atoms.append("--force-rebuild")
atoms.append("--nodeps")
if (enzymeRequestPretend):
atoms.append("--pretend")
if (enzymeRequestNoSync):
atoms.append("--nosync")
elif (enzymeRequestAsk):
atoms.append("--ask")
build(atoms)
def overlay(options):
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"overlay: called with options -> "+str(options))
# check if the portage tree is configured
if (not os.path.isfile(etpConst['portagetreedir']+"/metadata/timestamp")):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"overlay: Entropy Portage tree is not yet prepared. Use the 'sync' tool first.")
print_error(red(bold("Entropy Portage tree is not yet prepared. Use the 'sync' tool first.")))
return False
# check if layman is installed
layman = commands.getoutput("which layman")
if (not layman.startswith("/")):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"overlay: app-portage/layman is not installed. Please install.")
print_error(red(" * app-portage/layman is not installed. Please install."))
return False
myopts = options[1:]
# be verbose?
verbosity = "> /dev/null"
for x in myopts:
if x.startswith("--verbose") or x.startswith("-v"):
verbosity = None
# filter garbage
_myopts = []
for x in myopts:
# --verbose, -v
if (x != "--verbose" ) and (x != "-v" ):
_myopts.append(x)
myopts = _myopts
if (myopts == []):
print_error(red(bold("not enough parameters.")))
return False
# starting Test Case
if (myopts[0] == "add"):
# add overlay
myownopts = list(set(myopts[1:]))
for i in myownopts:
print_info(green("adding overlay: ")+bold(i))
rc = spawnCommand(layman+" --config="+etpConst['overlaysconffile']+" -f -a "+i, redirect = verbosity)
if (rc != 0):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"overlay: a problem occoured adding "+i+" overlay.")
print_warning(red(bold("a problem occoured adding "+i+" overlay.")))
elif (myopts[0] == "remove"):
# remove overlay
myownopts = list(set(myopts[1:]))
for i in myownopts:
print_info(green("removing overlay: ")+bold(i))
rc = spawnCommand(layman+" --config="+etpConst['overlaysconffile']+" -d "+i, redirect = verbosity)
if (rc != 0):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"overlay: a problem occoured removing "+i+" overlay.")
print_warning(red(bold("a problem occoured removing "+i+" overlay.")))
return True
elif (myopts[0] == "sync"):
# sync an overlay
myownopts = list(set(myopts[1:]))
if (myownopts == []):
# sync all
print_info(green("syncing all the overlays"))
rc = spawnCommand(layman+" --config="+etpConst['overlaysconffile']+" -S ", redirect = verbosity)
if (rc != 0):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"overlay: a problem occoured syncing all the overlays.")
print_warning(red(bold("a problem occoured syncing all the overlays.")))
else:
print_info(green("sync completed."))
else:
# sync each overlay
for i in myownopts:
print_info(green("syncing overlay: ")+bold(i),back = True)
rc = spawnCommand(layman+" --config="+etpConst['overlaysconffile']+" -s "+i, redirect = verbosity)
if (rc != 0):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"overlay: a problem occoured syncing "+i+" overlay.")
print_warning(red(bold("a problem occoured syncing "+i+" overlay.")))
else:
print_info(green("synced overlay: ")+bold(i))
return True
elif (myopts[0] == "list"):
# add an overlay
listing = listOverlays()
if (listing == []):
print_info(green("no overlays."))
else:
for i in listing:
print_info(green(i)+" overlay is added.")
else:
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"overlay: wrong synthax.")
print_error(red(bold("wrong synthax.")))
return False
return True
def uninstall(options):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"uninstall: called with options -> "+str(options))
# Filter extra commands
enzymeRequestVerbose = False
enzymeUninstallRedirect = "&>/dev/null"
enzymeRequestSimulation = False
enzymeRequestPrune = False
_atoms = []
for i in options:
if ( i == "--verbose" ) or ( i == "-v" ):
enzymeRequestVerbose = True
enzymeUninstallRedirect = None
elif ( i == "--pretend" ):
enzymeRequestSimulation = True
elif ( i == "--just-prune" ):
enzymeRequestPrune = True
else:
_atoms.append(i)
atoms = _atoms
if (enzymeRequestVerbose): print_info(i+" is Pretend?: "+str(enzymeRequestSimulation))
if (enzymeRequestVerbose): print_info(i+" is Prune?: "+str(enzymeRequestPrune))
validAtoms = []
_atoms = []
for i in atoms:
if (not isjustname(i)) and (not i.startswith("=")):
i = "="+i
_atoms.append(i)
atoms = _atoms
for i in atoms:
if (enzymeRequestVerbose): print_info(i+" is valid?: "+str(checkAtom(i)))
if (checkAtom(i)):
if (getInstalledAtom(dep_getkey(i)) != None):
validAtoms.append(i)
else:
print_info(red("* >>> ")+yellow(i)+" is not installed.")
else:
#print
print_warning(red("* >>> ")+yellow(i)+" is not a valid atom, it's masked or its name conflicts with something else.")
if getBestAtom(i) == "!!conflicts":
# it conflicts with something
print_warning(red("* ^^^ ")+"Ambiguous package name. Please add category.")
# Filter duplicates
validAtoms = list(set(validAtoms))
_validAtoms = []
for atom in validAtoms:
if (atom.find("/") == -1):
# add pkgcat
atom = getAtomCategory(atom)+"/"+atom
_validAtoms.append(atom)
validAtoms = _validAtoms
uninstallText = yellow(" * ")+"Doing "
if validAtoms == []:
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"uninstall: no valid package names specified.")
print_error(red(bold("no valid package names specified.")))
sys.exit(232)
if (not enzymeRequestPrune):
uninstallText += bold("unmerge ")
portageCmd = cdbRunEmerge+" -C "
print_info(green(" *")+" This is the list of the packages that would be removed, if installed:")
for i in validAtoms:
installedAtoms = getInstalledAtoms(i)
if installedAtoms is None:
continue
installedVers = []
for i in installedAtoms:
pkgname, pkgver = extractPkgNameVer(i)
installedVers.append(pkgver)
if len(installedVers) > 1:
x = string.join(installedVers)
print_info(yellow(" *")+" [REMOVE] "+bold(dep_getkey(i))+" [ selected: "+red(x)+" ]")
else:
installedVer = installedVers[0]
print_info(yellow(" *")+" [REMOVE] "+bold(dep_getkey(i))+" [ selected: "+red(installedVer)+" ]")
else:
uninstallText += bold("prune ")
# FIXME: rewrite this using Portage Python bindings directly?
portageCmd = cdbRunEmerge+" -P "
# filter unpruneable packages
_validAtoms = []
for atom in validAtoms:
rc = commands.getoutput(portageCmd+" --quiet --pretend "+atom)
if (rc != ''):
_validAtoms.append(atom)
validAtoms = _validAtoms
if validAtoms != []:
print_info(green(" *")+" This is the list of the packages that would be pruned, if possible:")
for atom in validAtoms:
selected = atom
protected = None
omitted = None
if isjustname(atom) == 1:
# if the user provide only the name, then parse the list of the packages
rc = commands.getoutput(portageCmd+" --quiet --pretend --color=n "+atom).split("\n")
for i in rc:
if i.find("selected:") != -1:
selected = i.strip().split(":")[1][1:]
if i.find("protected:") != -1:
protected = i.strip().split(":")[1][1:]
if i.find("omitted:") != -1:
omitted = i.strip().split(":")[1][1:]
print_info(yellow(" *")+" [PRUNE] "+bold(atom)+" [ selected: "+red(string.lower(str(selected)))+"; protected: "+green(string.lower(str(protected)))+"; omitted: "+yellow(string.lower(str(omitted)))+" ]")
else:
print_info(green(" *")+" No packages to prune.")
# if --pretend, end here
if (enzymeRequestSimulation):
sys.exit(0)
successfullyRemovedAtoms = []
for atom in validAtoms:
print_info(uninstallText+red(atom))
# now run the command
rc = spawnCommand(portageCmd+"'"+atom+"'",enzymeUninstallRedirect)
if (rc):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"uninstall: Something weird happened while running the action on "+str(atom))
print_warning(yellow(" *** ")+red("Something weird happened while running the action on ")+bold(atom))
if (not enzymeRequestVerbose):
print_warning(yellow(" *** ")+red("Please use --verbose and retry to see what was wrong. Continuing..."))
else:
print_info(green(" * ")+bold(atom)+" worked out successfully.")
successfullyRemovedAtoms.append(atom)
print_info(green(" * ")+red("Please also consider to remove these packages from the Entropy database."))
def search(atoms):
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"search: called with -> "+str(atoms))
# filter any --starting package
_atoms = []
for atom in atoms:
if (not atom.startswith("--")):
_atoms.append(atom)
keywords = _atoms
print
for keyword in keywords:
results = packageSearch(keyword)
for result in results:
# get latest version available
masked = ""
latestVersion = getBestAtom(result)
if (latestVersion == ""):
latestVersion = getBestMaskedAtom(result)
masked = " "+bold("[")+red("MASKED")+bold("]")
# get installed version
installedVer = getInstalledAtom(result)
# get Homepage
pkgHomepage = getPackageVar(latestVersion,'HOMEPAGE')
# get Description
pkgDescription = getPackageVar(latestVersion,'DESCRIPTION')
# get License
pkgLicense = getPackageVar(latestVersion,'LICENSE')
# format the output string
print_info(green(" * ")+bold(result))
print_info(red("\t Latest version available: ")+blue(latestVersion)+masked)
print_info(red("\t Latest version installed: ")+green(str(installedVer)))
print_info(red("\t Download size: ")+yellow(getPackageDownloadSize(latestVersion)))
print_info(red("\t Homepage: ")+darkred(pkgHomepage))
print_info(red("\t Description: ")+pkgDescription)
print_info(red("\t License: ")+bold(pkgLicense))
print
def distcc(options):
enzymeLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"distcc: called with options -> "+str(options))
# Filter
if options == []:
print_error(yellow(" * ")+red("Not enough parameters."))
sys.exit(200)
# Firstly check if distcc is available
distccAvail = spawnCommand("which distcc", "&> /dev/null")
if (distccAvail):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"distcc: distcc is not installed. Cannot continue.")
print_error(yellow(" *** ")+red("distcc is not installed. Cannot continue."))
sys.exit(201)
# Enable distcc function
if (options[0] == "--enable"):
mountProc()
distccStatus = spawnCommand(cdbStatusDistcc, "&> /dev/null")
if (distccStatus):
print_info(yellow(" * ")+red("Starting distccd..."))
rc = spawnCommand(cdbStartDistcc, "&> /dev/null")
if (rc):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"distcc: A problem occured while starting distcc. Please check.")
print_error(yellow(" *** ")+red(" A problem occured while starting distcc. Please check."))
sys.exit(202)
# now configure distcc properly in enzyme.conf
print_info(green(" * ")+red("Enabling DistCC Entropy infrastructure..."), back = True)
setDistCC(True)
print_info(green(" * ")+red("DistCC Entropy infrastructure enabled."))
# Disable distcc function
elif (options[0] == "--disable"):
mountProc()
distccStatus = spawnCommand(cdbStatusDistcc, "&> /dev/null")
if (not distccStatus):
print_info(yellow(" * ")+red("Stopping distccd..."))
rc = spawnCommand(cdbStopDistcc, "&> /dev/null")
if (rc):
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"distcc: A problem occured while stopping distcc. Please check.")
print_error(yellow(" *** ")+red(" A problem occured while stopping distcc. Please check."))
sys.exit(203)
# now configure distcc properly in enzyme.conf
print_info(green(" * ")+red("Disabling DistCC Entropy infrastructure..."), back = True)
setDistCC(False)
print_info(green(" * ")+red("DistCC Entropy infrastructure disabled."))
elif (options[0] == "--add-host"):
if (not getDistCCStatus()):
print_warning(yellow(" * ")+red("Attention: distcc is not enabled."))
myhosts = options[1:]
if len(myhosts) == 0:
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"distcc: (--add-host) No hosts specified.")
print_error(yellow(" * ")+red("No hosts specified."))
sys.exit(204)
print_info(green(" * ")+red("Adding specified hosts..."), back = True)
addDistCCHosts(myhosts)
myhosts = string.join(myhosts," ")
print_info(green(" * ")+red("Hosts: ")+blue(myhosts)+red(" added."))
elif (options[0] == "--remove-host"):
if (not getDistCCStatus()):
enzymeLog.log(ETP_LOGPRI_WARNING,ETP_LOGLEVEL_NORMAL,"distcc: Attention: distcc is not enabled.")
print_warning(yellow(" * ")+red("Attention: distcc is not enabled."))
myhosts = options[1:]
if len(myhosts) == 0:
enzymeLog.log(ETP_LOGPRI_ERROR,ETP_LOGLEVEL_NORMAL,"distcc: (--remove-host) No hosts specified.")
print_error(yellow(" * ")+red("No hosts specified."))
sys.exit(204)
print_info(green(" * ")+red("Removing specified hosts..."), back = True)
removeDistCCHosts(myhosts)
myhosts = string.join(myhosts," ")
print_info(green(" * ")+red("Hosts: ")+blue(myhosts)+red(" removed."))
elif (options[0] == "--show-hosts"):
if (not getDistCCStatus()):
print_warning(yellow(" * ")+red("Attention: distcc is not enabled."))
hosts = getDistCCHosts()
if len(hosts) == 0:
enzymeLog.log(ETP_LOGPRI_WARNING,ETP_LOGLEVEL_NORMAL,"distcc: (--show-hosts) Error: no hosts selected.")
print_error(yellow(" * ")+red("Error: no hosts selected."))
sys.exit(205)
print_info(green(" * ")+red("Showing DistCC hosts table:"))
for host in hosts:
availability = isIPAvailable(host)
if (availability):
availability = green("running")
else:
availability = green("not running")
print_info(green(" * ")+yellow("\tHost:\t")+blue(host)+red(" :: ")+availability)
########################################################
####
## DistCC handling functions
#
# Distcc check status function
def setDistCC(status = True):
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"setDistCC: called. ")
f = open(etpConst['enzymeconf'],"r")
enzymeconf = f.readlines()
f.close()
if (status):
distccSwitch = "enabled"
else:
distccSwitch = "disabled"
newenzymeconf = []
for line in enzymeconf:
if line.startswith("distcc-status|"):
line = "distcc-status|"+distccSwitch+"\n"
newenzymeconf.append(line)
f = open(etpConst['enzymeconf'],"w")
f.writelines(newenzymeconf)
f.flush()
f.close()
def getDistCCHosts():
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"getDistCCHosts: called.")
f = open(etpConst['enzymeconf'],"r")
enzymeconf = f.readlines()
f.close()
hostslist = []
for line in enzymeconf:
if line.startswith("distcc-hosts|") and (len(line.split("|")) == 2):
line = line.strip().split("|")[1].split()
for host in line:
hostslist.append(host)
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"getDistCCHosts: hosts list dump -> "+str(hostslist))
return hostslist
entropyLog.log(ETP_LOGPRI_WARNING,ETP_LOGLEVEL_VERBOSE,"getDistCCHosts: hosts list EMPTY.")
return []
# @returns True if validIP (type: string) is a valid IP
# @param validIP: IP string
def isValidIP(validIP):
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"getDistCCHosts: called. ")
validIPExpr = re.compile('(([0-9]|[01]?[0-9]{2}|2([0-4][0-9]|5[0-5]))\.){3}([0-9]|[01]?[0-9]{2}|2([0-4][0-9]|5[0-5]))$')
result = validIPExpr.match(validIP)
if (result != None):
return True
return False
# you must provide a list
def addDistCCHosts(hosts):
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"addDistCCHosts: called.")
hostslist = getDistCCHosts()
for host in hosts:
hostslist.append(host)
# filter dupies
hostslist = list(set(hostslist))
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"addDistCCHosts: hostslist dump -> "+str(hostslist))
# write back to file
f = open(etpConst['enzymeconf'],"r")
enzymeconf = f.readlines()
f.close()
newenzymeconf = []
distcchostslinefound = False
for line in enzymeconf:
if line.startswith("distcc-hosts|"):
distcchostslinefound = True
if (distcchostslinefound):
for line in enzymeconf:
if line.startswith("distcc-hosts|"):
hostsline = string.join(hostslist," ")
line = "distcc-hosts|"+hostsline+"\n"
newenzymeconf.append(line)
else:
newenzymeconf = enzymeconf
hostsline = string.join(hostslist," ")
newenzymeconf.append("distcc-hosts|"+hostsline+"\n")
# write distcc config file too
f = open(etpConst['distccconf'],"w")
f.write(hostsline+"\n")
f.flush()
f.close()
f = open(etpConst['enzymeconf'],"w")
f.writelines(newenzymeconf)
f.flush()
f.close()
# you must provide a list
def removeDistCCHosts(hosts):
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"removeDistCCHosts: called. ")
hostslist = getDistCCHosts()
cleanedhosts = []
for host in hostslist:
rmfound = False
for rmhost in hosts:
if (rmhost == host):
# remove
rmfound = True
if (not rmfound):
cleanedhosts.append(host)
# filter dupies
cleanedhosts = list(set(cleanedhosts))
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"removeDistCCHosts: cleanedhosts dump: "+cleanedhosts)
# write back to file
f = open(etpConst['enzymeconf'],"r")
enzymeconf = f.readlines()
f.close()
newenzymeconf = []
distcchostslinefound = False
for line in enzymeconf:
if line.startswith("distcc-hosts|"):
distcchostslinefound = True
if (distcchostslinefound):
for line in enzymeconf:
if line.startswith("distcc-hosts|"):
hostsline = string.join(cleanedhosts," ")
line = "distcc-hosts|"+hostsline+"\n"
newenzymeconf.append(line)
else:
newenzymeconf = enzymeconf
hostsline = string.join(cleanedhosts," ")
newenzymeconf.append("distcc-hosts|"+hostsline+"\n")
# write distcc config file too
f = open(etpConst['distccconf'],"w")
f.write(hostsline+"\n")
f.flush()
f.close()
f = open(etpConst['enzymeconf'],"w")
f.writelines(newenzymeconf)
f.flush()
f.close()
def getDistCCStatus():
return etpConst['distcc-status']
def isIPAvailable(ip):
entropyLog.log(ETP_LOGPRI_INFO,ETP_LOGLEVEL_VERBOSE,"isIPAvailable: called. ")
rc = spawnCommand("ping -c 1 "+ip, "&> /dev/null")
if (rc):
return False
return True