diff --git a/TODO b/TODO index 2ee4e0dac..d4d5e7b44 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ TODO list (for developers only): -- timestamp management across database and packages servers - a general option --info to print all the Entropy variables and constants - add a wrapper for qfile and qlist portage-utils tools because our internal repository is at /var/lib/entropy/portage - fix: python enzyme build planner --> ambiguos ebuilds' name +- complete the uninstall() funcion in enzymeTools and unmerge unsermake diff --git a/handlers/enzyme b/handlers/enzyme index 5e226529f..832495f1b 100644 --- a/handlers/enzyme +++ b/handlers/enzyme @@ -54,6 +54,9 @@ def print_help(): print "* opts * : \t\t"+entropyTools.red("--ignore-conflicts")+"\t ignore conflicts between packages" print "* opts * : \t\t"+entropyTools.red("--no-interaction")+"\t disable user interaction, automatic driving" print "* opts * : \t\t"+entropyTools.red("--simulate-building")+"\t compilations are simulated only" + print "* info * : \t"+entropyTools.green(entropyTools.bold("uninstall"))+"\t to uninstall one or a list of packages" + print "* opts * : \t\t"+entropyTools.red("--pretend")+"\t\t just show what would be done" + print "* opts * : \t\t"+entropyTools.red("--just-prune")+"\t\t with slotted packages, keep only the latest, remove the rest" print "* info * : \t"+entropyTools.green(entropyTools.bold("overlay"))+"\t\t to manage overlays" print "* opts * : \t\t "+entropyTools.red("add")+"\t\t\t to add overlays" print "* opts * : \t\t "+entropyTools.red("remove")+"\t\t\t to remove overlays" @@ -105,4 +108,8 @@ if (options[0] == "overlay"): # build tool if (options[0] == "build"): enzymeTools.build(options[1:]) + sys.exit(0) +# uninstall tool +if (options[0] == "uninstall"): + enzymeTools.uninstall(options[1:]) sys.exit(0) \ No newline at end of file diff --git a/libraries/entropyTools.py b/libraries/entropyTools.py index f980bcad7..3664f8a4d 100644 --- a/libraries/entropyTools.py +++ b/libraries/entropyTools.py @@ -62,6 +62,7 @@ def getThirdPartyMirrors(mirrorname): # sys-libs/application --> sys-libs/application-1.2.3-r1 def getBestAtom(atom): try: + #portage.portdb.melt() rc = portage.portdb.xmatch("bestmatch-visible",str(atom)) return rc except ValueError: @@ -93,6 +94,34 @@ def getInstalledAtom(atom): else: return None +def getInstalledAtoms(atom): + rc = portage.db['/']['vartree'].dep_match(str(atom)) + if (rc != []): + return rc + else: + return None + +# TO THIS FUNCTION: +# must be provided a valid and complete atom +# FIXME: needs some love ! +def extractPkgNameVer(atom): + package = atom.split("/")[len(atom.split("/"))-1] + package = package.split("-") + pkgname = "" + pkglen = len(package) + if package[pkglen-1].startswith("r"): + pkgver = package[pkglen-2]+"-"+package[pkglen-1] + pkglen -= 2 + else: + pkgver = package[len(package)-1] + pkglen -= 1 + for i in range(pkglen): + if i == pkglen-1: + pkgname += package[i] + else: + pkgname += package[i]+"-" + return pkgname,pkgver + def emerge(atom, options, outfile = None, redirect = "&>", simulate = False): if (simulate): return 0,"" # simulation enabled diff --git a/libraries/enzymeTools.py b/libraries/enzymeTools.py index 9bcd169cd..d61472988 100644 --- a/libraries/enzymeTools.py +++ b/libraries/enzymeTools.py @@ -135,7 +135,6 @@ def sync(options): def build(atoms): -# FIXME: move print() to our print function # FIXME: add runtime dependencies packages quickpkg enzymeRequestVerbose = False @@ -175,15 +174,15 @@ def build(atoms): validAtoms = [] for i in atoms: - if (enzymeRequestVerbose): print i+" is valid?: "+str(checkAtom(i)) + if (enzymeRequestVerbose): print_info(i+" is valid?: "+str(checkAtom(i))) if (checkAtom(i)): validAtoms.append(i) else: - print - print red("* >>> ")+yellow(i)+" is not a valid atom, it's masked or its name conflicts with something 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 red("* ^^^ ")+"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."))) @@ -206,20 +205,20 @@ def build(atoms): for atom in validAtoms: # let's dance !! isAvailable = getInstalledAtom("="+atom) - if (enzymeRequestVerbose): print "testing atom: "+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 "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" + 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 "Do I really have to build "+bold(atom)+" ?" + if (enzymeRequestVerbose): print_info("Do I really have to build "+bold(atom)+" ?") toBeBuilt.append(atom) else: - if (enzymeRequestVerbose): print "I will use this already precompiled package: "+tbz2Available + if (enzymeRequestVerbose): print_info("I will use this already precompiled package: "+tbz2Available) else: - if (enzymeRequestVerbose): print "I have to compile or quickpkg "+atom+" by myself..." + if (enzymeRequestVerbose): print_info("I have to compile or quickpkg "+atom+" by myself...") if (enzymeRequestForceRepackage) or (isAvailable is None): toBeBuilt.append(atom) elif (not enzymeRequestForceRepackage) and (isAvailable is not None): @@ -236,19 +235,19 @@ def build(atoms): for atom in toBeBuilt: # if this turns into true, we need to build the package because its dependencies do not match atomDepsTainted = False - print + #print # check its unsatisfied dependencies - print " Checking "+bold(atom)+" dependencies and conflicts..." + print_info(" Checking "+bold(atom)+" dependencies and conflicts...") atomdeps, atomconflicts = synthetizeRoughDependencies(getPackageDependencyList(atom)) atomdeps = atomdeps.split() atomconflicts = atomconflicts.split() - print " Current installed release: "+bold(str(getInstalledAtom(dep_getkey(atom)))) - if(enzymeRequestVerbose): print - if(enzymeRequestVerbose): print "\tfiltering "+atom+" dependencies..." + print_info(" Current installed release: "+bold(str(getInstalledAtom(dep_getkey(atom))))) + #if(enzymeRequestVerbose): print + if(enzymeRequestVerbose): print_info("\tfiltering "+atom+" dependencies...") # check if the dependency is satisfied for dep in atomdeps: - if(enzymeRequestVerbose): print "\tchecking for: "+red(dep) + if(enzymeRequestVerbose): print_info("\tchecking for: "+red(dep)) # filter |or| if dep.find(dbOR) != -1: deps = dep.split(dbOR) @@ -257,19 +256,19 @@ def build(atoms): dep = i break wantedAtom = getBestAtom(dep) - if(enzymeRequestVerbose): print "\t\tI want: "+yellow(wantedAtom) + if(enzymeRequestVerbose): print_info("\t\tI want: "+yellow(wantedAtom)) installedAtom = getInstalledAtom(dep) - if(enzymeRequestVerbose): print "\t\tIs installed: "+green(str(installedAtom)) + if(enzymeRequestVerbose): print_info("\t\tIs installed: "+green(str(installedAtom))) if installedAtom is None: # then append - because it's not installed ! - if(enzymeRequestVerbose): print "\t\t"+dep+" is not installed, adding." + if(enzymeRequestVerbose): print_info("\t\t"+dep+" is not installed, adding.") atomDepsTainted = True # taint ! PackagesDependencies.append(wantedAtom) elif (wantedAtom != installedAtom): if (enzymeRequestUpdate): PackagesDependencies.append(wantedAtom) atomDepsTainted = True # taint ! - if(enzymeRequestVerbose): print "\t\t"+dep+" versions differs, adding (pulled in by --update)." + if(enzymeRequestVerbose): print_info("\t\t"+dep+" versions differs, adding (pulled in by --update).") else: if (isTbz2PackageAvailable(installedAtom) == False): # quickpkg'd @@ -277,28 +276,28 @@ def build(atoms): else: # already available PackagesQuickpkg.append("avail|"+installedAtom) - if(enzymeRequestVerbose): print "\t\t"+dep+" versions differs but not adding since the dependency is permissive." + if(enzymeRequestVerbose): print_info("\t\t"+dep+" versions differs but not adding since the dependency is permissive.") else: if (isTbz2PackageAvailable(installedAtom) == False): PackagesQuickpkg.append("quick|"+installedAtom) - if(enzymeRequestVerbose): print "\t\t"+dep+" versions match, no need to build" - print + if(enzymeRequestVerbose): print_info("\t\t"+dep+" versions match, no need to build") + #print if atomconflicts != []: - if(enzymeRequestVerbose): print "\tfiltering "+atom+" conflicts..." + if(enzymeRequestVerbose): print_info("\tfiltering "+atom+" conflicts...") for conflict in atomconflicts: - if(enzymeRequestVerbose): print "\tchecking for: "+red(conflict) + if(enzymeRequestVerbose): print_info("\tchecking for: "+red(conflict)) if getInstalledAtom(conflict) is not None: # damn, it's installed - if(enzymeRequestVerbose): print "\t\t Package "+yellow(conflict)+" conflicts" + if(enzymeRequestVerbose): print_info("\t\t Package "+yellow(conflict)+" conflicts") PackagesConflicting.append(conflict) # Now check if its dependency list is empty, in the case, just quickpkg it - if (enzymeRequestVerbose): print "\n\t"+red("*")+" Package dependencies of: "+atom+" are tainted? --> "+str(atomDepsTainted) + if (enzymeRequestVerbose): print_info("\n\t"+red("*")+" Package dependencies of: "+atom+" are tainted? --> "+str(atomDepsTainted)) # add to the packages that can be quickpkg'd if (not atomDepsTainted) and (not enzymeRequestForceRebuild) and ( atom == getInstalledAtom(dep_getkey(atom)) ): toBeQuickpkg.append(getInstalledAtom(dep_getkey(atom))) # append the currently installed release ONLY! - if (enzymeRequestVerbose): print; print + #if (enzymeRequestVerbose): print; print # Clean out toBeBuilt by removing entries that are in toBeQuickpkg _toBeBuilt = [] @@ -314,48 +313,48 @@ def build(atoms): # Now clean toBeQuickpkg if toBeBuilt != []: - print green(" *")+" This is the list of the packages that have been considered:" + print_info(green(" *")+" This is the list of the packages that have been considered:") for i in toBeBuilt: - print yellow(" *")+" [BUILD] "+i + print_info(yellow(" *")+" [BUILD] "+i) for i in toBeQuickpkg: - print green(" *")+" [QUICK] "+i + print_info(green(" *")+" [QUICK] "+i) else: - print - print red(" *")+" No new packages to build, they're all already built or packaged." - print + #print + print_info(red(" *")+" No new packages to build, they're all already built or packaged.") + #print if PackagesDependencies != []: - print yellow(" *")+" These are their dependencies (pulled in):" + print_info(yellow(" *")+" These are their dependencies (pulled in):") for i in PackagesDependencies: - print red(" *")+bold(" [BUILD] ")+i + print_info(red(" *")+bold(" [BUILD] ")+i) for i in PackagesQuickpkg: if i.startswith("quick|"): - print green(" *")+bold(" [QUICK] ")+i.split("quick|")[len(i.split("quick|"))-1] + print_info(green(" *")+bold(" [QUICK] ")+i.split("quick|")[len(i.split("quick|"))-1]) elif i.startswith("avail|"): - print green(" *")+bold(" [AVAIL] ")+i.split("avail|")[len(i.split("avail|"))-1] + print_info(green(" *")+bold(" [AVAIL] ")+i.split("avail|")[len(i.split("avail|"))-1]) else: # I should never get here - print green(" *")+bold(" [MERGE] ")+i - print + print_info(green(" *")+bold(" [MERGE] ")+i) + #print else: - print green(" *")+" No extra dependencies need to be built" + print_info(green(" *")+" No extra dependencies need to be built") if PackagesConflicting != []: - print red(" *")+" These are the conflicting packages:" + print_info(red(" *")+" These are the conflicting packages:") for i in PackagesConflicting: - print red(" *")+bold(" [CONFL] ")+i + print_warning(red(" *")+bold(" [CONFL] ")+i) if (not enzymeRequestIgnoreConflicts): - print - print - print red(" ***")+" Sorry, I can't continue. To force this, add --ignore-conflicts at your own risk." + #print + #print + print_error(red(" ***")+" Sorry, I can't continue. To force this, add --ignore-conflicts at your own risk.") sys.exit(1) else: import time - print - print yellow(" ***")+" You are using --ignore-conflicts at your own risk." - print + #print + print_warning((" ***")+" You are using --ignore-conflicts at your own risk.") + #print time.sleep(5) if (enzymeRequestPretendAll): @@ -365,92 +364,92 @@ def build(atoms): packagesPaths = [] if PackagesDependencies != []: - print - print yellow(" *")+" Building dependencies..." + #print + print_info(yellow(" *")+" Building dependencies...") for dep in PackagesDependencies: outfile = etpConst['packagestmpdir']+"/.emerge-"+str(getRandomNumber()) - print green(" *")+" Compiling: "+red(dep)+" ... " + print_info(green(" *")+" Compiling: "+red(dep)+" ... ") if (not enzymeRequestVerbose): - print yellow(" *")+" redirecting output to: "+green(outfile) + print_info(yellow(" *")+" redirecting output to: "+green(outfile)) rc, outfile = emerge("="+dep, odbNodeps, outfile, "&>", enzymeRequestSimulation) else: rc, outfile = emerge("="+dep,odbNodeps,None,None, enzymeRequestSimulation) if (not rc): # compilation is fine - print green(" *")+" Compiled successfully" + print_info(green(" *")+" Compiled successfully") PackagesQuickpkg.append("quick|"+dep) if os.path.isfile(outfile): os.remove(outfile) else: - print red(" *")+" Compile error" - if (not enzymeRequestVerbose): print red(" *")+" Log file at: "+outfile - print - print - print red(" ***")+" Cannot continue" + print_error(red(" *")+" Compile error") + if (not enzymeRequestVerbose): print_info(red(" *")+" Log file at: "+outfile) + #print + #print + print_error(red(" ***")+" Cannot continue") sys.exit(250) if toBeBuilt != []: - print - print green(" *")+" Building packages..." + #print + print_info(green(" *")+" Building packages...") for dep in toBeBuilt: outfile = etpConst['packagestmpdir']+"/.emerge-"+str(getRandomNumber()) - print green(" *")+" Compiling: "+red(dep) + print_info(green(" *")+" Compiling: "+red(dep)) if (not enzymeRequestVerbose): - print yellow(" *")+" redirecting output to: "+green(outfile) + print_info(yellow(" *")+" redirecting output to: "+green(outfile)) rc, outfile = emerge("="+dep, odbNodeps, outfile, "&>", enzymeRequestSimulation) else: rc, outfile = emerge("="+dep,odbNodeps, None, None, enzymeRequestSimulation) if (not rc): # compilation is fine - print green(" *")+" Compiled successfully" + print_info(green(" *")+" Compiled successfully") PackagesQuickpkg.append("quick|"+dep) if os.path.isfile(outfile): os.remove(outfile) else: - print red(" *")+" Compile error" - if (not enzymeRequestVerbose): print red(" *")+" Log file at: "+outfile - print - print - print red(" ***")+" Cannot continue" + print_error(red(" *")+" Compile error") + if (not enzymeRequestVerbose): print_info(red(" *")+" Log file at: "+outfile) + #print + #print + print_error(red(" ***")+" Cannot continue") sys.exit(250) if (enzymeRequestInteraction): # interaction needed - print green(" *")+" Running etc-update..." + print_info(green(" *")+" Running etc-update...") spawnCommand("etc-update") else: - print green(" *")+" Auto-running etc-update..." + print_info(green(" *")+" Auto-running etc-update...") spawnCommand("echo -5 | etc-update") - print + #print if (PackagesQuickpkg != []) or (toBeQuickpkg != []): - print green(" *")+" Compressing installed packages..." + print_info(green(" *")+" Compressing installed packages...") for dep in toBeQuickpkg: dep = dep.split("|")[len(dep.split("|"))-1] - print green(" *")+" Compressing: "+red(dep) + print_info(green(" *")+" Compressing: "+red(dep)) rc = quickpkg(dep,etpConst['packagesstoredir']) if (rc is not None): packagesPaths.append(rc) else: - print red(" *")+" quickpkg error for "+red(dep) - print red(" ***")+" Fatal error, cannot continue" + print_error(red(" *")+" quickpkg error for "+red(dep)) + print_error(red(" ***")+" Fatal error, cannot continue") sys.exit(251) for dep in PackagesQuickpkg: dep = dep.split("|")[len(dep.split("|"))-1] - print green(" *")+" Compressing: "+red(dep) + print_info(green(" *")+" Compressing: "+red(dep)) rc = quickpkg(dep,etpConst['packagesstoredir']) if (rc is not None): packagesPaths.append(rc) else: - print red(" *")+" quickpkg error for "+red(dep) - print red(" ***")+" Fatal 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 red(" *")+" These are the binary packages created:" + #print + print_info(red(" *")+" These are the binary packages created:") for pkg in packagesPaths: - print green(" * ")+red(pkg) + print_info(green(" * ")+red(pkg)) return packagesPaths @@ -570,3 +569,97 @@ def overlay(options): return True +def uninstall(options): + + # FIXME: add --prune option? (--just-prune) + + # Filter extra commands + enzymeRequestVerbose = False + enzymeRequestSimulation = False + enzymeRequestPrune = False + _atoms = [] + for i in options: + if ( i == "--verbose" ) or ( i == "-v" ): + enzymeRequestVerbose = True + 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 = [] + for i in atoms: + if (enzymeRequestVerbose): print_info(i+" is valid?: "+str(checkAtom(i))) + if (checkAtom(i)) and (getInstalledAtom(dep_getkey(i)) != None): + validAtoms.append(i) + 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)) + + if validAtoms == []: + print_error(red(bold("no valid package names specified."))) + sys.exit(102) + + if (not enzymeRequestPrune): + 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) + installedVers = [] + for i in installedAtoms: + pkgname, pkgver = extractPkgNameVer(i) + installedVers.append(pkgver) + if len(installedVers) > 1: + import string + x = string.join(installedVers) + print_info(yellow(" *")+" [REMOVE] "+bold(i)+" [ selected: "+red(x)+" ]") + else: + print_info(yellow(" *")+" [REMOVE] "+bold(i)) + else: + # 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: + 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") + selected = None + protected = None + omitted = None + for i in rc: + if i.find("selected:") != -1: + selected = i.strip().split(":")[1] + if i.find("protected:") != -1: + protected = i.strip().split(":")[1] + if i.find("omitted:") != -1: + omitted = i.strip().split(":")[1] + print_info(yellow(" *")+" [PRUNE] "+bold(atom)+" [ selected:"+red(selected)+"; protected:"+green(protected)+"; omitted:"+yellow(omitted)+" ]") + else: + print_info(green(" *")+" No packages to prune.") + + # if --pretend, end here + if (enzymeRequestSimulation): + sys.exit(0) + + + # now wrap emerge -C + \ No newline at end of file diff --git a/libraries/reagentTools.py b/libraries/reagentTools.py index ebb691084..9095023a5 100644 --- a/libraries/reagentTools.py +++ b/libraries/reagentTools.py @@ -65,8 +65,8 @@ def extractPkgData(package): tbz2File = package - package = package.split(".tbz2") - package = package[0].split("-") + package = package.split(".tbz2")[0] + package = package.split("-") pkgname = "" pkglen = len(package) if package[pkglen-1].startswith("r"):