From 7c3f15529ec0dbf4c835b731c1098d5c4d652e66 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Sun, 21 Oct 2007 12:24:56 +0000 Subject: [PATCH] Merged from trunk 8141:8142 (Manually applied) | 8142 | Move the emerge module to _emerge to make it private since | | zmedico | it's mostly unsuitable for api consumers at this time. | svn path=/main/branches/prefix/; revision=8209 --- pym/_emerge/__init__.py | 140 +++++++++++------------------------ pym/portage/news.py | 61 +++++++-------- pym/portage/sets/__init__.py | 26 ++++--- pym/portage/sets/dbapi.py | 13 +++- pym/portage/sets/files.py | 25 +++++++ 5 files changed, 120 insertions(+), 145 deletions(-) diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index ef3a42dc8..71bac6346 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -362,6 +362,22 @@ def create_depgraph_params(myopts, myaction): myparams.add("deep") return myparams + +class EmergeConfig(portage.config): + def __init__(self, settings, trees=None, setconfig=None): + """ You have to specify one of trees or setconfig """ + portage.config.__init__(self, clone=settings) + if not setconfig: + setconfigpaths = [os.path.join(GLOBAL_CONFIG_PATH, "sets.conf")] + setconfigpaths.append(os.path.join(settings["PORTDIR"], "sets.conf")) + setconfigpaths += [os.path.join(x, "sets.conf") for x in settings["PORDIR_OVERLAY"].split()] + setconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"], + USER_CONFIG_PATH.lstrip(os.path.sep), "sets.conf")) + #setconfig = SetConfig(setconfigpaths, settings, trees) + setconfig = make_default_config(settings, trees) + self.setconfig = setconfig + self.sets = self.setconfig.getSetsWithAliases() + # search functionality class search(object): @@ -375,7 +391,7 @@ class search(object): # public interface # def __init__(self, settings, portdb, vartree, spinner, searchdesc, - verbose, setconfig): + verbose): """Searches the available and installed packages for the supplied search key. The list of available and installed packages is created at object instantiation. This makes successive searches faster.""" @@ -385,7 +401,7 @@ class search(object): self.spinner = spinner self.verbose = verbose self.searchdesc = searchdesc - self.setconfig = setconfig + self.setconfig = settings.setconfig def execute(self,searchkey): """Performs the search for the supplied search key""" @@ -443,7 +459,7 @@ class search(object): if self.searchre.search(full_desc): self.matches["desc"].append([full_package,masked]) - self.sdict = self.setconfig.getSets()[0] + self.sdict = self.setconfig.getSets() for setname in self.sdict: self.spinner.update() if match_category: @@ -555,76 +571,13 @@ class search(object): return result -#build our package digraph -def getlist(settings, mode): - if mode=="system": - mylines = settings.packages - elif mode=="world": - try: - file_path = os.path.join(settings["ROOT"], portage.WORLD_FILE) - myfile = open(file_path, "r") - mylines = myfile.readlines() - myfile.close() - except (OSError, IOError), e: - if e.errno == errno.ENOENT: - portage.writemsg("\n!!! World file does not exist: '%s'\n" % file_path) - mylines=[] - else: - raise - mynewlines=[] - for x in mylines: - myline=" ".join(x.split()) - if not len(myline): - continue - elif myline[0]=="#": - continue - elif mode=="system": - if myline[0]!="*": - continue - myline=myline[1:] - mynewlines.append(myline.strip()) - - return mynewlines - -def clean_world(vardb, cpv): - """Remove a package from the world file when unmerged.""" - world_set = WorldSet(vardb.settings["ROOT"]) - world_set.lock() - worldlist = list(world_set) # loads latest from disk - mykey = portage.cpv_getkey(cpv) - newworldlist = [] - for x in worldlist: - if portage.dep_getkey(x) == mykey: - matches = vardb.match(x, use_cache=0) - if not matches: - #zap our world entry - pass - elif len(matches) == 1 and matches[0] == cpv: - #zap our world entry - pass - else: - #others are around; keep it. - newworldlist.append(x) - else: - #this doesn't match the package we're unmerging; keep it. - newworldlist.append(x) - - world_set.replace(newworldlist) - world_set.unlock() - - class RootConfig(object): """This is used internally by depgraph to track information about a particular $ROOT.""" def __init__(self, trees): self.trees = trees - self.settings = trees["vartree"].settings + self.settings = EmergeConfig(trees["vartree"].settings, trees=trees) self.root = self.settings["ROOT"] - self.sets = {} - world_set = WorldSet(self.root) - self.sets["world"] = world_set - system_set = SystemSet(self.settings.profiles) - self.sets["system"] = system_set def create_world_atom(pkg_key, metadata, args_set, root_config): """Create a new atom for the world file if one does not exist. If the @@ -636,7 +589,7 @@ def create_world_atom(pkg_key, metadata, args_set, root_config): arg_atom = args_set.findAtomForPackage(pkg_key, metadata) cp = portage.dep_getkey(arg_atom) new_world_atom = cp - sets = root_config.sets + sets = root_config.settings.sets portdb = root_config.trees["porttree"].dbapi vardb = root_config.trees["vartree"].dbapi available_slots = set(portdb.aux_get(cpv, ["SLOT"])[0] \ @@ -2769,8 +2722,8 @@ class depgraph(object): world_problems = False root_config = self.roots[self.target_root] - world_set = root_config.sets["world"] - system_set = root_config.sets["system"] + world_set = root_config.settings.sets["world"] + system_set = root_config.settings.sets["system"] mylist = list(system_set) self._sets["system"] = system_set if mode == "world": @@ -3358,8 +3311,8 @@ class depgraph(object): pkg_cp = xs[0] root_config = self.roots[myroot] - system_set = root_config.sets["system"] - world_set = root_config.sets["world"] + system_set = root_config.settings.sets["system"] + world_set = root_config.settings.sets["world"] pkg_system = False pkg_world = False @@ -3572,7 +3525,7 @@ class depgraph(object): if x in self.myopts: return root_config = self.roots[self.target_root] - world_set = root_config.sets["world"] + world_set = root_config.settings.sets["world"] world_set.lock() world_set.load() # maybe it's changed on disk args_set = self._sets["args"] @@ -3765,10 +3718,10 @@ class MergeTask(object): if settings.get("PORTAGE_DEBUG", "") == "1": self.edebug = 1 self.pkgsettings = {} - self.pkgsettings[self.target_root] = portage.config(clone=settings) + self.pkgsettings[self.target_root] = EmergeConfig(settings, setconfig=settings.setconfig) if self.target_root != "/": self.pkgsettings["/"] = \ - portage.config(clone=trees["/"]["vartree"].settings) + EmergeConfig(trees["/"]["vartree"].settings, setconfig=settings.setconfig) self.curval = 0 def merge(self, mylist, favorites, mtimedb): @@ -3835,9 +3788,9 @@ class MergeTask(object): del shown_verifying_msg, quiet_settings root_config = RootConfig(self.trees[self.target_root]) - system_set = root_config.sets["system"] + system_set = root_config.settings.sets["system"] args_set = InternalPackageSet(favorites) - world_set = root_config.sets["world"] + world_set = root_config.settings.sets["world"] if "--resume" not in self.myopts: mymergelist = mylist mtimedb["resume"]["mergelist"]=mymergelist[:] @@ -4254,7 +4207,7 @@ def unmerge(settings, myopts, vartree, unmerge_action, unmerge_files, try: if os.access(vdb_path, os.W_OK): vdb_lock = portage.locks.lockdir(vdb_path) - realsyslist = getlist(settings, "system") + realsyslist = settings.sets["system"].getAtoms() syslist = [] for x in realsyslist: mycp = portage.dep_getkey(x) @@ -4289,7 +4242,7 @@ def unmerge(settings, myopts, vartree, unmerge_action, unmerge_files, if not unmerge_files or "world" in unmerge_files: candidate_catpkgs.extend(vartree.dbapi.cp_all()) elif "system" in unmerge_files: - candidate_catpkgs.extend(getlist(settings, "system")) + candidate_catpkgs.extend(settings.sets["system"].getAtoms()) else: #we've got command-line arguments if not unmerge_files: @@ -4541,7 +4494,7 @@ def unmerge(settings, myopts, vartree, unmerge_action, unmerge_files, show_unmerge_failure_message(y, ebuild, retval) sys.exit(retval) else: - clean_world(vartree.dbapi, y) + settings.sets["world"].cleanPackage(vartree.dbapi, y) emergelog(xterm_titles, " >>> unmerge success: "+y) return 1 @@ -5730,13 +5683,13 @@ def action_info(settings, trees, myopts, myfiles): mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, tree="vartree") -def action_search(settings, portdb, vartree, myopts, myfiles, spinner, setconfig): +def action_search(settings, portdb, vartree, myopts, myfiles, spinner): if not myfiles: print "emerge: no search terms provided." else: searchinstance = search(settings, portdb, vartree, spinner, "--searchdesc" in myopts, - "--quiet" not in myopts, setconfig) + "--quiet" not in myopts) for mysearch in myfiles: try: searchinstance.execute(mysearch) @@ -6475,9 +6428,12 @@ def load_emerge_config(trees=None): if myroot != "/": settings = trees[myroot]["vartree"].settings break + + settings = EmergeConfig(settings, trees=trees[settings["ROOT"]]) mtimedbfile = os.path.join("/", portage.CACHE_PATH.lstrip(os.path.sep), "mtimedb") mtimedb = portage.MtimeDB(mtimedbfile) + return settings, trees, mtimedb def adjust_config(myopts, settings): @@ -6660,28 +6616,20 @@ def emerge_main(): print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n") break - setconfigpaths = [os.path.join(GLOBAL_CONFIG_PATH, "sets.conf")] - setconfigpaths.append(os.path.join(settings["PORTDIR"], "sets.conf")) - setconfigpaths += [os.path.join(x, "sets.conf") for x in settings["PORDIR_OVERLAY"].split()] - setconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"], - USER_CONFIG_PATH.lstrip(os.path.sep), "sets.conf")) - #setconfig = SetConfig(setconfigpaths, settings, trees[settings["ROOT"]]) - setconfig = make_default_config(settings, trees[settings["ROOT"]]) - del setconfigpaths + # only expand sets for actions taking package arguments if myaction not in ["search", "metadata", "sync"]: oldargs = myfiles[:] - packagesets, setconfig_errors = setconfig.getSetsWithAliases() - for s in packagesets: + for s in settings.sets: if s in myfiles: # TODO: check if the current setname also resolves to a package name if myaction in ["unmerge", "prune", "clean", "depclean"] and not packagesets[s].supportsOperation("unmerge"): print "emerge: the given set %s does not support unmerge operations" % s sys.exit(1) - if not packagesets[s].getAtoms(): + if not settings.sets[s].getAtoms(): print "emerge: '%s' is an empty set" % s else: - myfiles.extend(packagesets[s].getAtoms()) - for e in packagesets[s].errors: + myfiles.extend(settings.sets[s].getAtoms()) + for e in settings.sets[s].errors: print e myfiles.remove(s) # Need to handle empty sets specially, otherwise emerge will react @@ -6879,7 +6827,7 @@ def emerge_main(): elif "search"==myaction: validate_ebuild_environment(trees) action_search(settings, portdb, trees["/"]["vartree"], - myopts, myfiles, spinner, setconfig) + myopts, myfiles, spinner) elif myaction in ("clean", "unmerge") or \ (myaction == "prune" and "--nodeps" in myopts): validate_ebuild_environment(trees) diff --git a/pym/portage/news.py b/pym/portage/news.py index dff66e3da..6f2eac2b2 100644 --- a/pym/portage/news.py +++ b/pym/portage/news.py @@ -6,7 +6,7 @@ import os import re from portage.const import INCREMENTALS, PROFILE_PATH, NEWS_LIB_PATH -from portage.util import ensure_dirs, apply_permissions, normalize_path +from portage.util import ensure_dirs, apply_permissions, normalize_path, grabfile, write_atomic from portage.data import portage_gid from portage.locks import lockfile, unlockfile, lockdir, unlockdir from portage.exception import FileNotFound @@ -19,20 +19,16 @@ class NewsManager(object): Creating a news manager requires: root - typically ${ROOT} see man make.conf and man emerge for details - NEWS_PATH - path to news items; usually $REPODIR/metadata/news - UNREAD_PATH - path to the news.repoid.unread file; this helps us track news items + news_path - path to news items; usually $REPODIR/metadata/news + unread_path - path to the news.repoid.unread file; this helps us track news items """ - TIMESTAMP_FILE = 'news-timestamp' - - def __init__(self, portdb, vardb, NEWS_PATH, UNREAD_PATH, LANGUAGE_ID='en'): - self.NEWS_PATH = NEWS_PATH - self.UNREAD_PATH = UNREAD_PATH - self.TIMESTAMP_PATH = os.path.join(vardb.root, - NEWS_LIB_PATH, NewsManager.TIMESTAMP_FILE) + def __init__(self, portdb, vardb, news_path, unread_path, language_id='en'): + self.news_path = news_path + self.unread_path = unread_path self.target_root = vardb.root - self.LANGUAGE_ID = LANGUAGE_ID + self.language_id = language_id self.config = vardb.settings self.vdb = vardb self.portdb = portdb @@ -48,7 +44,7 @@ class NewsManager(object): # Ensure that the unread path exists and is writable. dirmode = 02070 modemask = 02 - ensure_dirs(self.UNREAD_PATH, mode=dirmode, mask=modemask, gid=portage_gid) + ensure_dirs(self.unread_path, mode=dirmode, mask=modemask, gid=portage_gid) def updateItems(self, repoid): """ @@ -61,35 +57,31 @@ class NewsManager(object): if repoid not in repos: raise ValueError("Invalid repoID: %s" % repoid) - timestamp_file = self.TIMESTAMP_PATH + repoid - if os.path.exists(timestamp_file): - # Make sure the timestamp has correct permissions. - apply_permissions(filename=timestamp_file, - uid=int(self.config["PORTAGE_INST_UID"]), gid=portage_gid, mode=0664) - timestamp = os.stat(timestamp_file).st_mtime - else: - timestamp = 0 - - path = os.path.join(self.portdb.getRepositoryPath(repoid), self.NEWS_PATH) + path = os.path.join(self.portdb.getRepositoryPath(repoid), self.news_path) # Skip reading news for repoid if the news dir does not exist. Requested by # NightMorph :) if not os.path.exists(path): return None news = os.listdir(path) + + skipfile = os.path.join(self.unread_path, "news-%s.skip" % repoid) + skiplist = grabfile(skipfile) updates = [] for itemid in news: + if itemid in skiplist: + continue try: - filename = os.path.join(path, itemid, itemid + "." + self.LANGUAGE_ID + ".txt") - item = NewsItem(filename, itemid, timestamp) - except (TypeError, ValueError): + filename = os.path.join(path, itemid, itemid + "." + self.language_id + ".txt") + item = NewsItem(filename, itemid) + except (TypeError): continue if item.isRelevant(profile=self._profile_path, config=self.config, vardb=self.vdb): updates.append(item) del path - path = os.path.join(self.UNREAD_PATH, 'news-' + repoid + '.unread') + path = os.path.join(self.unread_path, 'news-%s.unread' % repoid) try: unread_lock = lockfile(path) if not os.path.exists(path): @@ -103,13 +95,13 @@ class NewsManager(object): for item in updates: unread_file.write(item.name + "\n") + skiplist.append(item.name) unread_file.close() finally: unlockfile(unread_lock) - - # Touch the timestamp file - f = open(timestamp_file, 'w') - f.close() + write_atomic(skipfile, "\n".join(skiplist)+"\n") + apply_permissions(filename=skipfile, + uid=int(self.config["PORTAGE_INST_UID"]), gid=portage_gid, mode=0664) def getUnreadItems(self, repoid, update=False): """ @@ -122,7 +114,7 @@ class NewsManager(object): if update: self.updateItems(repoid) - unreadfile = os.path.join(self.UNREAD_PATH, 'news-' + repoid + '.unread') + unreadfile = os.path.join(self.unread_path, 'news-%s.unread' % repoid) try: try: unread_lock = lockfile(unreadfile) @@ -156,15 +148,12 @@ class NewsItem(object): """ - def __init__(self, path, name, cache_mtime = 0): + def __init__(self, path, name): """ - For a given news item we only want if it path is a file and it's - mtime is newer than the cache'd timestamp. + For a given news item we only want if it path is a file. """ if not os.path.isfile(path): raise TypeError("%s is no regular file" % path) - if not os.stat(path).st_mtime > cache_mtime: - raise ValueError("%s / %s timestamp mismatch" % (str(os.stat(path).st_mtime), str(cache_mtime))) self.path = path self.name = name self._parsed = False diff --git a/pym/portage/sets/__init__.py b/pym/portage/sets/__init__.py index dc281dea3..ac3f4b0cb 100644 --- a/pym/portage/sets/__init__.py +++ b/pym/portage/sets/__init__.py @@ -179,6 +179,8 @@ class SetConfig(SafeConfigParser): self.trees = trees self.settings = settings self._parsed = False + self.active = [] + self.aliases = {} def _parse(self): if self._parsed: @@ -230,20 +232,22 @@ class SetConfig(SafeConfigParser): def getSets(self): self._parse() - return (self.psets, self.errors) + return self.psets def getSetsWithAliases(self): self._parse() - shortnames = {} - for name in self.psets: - mysplit = name.split("/") - if len(mysplit) > 1 and mysplit[0] == "sets" and mysplit[-1] != "": - if mysplit[-1] in shortnames: - del shortnames[mysplit[-1]] - else: - shortnames[mysplit[-1]] = self.psets[name] - shortnames.update(self.psets) - return (shortnames, self.errors) + if not self.aliases: + shortnames = {} + for name in self.psets: + mysplit = name.split("/") + if len(mysplit) > 1 and mysplit[0] == "sets" and mysplit[-1] != "": + if mysplit[-1] in shortnames: + del shortnames[mysplit[-1]] + else: + shortnames[mysplit[-1]] = self.psets[name] + shortnames.update(self.psets) + self.aliases = shortnames + return self.aliases def make_default_config(settings, trees): sc = SetConfig([], settings, trees) diff --git a/pym/portage/sets/dbapi.py b/pym/portage/sets/dbapi.py index fbff27054..bc842ae2c 100644 --- a/pym/portage/sets/dbapi.py +++ b/pym/portage/sets/dbapi.py @@ -113,9 +113,10 @@ class CategorySet(PackageSet): class LibraryConsumerSet(PackageSet): _operations = ["merge", "unmerge"] - def __init__(self, vardbapi): + def __init__(self, vardbapi, debug=False): super(LibraryConsumerSet, self).__init__() self.dbapi = vardbapi + self.debug = debug def mapPathsToAtoms(self, paths): rValue = set() @@ -162,11 +163,19 @@ class MissingLibraryConsumerSet(LibraryConsumerSet): found=True break if not found: + print "missing library: %s" % lib + print "consumers:" + for x in self.dbapi.libmap.get()[lib]: + print " ", x consumers.update(self.dbapi.libmap.get()[lib]) if not consumers: return self._setAtoms(self.mapPathsToAtoms(consumers)) def singleBuilder(cls, options, settings, trees): - return MissingLibraryConsumerSet(trees["vartree"].dbapi) + if options.get("debug", "true").lower() in ["true", "on", "1", "yes"]: + debug = True + else: + debug = False + return MissingLibraryConsumerSet(trees["vartree"].dbapi, debug=debug) singleBuilder = classmethod(singleBuilder) diff --git a/pym/portage/sets/files.py b/pym/portage/sets/files.py index 61ab1bc53..71a2ecd85 100644 --- a/pym/portage/sets/files.py +++ b/pym/portage/sets/files.py @@ -11,6 +11,7 @@ from portage import portage_gid from portage.sets import PackageSet, EditablePackageSet, SetConfigError from portage.env.loaders import ItemFileLoader, KeyListFileLoader from portage.env.validators import ValidAtomValidator +from portage import dep_getkey, cpv_getkey __all__ = ["StaticFileSet", "ConfigFileSet", "WorldSet"] @@ -135,6 +136,30 @@ class WorldSet(StaticFileSet): unlockfile(self._lock) self._lock = None + def cleanPackage(self, vardb, cpv): + self.lock() + worldlist = list(self.getAtoms()) # loads latest from disk + mykey = cpv_getkey(cpv) + newworldlist = [] + for x in worldlist: + if dep_getkey(x) == mykey: + matches = vardb.match(x, use_cache=0) + if not matches: + #zap our world entry + pass + elif len(matches) == 1 and matches[0] == cpv: + #zap our world entry + pass + else: + #others are around; keep it. + newworldlist.append(x) + else: + #this doesn't match the package we're unmerging; keep it. + newworldlist.append(x) + + self.replace(newworldlist) + self.unlock() + def singleBuilder(self, options, settings, trees): return WorldSet(settings["ROOT"]) singleBuilder = classmethod(singleBuilder) -- 2.26.2