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):
# 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."""
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"""
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:
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
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] \
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":
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
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"]
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):
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[:]
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)
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:
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
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)
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):
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
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)
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
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
# 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):
"""
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):
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):
"""
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)
"""
- 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