diff -uNr pym.orig/portage.py pym/portage.py --- pym.orig/portage.py 2003-09-16 21:03:41.000000000 +0200 +++ pym/portage.py 2003-09-16 22:49:26.000000000 +0200 @@ -78,7 +78,7 @@ sys.stderr.write(red("*** Please add this user to the portage group if you wish to use portage.\n")) sys.stderr.write("\n") -incrementals=["USE","FEATURES","ACCEPT_KEYWORDS","ACCEPT_LICENSE","CONFIG_PROTECT_MASK","CONFIG_PROTECT","PRELINK_PATH","PRELINK_PATH_MASK"] +incrementals=["USE","FEATURES","ACCEPT_KEYWORDS","ACCEPT_LICENSE","CONFIG_PROTECT_MASK","CONFIG_PROTECT","CLEAN_PROTECT_MASK","CLEAN_PROTECT","PRELINK_PATH","PRELINK_PATH_MASK"] stickies=["KEYWORDS_ACCEPT","USE","CFLAGS","CXXFLAGS","MAKEOPTS","EXTRA_ECONF","EXTRA_EMAKE"] def getcwd(): @@ -437,7 +437,7 @@ continue pos=pos+1 - specials={"KDEDIRS":[],"PATH":[],"CLASSPATH":[],"LDPATH":[],"MANPATH":[],"INFODIR":[],"INFOPATH":[],"ROOTPATH":[],"CONFIG_PROTECT":[],"CONFIG_PROTECT_MASK":[],"PRELINK_PATH":[],"PRELINK_PATH_MASK":[]} + specials={"KDEDIRS":[],"PATH":[],"CLASSPATH":[],"LDPATH":[],"MANPATH":[],"INFODIR":[],"INFOPATH":[],"ROOTPATH":[],"CONFIG_PROTECT":[],"CONFIG_PROTECT_MASK":[],"CLEAN_PROTECT":[],"CLEAN_PROTECT_MASK":[],"PRELINK_PATH":[],"PRELINK_PATH_MASK":[]} env={} for x in fns: @@ -532,7 +532,7 @@ if len(specials[path])==0: continue outstring="export "+path+"='" - if path in ["CONFIG_PROTECT","CONFIG_PROTECT_MASK"]: + if path in ["CONFIG_PROTECT","CONFIG_PROTECT_MASK","CLEAN_PROTECT","CLEAN_PROTECT_MASK"]: for x in specials[path][:-1]: outstring += x+" " else: @@ -1918,11 +1918,26 @@ #shell error code return mylink.merge(pkgloc,infloc,myroot,myebuild) -def unmerge(cat,pkg,myroot,mytrimworld=1): +def unmerge(cat,pkg,myroot,mytrimworld=1,protector=""): + # clnpro: Here, the protector is a cpv string, and we'll give an opened /db/c/pv/CONTENTS + # file to the dblink.unmerge() call. + # If no protector is given, don't worry, it's not an error but a real unmerge + # instead of a clean or prune. + myprotfile=None + if protector: + myprotcat=string.split(protector,"/")[0] + myprotpkg=string.split(protector,"/")[1] + myprotfilename=myroot+"///var/db/pkg/"+myprotcat+"/"+myprotpkg+"/CONTENTS" + if not os.path.exists(myprotfilename) or (cat==myprotcat and pkg==myprotpkg): + print "!!! Wrong protector. This shouldn't happen." + else: + myprotfile=open(myprotfilename,"a") mylink=dblink(cat,pkg,myroot) if mylink.exists(): - mylink.unmerge(trimworld=mytrimworld) + mylink.unmerge(trimworld=mytrimworld,protectfile=myprotfile) mylink.delete() + if (myprotfile != None): + myprotfile.close() def relparse(myver): "converts last version part into three components" @@ -4306,6 +4321,21 @@ if os.path.isdir(ppath): self.protectmask.append(ppath) #if it doesn't exist, silently skip it + + #clnpro: update protection path + self.cleanprotect=[] + for x in string.split(settings["CLEAN_PROTECT"]): + ppath=os.path.normpath(self.myroot+"/"+x)+"/" + if os.path.isdir(ppath): + self.cleanprotect.append(ppath) + #if it doesn't exist, silently skip it + #clnpro: is a masked relly needed? + self.cleanprotectmask=[] + for x in string.split(settings["CLEAN_PROTECT_MASK"]): + ppath=os.path.normpath(self.myroot+"/"+x)+"/" + if os.path.isdir(ppath): + self.cleanprotectmask.append(ppath) + #if it doesn't exist, silently skip it def isprotected(self,obj): """Checks if obj is in the current protect/mask directories. Returns @@ -4322,7 +4352,25 @@ masked=len(pmpath) return (protected > masked) - def unmerge(self,pkgfiles=None,trimworld=1): + def iscleanprotected(self,obj): + """Checks if obj is in the current clean protect/mask directories. Returns + 0 on unprotected/masked, and 1 on protected.""" + masked=0 + protected=0 + for ppath in self.cleanprotect: + if (len(ppath) > masked) and (obj[0:len(ppath)]==ppath): + protected=len(ppath) + #clnpro file management + for pmpath in self.cleanprotectmask: + if (len(pmpath) >= protected) and (obj[0:len(pmpath)]==pmpath): + #skip, it's in the mask + masked=len(pmpath) + return (protected > masked) + + def unmerge(self,pkgfiles=None,trimworld=1,protectfile=None): + # clnpro: Here, protectfile is an opened /db/c/pv/CONTENTS file. + # If a file to unmerge is protected, then it will instead be recorded in protectfile. + # If protectfile=None, it means that we are doing a real unmerge, not just a clean/prune. global dircache dircache={} @@ -4393,6 +4441,13 @@ if mymd5 != string.lower(pkgfiles[obj][2]): print "--- !md5 ","obj", obj continue + if self.iscleanprotected(obj) and (protectfile != None): + #clnpro: this object must be protected + print "--- clnpro "+str(pkgfiles[obj][0]), obj + contentsentry="obj "+obj+" "+pkgfiles[obj][2]+" "+pkgfiles[obj][1]+"\n" + #print contentsentry + protectfile.write(contentsentry) + continue try: os.unlink(obj) except (OSError,IOError),e: @@ -4402,6 +4457,15 @@ if not S_ISFIFO(lstatobj[ST_MODE]): print "--- !fif ","fif", obj continue + #if self.iscleanprotected(obj) and (protectfile != None): + # #clnpro: should a fifo be protected? + # #this may introduce duplicates, because they lacks mtime/md5. + # #have to check existing CONTENTS + # print "--- clnpro "+str(pkgfiles[obj][0]), obj + # contentsentry="fif "+obj+"\n" + # print contentsentry + # #protectfile.write(contentsentry) + # continue try: os.unlink(obj) except (OSError,IOError),e: @@ -4409,6 +4473,7 @@ print "<<< ","fif",obj elif pkgfiles[obj][0]=="dev": print "--- ","dev",obj + #clnpro: since devs never get cleaned, no need to protect them. #Now, we need to remove symlinks and directories. We'll repeatedly #remove dead symlinks, then directories until we stop making progress. @@ -4425,7 +4490,8 @@ progress=0 #step 1: remove all the dead symlinks we can... - + #clnpro:symlinks protection not yet implemented. + #(what if target does not match? keep or forget?) pos = 0 while pos>> Safely unmerging already-installed instance..." - self.unmerge(oldcontents,trimworld=0) - print ">>> original instance of package unmerged safely." + self.unmerge(oldcontents,trimworld=0,protectfile=outfile) + print ">>> original instance of package unmerged safely." + #if we opened it, close it + outfile.close() # copy "info" files (like SLOT, CFLAGS, etc.) into the database for x in listdir(inforoot): self.copyfile(inforoot+"/"+x) diff -uNr bin.orig/emerge bin/emerge --- bin.orig/emerge 2003-09-16 21:03:21.000000000 +0200 +++ bin/emerge 2003-09-16 21:44:02.000000000 +0200 @@ -1480,6 +1480,7 @@ print darkgreen("\n>>> These are the packages that I would unmerge:") pkgmap={} + cleanprotmap={} numselected=0 for x in candidate_catpkgs: #cycle through all our candidate deps and determine what will and will not get unmerged @@ -1517,12 +1518,16 @@ continue counterkeys.sort() pkgmap[mykey]["protected"].append(slotmap[myslot][counterkeys[-1]]) + protpkg=slotmap[myslot][counterkeys[-1]] del counterkeys[-1] #be pretty and get them in order of merge: for ckey in counterkeys: pkgmap[mykey]["selected"].append(slotmap[myslot][ckey]) + cleanprotmap[slotmap[myslot][ckey]]=protpkg numselected=numselected+1 #ok, now the last-merged package is protected, and the rest are selected + # clnpro: now, cleanprotmap should contain selected_cpv:protected_cpv entries for + # each selected pkg. if global_unmerge and not numselected: print "\n>>> No outdated packages were found on your system.\n" return 0 @@ -1581,7 +1586,11 @@ emergelog("=== Unmerging... ("+y+")") mysplit=string.split(y,"/") #unmerge... - retval=portage.unmerge(mysplit[0],mysplit[1],portage.root,unmerge_action not in ["clean","prune"]) + #clnpro: we add the protecting cpv to the unmerge call + if cleanprotmap.has_key(y): + retval=portage.unmerge(mysplit[0],mysplit[1],portage.root,unmerge_action not in ["clean","prune"],protector=cleanprotmap[y]) + else: + retval=portage.unmerge(mysplit[0],mysplit[1],portage.root,unmerge_action not in ["clean","prune"]) if retval: emergelog(" !!! unmerge FAILURE: "+y) else: