dict[foo] = default_value
The get call is nicer (compact) and faster (try,except are slow).
+
+Imports
+-------
+
+Import things one per line
+
+YES:
+ import os
+ import time
+ import sys
+
+NO:
+ import os,sys,time
+
+When importing from a module, you may import more than 1 thing at a time.
+
+YES:
+ from portage.module import foo, bar, baz
+
+Multiline imports are ok (for now :))
+
+Try to group system and package imports separately.
+
+YES:
+ import os
+ import sys
+ import time
+
+ from portage.locks import lockfile
+ from portage.versions import vercmp
+
+NO:
+ import os
+ import portage
+ import portage.util
+ import time
+ import sys
used in ACCEPT_KEYWORDS.
For packages that don't specify any other KEYWORDS you can use the new ** token
as documented in portage(5) to disable KEYWORDS filtering completely.
-* Portage now warns if a ebild repository does not have a name, as several new
+* Portage now warns if an ebuild repository does not have a name, as several new
features in 2.2 make use of or require named repositories. The repository name
is stored in profiles/repo_name in each repository.
unrar x -idq -o+ "${srcdir}/${x}" || die "$myfail"
;;
LHa|LHA|lha|lzh)
- lha xqf "${srcdir}/${x}" || die "$myfail"
+ lha xfq "${srcdir}/${x}" || die "$myfail"
;;
deb)
# Unpacking .deb archives can not always be done with
from portage.data import secpass
from portage.util import normalize_path as normpath
from portage.util import writemsg
-from portage.sets import InternalPackageSet
+from portage.sets.dbapi import InternalPackageSet
from portage.sets.profiles import PackagesSystemSet as SystemSet
from portage.sets.files import WorldSet
blocksize = HASHING_BLOCKSIZE
data = f.read(blocksize)
size = 0L
- sum = hashobject()
+ checksum = hashobject()
while data:
- sum.update(data)
+ checksum.update(data)
size = size + len(data)
data = f.read(blocksize)
f.close()
- return (sum.hexdigest(), size)
+ return (checksum.hexdigest(), size)
hashfunc_map[hashtype] = pyhash
hashorigin_map[hashtype] = origin
return pyhash
from UserDict import UserDict
from portage.env.loaders import KeyListFileLoader, KeyValuePairFileLoader, ItemFileLoader
-class UserConfigKlass(UserDict,object):
+class ConfigLoaderKlass(UserDict, object):
"""
A base class stub for things to inherit from.
Users may want a non-file backend.
"""
- data = {}
-
def __init__(self, loader):
"""
@param loader: A class that has a load() that returns two dicts
the first being a data dict, the second being a dict of errors.
"""
+ UserDict.__init__(self)
self._loader = loader
def load(self):
def __iter__(self):
return iter(self.data)
-class PackageKeywordsFile(UserConfigKlass):
+class GenericFile(UserDict):
+ """
+ Inherits from ConfigLoaderKlass, attempts to use all known loaders
+ until it gets <something> in data. This is probably really slow but is
+ helpful when you really have no idea what you are loading (hint hint the file
+ should perhaps declare what type it is? ;)
+ """
+
+ loaders = [KeyListFileLoader, KeyValuePairFileLoader, ItemFileLoader]
+
+ def __init__(self, filename):
+ UserDict.__init__(self)
+ self.filename = filename
+
+ def load(self):
+ for loader in self.loaders:
+ l = loader(self.filename, None)
+ data, errors = l.load()
+ if len(data) and not len(errors):
+ (self.data, self.errors) = (data, errors)
+ return
+
+
+class PackageKeywordsFile(ConfigLoaderKlass):
"""
- Inherits from UserConfigKlass; implements a file-based backend.
+ Inherits from ConfigLoaderKlass; implements a file-based backend.
"""
default_loader = KeyListFileLoader
super(PackageKeywordsFile, self).__init__(
self.default_loader(filename, validator=None))
-class PackageUseFile(UserConfigKlass):
+class PackageUseFile(ConfigLoaderKlass):
"""
Inherits from PackageUse; implements a file-based backend. Doesn't handle recursion yet.
"""
super(PackageUseFile, self).__init__(
self.default_loader(filename, validator=None))
-class PackageMaskFile(UserConfigKlass):
+class PackageMaskFile(ConfigLoaderKlass):
"""
A class that implements a file-based package.mask
super(PackageMaskFile, self).__init__(
self.default_loader(filename, validator=None))
-class PortageModulesFile(UserConfigKlass):
+class PortageModulesFile(ConfigLoaderKlass):
"""
File Class for /etc/portage/modules
"""
@type error_msg: String
"""
- self.resource
+ self.resource = resource
+ self.error_msg = error_msg
def __str__(self):
return "Failed while loading resource: %s, error was: %s" % (
- resource, error_msg)
+ self.resource, self.error_msg)
+
def RecursiveFileLoader(filename):
"""
- If filename is of type file, return [filename]
- else if filename is of type directory, return an array
- full of files in that directory to process.
+ If filename is of type file, return a generate that yields filename
+ else if filename is of type directory, return a generator that fields
+ files in that directory.
Ignore files beginning with . or ending in ~.
Prune CVS directories.
"""
if os.path.isdir(filename):
- for root, dirs, files in os.walk(self.fname):
+ for root, dirs, files in os.walk(filename):
if 'CVS' in dirs:
dirs.remove('CVS')
- files = filter(files,startswith('.'))
- files = filter(files,endswith('~'))
- for file in files:
- yield file
+ files = filter(files, str.startswith('.'))
+ files = filter(files, str.endswith('~'))
+ for f in files:
+ yield f
else:
yield filename
+
class DataLoader(object):
- def __init__(self, validator=None):
+ def __init__(self, validator):
f = validator
if f is None:
# if they pass in no validator, just make a fake one
# that always returns true
- class AlwaysTrue(object):
- def validate(self, key):
- return True
- f = AlwaysTrue()
- self._validator = f
+ def validate(key):
+ return True
+ f = validate
+ self._validate = f
def load(self):
"""
Function to do the actual work of a Loader
"""
- pass
+ raise NotImplementedError("Please override in a subclass")
+
+
+class FileLoader(DataLoader):
+ """ Class to access data in files """
+
+ def __init__(self, filename, validator):
+ """
+ Args:
+ filename : Name of file or directory to open
+ validator : class with validate() method to validate data.
+ """
+ DataLoader.__init__(self, validator)
+ self.fname = filename
+
+ def load(self):
+ """
+ Return the {source: {key: value}} pairs from a file
+ Return the {source: [list of errors] from a load
+
+ @param recursive: If set and self.fname is a directory;
+ load all files in self.fname
+ @type: Boolean
+ @rtype: tuple
+ @returns:
+ Returns (data,errors), both may be empty dicts or populated.
+ """
+ data = {}
+ errors = {}
+ # I tried to save a nasty lookup on lineparser by doing the lookup
+ # once, which may be expensive due to digging in child classes.
+ func = self.lineParser
+ for fn in RecursiveFileLoader(self.fname):
+ f = open(fn, 'rb')
+ for line_num, line in enumerate(f):
+ func(line, line_num, data, errors)
+ return (data, errors)
+
+ def lineParser(self, line, line_num, data, errors):
+ """ This function parses 1 line at a time
+ Args:
+ line: a string representing 1 line of a file
+ line_num: an integer representing what line we are processing
+ data: a dict that contains the data we have extracted from the file
+ already
+ errors: a dict representing parse errors.
+ Returns:
+ Nothing (None). Writes to data and errors
+ """
+ raise NotImplementedError("Please over-ride this in a child class")
-class ItemFileLoader(DataLoader):
+class ItemFileLoader(FileLoader):
"""
Class to load data from a file full of items one per line
Note that due to the data store being a dict, duplicates
are removed.
"""
-
- _recursive = False
def __init__(self, filename, validator):
- DataLoader.__init__(self, validator)
- self.fname = filename
+ FileLoader.__init__(self, filename, validator)
- def load(self):
- data = {}
- errors = {}
- for file in RecursiveFileLoader(self.fname):
- f = open(file, 'rb')
- for line_num, line in enumerate(f):
- if line.startswith('#'):
- continue
- split = line.strip().split()
- if not len(split):
- errors.setdefault(self.fname,[]).append(
- "Malformed data at line: %s, data: %s"
- % (line_num + 1, split))
- key = split[0]
- if not self._validator.validate(key):
- errors.setdefault(self.fname,[]).append(
- "Validation failed at line: %s, data %s"
- % (line_num + 1, split))
- continue
- data[key] = None
- return (data, errors)
-
-class KeyListFileLoader(DataLoader):
+ def lineParser(self, line, line_num, data, errors):
+ line = line.strip()
+ if line.startswith('#'): # Skip commented lines
+ return
+ if not len(line): # skip empty lines
+ return
+ split = line.split()
+ if not len(split):
+ errors.setdefault(self.fname, []).append(
+ "Malformed data at line: %s, data: %s"
+ % (line_num + 1, line))
+ return
+ key = split[0]
+ if not self._validate(key):
+ errors.setdefault(self.fname, []).append(
+ "Validation failed at line: %s, data %s"
+ % (line_num + 1, key))
+ return
+ data[key] = None
+
+class KeyListFileLoader(FileLoader):
"""
Class to load data from a file full of key [list] tuples
{'key':['foo1','foo2','foo3']}
"""
- _recursive = False
-
def __init__(self, filename, validator):
- DataLoader.__init__(self, validator)
- self.fname = filename
-
- def load(self):
- data = {}
- errors = {}
- for file in RecursiveFileLoader(self.fname):
- f = open(file, 'rb')
- for line_num, line in enumerate(f):
- if line.startswith('#'):
- continue
- split = line.strip().split()
- if len(split) < 2:
- errors.setdefault(self.fname,[]).append(
- "Malformed data at line: %s, data: %s"
- % (line_num + 1, split))
- continue
- key = split[0]
- value = split[1:]
- if not self._validator.validate(key):
- errors.setdefault(self.fname,[]).append(
- "Validation failed at line: %s, data %s"
- % (line_num + 1, split))
- continue
- if key in data:
- data[key].append(value)
- else:
- data[key] = value
- return (data, errors)
-
-class KeyValuePairFileLoader(DataLoader):
+ FileLoader.__init__(self, filename, validator)
+
+
+ def lineParser(self, line, line_num, data, errors):
+ line = line.strip()
+ if line.startswith('#'): # Skip commented lines
+ return
+ if not len(line): # skip empty lines
+ return
+ split = line.split()
+ if len(split) < 2:
+ errors.setdefault(self.fname, []).append(
+ "Malformed data at line: %s, data: %s"
+ % (line_num + 1, line))
+ return
+ key = split[0]
+ value = split[1:]
+ if not self._validate(key):
+ errors.setdefault(self.fname, []).append(
+ "Validation failed at line: %s, data %s"
+ % (line_num + 1, key))
+ return
+ if key in data:
+ data[key].append(value)
+ else:
+ data[key] = value
+
+
+class KeyValuePairFileLoader(FileLoader):
"""
Class to load data from a file full of key=value pairs
'foo':'bar'}
"""
- _recursive = False
-
def __init__(self, filename, validator):
- DataLoader.__init__(self, validator)
- self.fname = filename
+ FileLoader.__init__(self, filename, validator)
+
+
+ def lineParser(self, line, line_num, data, errors):
+ line = line.strip()
+ if line.startswith('#'): # skip commented lines
+ return
+ if not len(line): # skip empty lines
+ return
+ split = line.split('=')
+ if len(split) < 2:
+ errors.setdefault(self.fname, []).append(
+ "Malformed data at line: %s, data %s"
+ % (line_num + 1, line))
+ return
+ key = split[0]
+ value = split[1:]
+ if not key:
+ errors.setdefault(self.fname, []).append(
+ "Malformed key at line: %s, key %s"
+ % (line_num + 1, key))
+ return
+ if not self._validate(key):
+ errors.setdefault(self.fname, []).append(
+ "Validation failed at line: %s, data %s"
+ % (line_num + 1, key))
+ return
+ if key in data:
+ data[key].append(value)
+ else:
+ data[key] = value
- def load(self):
- """
- Return the {source: {key: value}} pairs from a file
- Return the {source: [list of errors] from a load
-
- @param recursive: If set and self.fname is a directory;
- load all files in self.fname
- @type: Boolean
- @rtype: tuple
- @returns:
- Returns (data,errors), both may be empty dicts or populated.
- """
-
- DataLoader.load(self)
- data = {}
- errors = {}
- for file in RecursiveFileLoader(self.fname):
- f = open(file, 'rb')
- for line_num, line in enumerate(f):
- if line.startswith('#'):
- continue
- split = line.strip().split('=')
- if len(split) < 2:
- errors.setdefault(self.fname,[]).append(
- "Malformed data at line: %s, data %s"
- % (line_num + 1, split))
- key = split[0]
- value = split[1:]
- if not self._validator.validate(key):
- errors.setdefault(self.fname,[]).append(
- "Validation failed at line: %s, data %s"
- % (line_num + 1, split))
- continue
- if key in data:
- data[key].append(value)
- else:
- data[key] = value
- return (data, errors)
--- /dev/null
+# validators.py Portage File Loader Code
+# Copyright 2007 Gentoo Foundation
+# $Id$
+
+from portage.dep import isvalidatom
+
+ValidAtomValidator = isvalidatom
+
+def PackagesFileValidator(atom):
+ """ This function mutates atoms that begin with - or *
+ It then checks to see if that atom is valid, and if
+ so returns True, else it returns False.
+
+ Args:
+ atom: a string representing an atom such as sys-apps/portage-2.1
+ """
+ if atom.startswith("*") or atom.startswith("-"):
+ atom = atom[1:]
+ if not isvalidatom(atom):
+ return False
+ return True
# $Id: getbinpkg.py 3483 2006-06-10 21:40:40Z genone $
from portage.output import red, yellow, green
-import htmllib,HTMLParser,formatter,sys,os,portage.xpak,time,tempfile,base64,urllib2
+import portage.xpak
+import HTMLParser
+import sys
+import os
+import time
+import tempfile
+import base64
+import urllib2
from portage.const import CACHE_PATH
try:
try:
import ftplib
-except SystemExit, e:
- raise
-except Exception, e:
+except ImportError, e:
sys.stderr.write(red("!!! CANNOT IMPORT FTPLIB: ")+str(e)+"\n")
try:
import httplib
-except SystemExit, e:
- raise
-except Exception, e:
+except ImportError, e:
sys.stderr.write(red("!!! CANNOT IMPORT HTTPLIB: ")+str(e)+"\n")
def make_metadata_dict(data):
if not allow_overlap: # Not allow to overlap prefix and suffix
if len(x) >= (len(prefix)+len(suffix)):
- y = x[len(prefix):]
+ pass
else:
continue # Too short to match.
else:
- y = x # Do whatever... We're overlapping.
+ pass # Do whatever... We're overlapping.
if suffix and (len(x) >= len(suffix)) and (x[-len(suffix):] == suffix):
myarray.append(x) # It matches
conn,protocol,address,params,headers = create_conn(baseurl, conn)
- filedict = {}
-
try:
metadatafile = open(CACHE_PATH+"/remote_metadata.pickle")
metadata = cPickle.load(metadatafile)
# Determine if our metadata file is current.
metalist.sort()
metalist.reverse() # makes the order new-to-old.
- havecache=0
for mfile in metalist:
if usingcache and \
((metadata[baseurl]["indexname"] != mfile) or \
cpv_all = self.packages.keys()
cpv_all.sort()
if self.modified:
- import time
self.header["TIMESTAMP"] = str(long(time.time()))
self.header["PACKAGES"] = str(len(cpv_all))
keys = self.header.keys()
import os
import sys
import urllib
-import time
-import codecs
import re
import xml.dom.minidom
@rtype: Boolean
@returns: True if the system is affected, False if not
"""
- vList = []
rValue = False
for k in self.packages.keys():
pkg = self.packages[k]
path = os.path.join(self.portdb.getRepositoryPath(repoid), self.NEWS_PATH)
- repo_path = self.portdb.getRepositoryPath(repoid)
# Skip reading news for repoid if the news dir does not exist. Requested by
# NightMorph :)
if not os.path.exists(path):
try:
filename = os.path.join(path, itemid, itemid + "." + self.LANGUAGE_ID + ".txt")
item = NewsItem(filename, itemid, timestamp)
- except (TypeError, ValueError), e:
+ except (TypeError, ValueError):
continue
if item.isRelevant(profile=self._profile_path,
config=self.config, vardb=self.vdb):
__docformat__ = "epytext"
-import commands, errno, os, re, shlex, sys, time
+import commands
+import errno
+import os
+import re
+import shlex
+import sys
from portage.const import COLOR_MAP_FILE
from portage.util import writemsg
from portage.exception import PortageException, ParseError, PermissionDenied, FileNotFound
try:
s = shlex.shlex(open(myfile))
s.wordchars = s.wordchars + ";" # for ansi codes
- d = {}
while True:
k, o, v = s.get_token(), s.get_token(), s.get_token()
if k is s.eof:
try:
parse_color_map(onerror=lambda e: writemsg("%s\n" % str(e), noiselevel=-1))
-except FileNotFound, e:
+except FileNotFound:
pass
except PortageException, e:
writemsg("%s\n" % str(e))
+ del e
def nc_len(mystr):
tmp = re.sub(esc_seq + "^m]+m", "", mystr);
# $Id$
-import os, atexit, signal, sys
-import portage.data
+import os
+import atexit
+import signal
+import sys
from portage.util import dump_traceback
from portage.const import BASH_BINARY, SANDBOX_BINARY
import os
-from portage.const import PRIVATE_PATH, USER_CONFIG_PATH
-from portage.exception import InvalidAtom
-from portage.dep import isvalidatom, match_from_list, best_match_to_list, dep_getkey, use_reduce, paren_reduce
-from portage import flatten
-
OPERATIONS = ["merge", "unmerge"]
DEFAULT_SETS = ["world", "system", "everything", "security"] \
+["package_"+x for x in ["mask", "unmask", "use", "keywords"]]
-
-class PackageSet(object):
- # Set this to operations that are supported by your subclass. While
- # technically there is no difference between "merge" and "unmerge" regarding
- # package sets, the latter doesn't make sense for some sets like "system"
- # or "security" and therefore isn't supported by them.
- _operations = ["merge"]
- _atommap = {}
- description = "generic package set"
-
- def __init__(self, name):
- self.name = name
- self._atoms = set()
- self._atommap = {}
- self._loaded = False
- self._loading = False
-
- def __contains__(self, atom):
- return atom in self.getAtoms()
-
- def __iter__(self):
- for x in self.getAtoms():
- yield x
-
- def supportsOperation(self, op):
- if not op in OPERATIONS:
- raise ValueError(op)
- return op in self._operations
-
- def getAtoms(self):
- if not (self._loaded or self._loading):
- self._loading = True
- self.load()
- self._loaded = True
- self._loading = False
- return self._atoms
-
- def _setAtoms(self, atoms):
- atoms = map(str.strip, atoms)
- for a in atoms[:]:
- if a == "":
- atoms.remove(a)
- elif not isvalidatom(a):
- raise InvalidAtom(a)
- self._atoms = set(atoms)
- self._updateAtomMap()
-
- def load(self):
- # This method must be overwritten by subclasses
- # Editable sets should use the value of self._mtime to determine if they
- # need to reload themselves
- raise NotImplementedError()
-
- def containsCPV(self, cpv):
- for a in self.getAtoms():
- if match_from_list(a, [cpv]):
- return True
- return False
-
- def getMetadata(self, key):
- if hasattr(self, key.lower()):
- return getattr(self, key.lower())
- else:
- return ""
-
- def _updateAtomMap(self, atoms=None):
- """Update self._atommap for specific atoms or all atoms."""
- if not atoms:
- self._atommap.clear()
- atoms = self._atoms
- for a in atoms:
- cp = dep_getkey(a)
- self._atommap.setdefault(cp, set())
- self._atommap[cp].add(a)
-
- # Not sure if this one should really be in PackageSet
- def findAtomForPackage(self, cpv, metadata):
- """Return the best match for a given package from the arguments, or
- None if there are no matches. This matches virtual arguments against
- the PROVIDE metadata. This can raise an InvalidDependString exception
- if an error occurs while parsing PROVIDE."""
- cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
- cp = dep_getkey(cpv)
- self.getAtoms() # make sure the atoms are loaded
- atoms = self._atommap.get(cp)
- if atoms:
- best_match = best_match_to_list(cpv_slot, atoms)
- if best_match:
- return best_match
- if not metadata["PROVIDE"]:
- return None
- provides = flatten(use_reduce(paren_reduce(metadata["PROVIDE"]),
- uselist=metadata["USE"].split()))
- for provide in provides:
- provided_cp = dep_getkey(provide)
- atoms = self._atommap.get(provided_cp)
- if atoms:
- atoms = list(atoms)
- transformed_atoms = [atom.replace(provided_cp, cp) for atom in atoms]
- best_match = best_match_to_list(cpv_slot, transformed_atoms)
- if best_match:
- return atoms[transformed_atoms.index(best_match)]
- return None
-
-class EditablePackageSet(PackageSet):
-
- def update(self, atoms):
- self.getAtoms()
- self._atoms.update(atoms)
- self._updateAtomMap(atoms=atoms)
- self.write()
-
- def add(self, atom):
- self.update([atom])
-
- def replace(self, atoms):
- self._setAtoms(atoms)
- self.write()
-
- def remove(self, atom):
- self.getAtoms()
- self._atoms.discard(atom)
- self._updateAtomMap()
- self.write()
-
- def removePackageAtoms(self, cp):
- for a in list(self.getAtoms()):
- if dep_getkey(a) == cp:
- self.remove(a)
- self.write()
-
- def write(self):
- # This method must be overwritten in subclasses that should be editable
- raise NotImplementedError()
-
-
-class InternalPackageSet(EditablePackageSet):
- def __init__(self, initial_atoms=None):
- super(InternalPackageSet, self).__init__("")
- if initial_atoms != None:
- self.update(initial_atoms)
-
- def clear(self):
- self._atoms.clear()
- self._updateAtomMap()
-
- def load(self):
- pass
-
- def write(self):
- pass
+del x
def make_default_sets(configroot, root, profile_paths, settings=None,
vdbapi=None, portdbapi=None):
from portage.sets.profiles import PackagesSystemSet
from portage.sets.security import NewAffectedSet
from portage.sets.dbapi import EverythingSet
+ from portage.const import PRIVATE_PATH, USER_CONFIG_PATH
rValue = set()
worldset = StaticFileSet("world", os.path.join(root, PRIVATE_PATH, "world"))
def make_extra_static_sets(configroot):
from portage.sets.files import StaticFileSet
+ from portage.const import PRIVATE_PATH, USER_CONFIG_PATH
rValue = set()
mydir = os.path.join(configroot, USER_CONFIG_PATH.lstrip(os.sep), "sets")
for myname in mysets:
if myname in DEFAULT_SETS:
continue
- rValue.add(StaticFileSet(fname, os.path.join(mydir, myname)))
+ rValue.add(StaticFileSet(myname, os.path.join(mydir, myname)))
return rValue
def make_category_sets(portdbapi, settings, only_visible=True):
for s in sys.argv[1:]:
if s.startswith("category_"):
c = s[9:]
- l.add(CategorySet("category_%s" % c, c, portdbapi, only_visible=only_visible))
+ l.add(CategorySet("category_%s" % c, c, portage.db['/']['porttree'].dbapi, only_visible=False))
elif os.path.exists(s):
l.add(StaticFileSet(os.path.basename(s), s))
elif s != "*":
# $Id$
from portage.versions import catsplit
+from portage import flatten
+from portage.dep import isvalidatom, match_from_list, \
+ best_match_to_list, dep_getkey, use_reduce, paren_reduce
+from portage.exception import InvalidAtom
+from portage.sets import OPERATIONS
-from portage.sets import PackageSet
+class PackageSet(object):
+ # Set this to operations that are supported by your subclass. While
+ # technically there is no difference between "merge" and "unmerge" regarding
+ # package sets, the latter doesn't make sense for some sets like "system"
+ # or "security" and therefore isn't supported by them.
+ _operations = ["merge"]
+ _atommap = {}
+ description = "generic package set"
+
+ def __init__(self, name):
+ self.name = name
+ self._atoms = set()
+ self._atommap = {}
+ self._loaded = False
+ self._loading = False
+
+ def __contains__(self, atom):
+ return atom in self.getAtoms()
+
+ def __iter__(self):
+ for x in self.getAtoms():
+ yield x
+
+ def supportsOperation(self, op):
+ if not op in OPERATIONS:
+ raise ValueError(op)
+ return op in self._operations
+
+ def getAtoms(self):
+ if not (self._loaded or self._loading):
+ self._loading = True
+ self.load()
+ self._loaded = True
+ self._loading = False
+ return self._atoms
+
+ def _setAtoms(self, atoms):
+ atoms = map(str.strip, atoms)
+ for a in atoms[:]:
+ if a == "":
+ atoms.remove(a)
+ elif not isvalidatom(a):
+ raise InvalidAtom(a)
+ self._atoms = set(atoms)
+ self._updateAtomMap()
+
+ def load(self):
+ # This method must be overwritten by subclasses
+ # Editable sets should use the value of self._mtime to determine if they
+ # need to reload themselves
+ raise NotImplementedError()
+
+ def containsCPV(self, cpv):
+ for a in self.getAtoms():
+ if match_from_list(a, [cpv]):
+ return True
+ return False
+
+ def getMetadata(self, key):
+ if hasattr(self, key.lower()):
+ return getattr(self, key.lower())
+ else:
+ return ""
+
+ def _updateAtomMap(self, atoms=None):
+ """Update self._atommap for specific atoms or all atoms."""
+ if not atoms:
+ self._atommap.clear()
+ atoms = self._atoms
+ for a in atoms:
+ cp = dep_getkey(a)
+ self._atommap.setdefault(cp, set())
+ self._atommap[cp].add(a)
+
+ # Not sure if this one should really be in PackageSet
+ def findAtomForPackage(self, cpv, metadata):
+ """Return the best match for a given package from the arguments, or
+ None if there are no matches. This matches virtual arguments against
+ the PROVIDE metadata. This can raise an InvalidDependString exception
+ if an error occurs while parsing PROVIDE."""
+ cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
+ cp = dep_getkey(cpv)
+ self.getAtoms() # make sure the atoms are loaded
+ atoms = self._atommap.get(cp)
+ if atoms:
+ best_match = best_match_to_list(cpv_slot, atoms)
+ if best_match:
+ return best_match
+ if not metadata["PROVIDE"]:
+ return None
+ provides = flatten(use_reduce(paren_reduce(metadata["PROVIDE"]),
+ uselist=metadata["USE"].split()))
+ for provide in provides:
+ provided_cp = dep_getkey(provide)
+ atoms = self._atommap.get(provided_cp)
+ if atoms:
+ atoms = list(atoms)
+ transformed_atoms = [atom.replace(provided_cp, cp) for atom in atoms]
+ best_match = best_match_to_list(cpv_slot, transformed_atoms)
+ if best_match:
+ return atoms[transformed_atoms.index(best_match)]
+ return None
+
+class EditablePackageSet(PackageSet):
+
+ def update(self, atoms):
+ self.getAtoms()
+ self._atoms.update(atoms)
+ self._updateAtomMap(atoms=atoms)
+ self.write()
+
+ def add(self, atom):
+ self.update([atom])
+
+ def replace(self, atoms):
+ self._setAtoms(atoms)
+ self.write()
+
+ def remove(self, atom):
+ self.getAtoms()
+ self._atoms.discard(atom)
+ self._updateAtomMap()
+ self.write()
+
+ def removePackageAtoms(self, cp):
+ for a in list(self.getAtoms()):
+ if dep_getkey(a) == cp:
+ self.remove(a)
+ self.write()
+
+ def write(self):
+ # This method must be overwritten in subclasses that should be editable
+ raise NotImplementedError()
+
+
+class InternalPackageSet(EditablePackageSet):
+ def __init__(self, initial_atoms=None):
+ super(InternalPackageSet, self).__init__("")
+ if initial_atoms != None:
+ self.update(initial_atoms)
+
+ def clear(self):
+ self._atoms.clear()
+ self._updateAtomMap()
+
+ def load(self):
+ pass
+
+ def write(self):
+ pass
class EverythingSet(PackageSet):
_operations = ["merge", "unmerge"]
# Distributed under the terms of the GNU General Public License v2
# $Id$
-from portage.util import grabfile, grabfile_package, grabdict_package, write_atomic, ensure_dirs
+import os
+
+from portage.util import grabfile, write_atomic, ensure_dirs
from portage.const import PRIVATE_PATH
from portage.locks import lockfile, unlockfile
from portage import portage_gid
-import os
-
-from portage.sets import PackageSet, EditablePackageSet
+from portage.sets.dbapi import PackageSet, EditablePackageSet
+from portage.env.config import ConfigLoaderKlass, GenericFile
+from portage.env.loaders import ItemFileLoader, KeyListFileLoader
+from portage.env.validators import PackagesFileValidator, ValidAtomValidator
class StaticFileSet(EditablePackageSet):
_operations = ["merge", "unmerge"]
- def __init__(self, name, filename):
+ def __init__(self, name, filename, loader=None):
super(StaticFileSet, self).__init__(name)
self._filename = filename
self._mtime = None
self.description = "Package set loaded from file %s" % self._filename
+ if loader is None:
+ self.loader = ConfigLoaderKlass(ItemFileLoader(filename=self._filename,
+ validator=PackagesFileValidator))
metadata = grabfile(self._filename + ".metadata")
key = None
+ value = []
for line in metadata:
line = line.strip()
if len(line) == 0 and key != None:
except (OSError, IOError):
mtime = None
if (not self._loaded or self._mtime != mtime):
- self._setAtoms(grabfile_package(self._filename, recursive=True))
+ self.loader.load()
+ self._setAtoms(self.loader.keys())
self._mtime = mtime
class ConfigFileSet(PackageSet):
- def __init__(self, name, filename):
+ def __init__(self, name, filename, loader=None, validator=None):
super(ConfigFileSet, self).__init__(name)
self._filename = filename
self.description = "Package set generated from %s" % self._filename
+ if loader is None:
+ self.loader = GenericFile(filename=self._filename)
+ else:
+ self.loader = loader(filename, validator)
def load(self):
- self._setAtoms(grabdict_package(self._filename, recursive=True).keys())
+ self.loader.load()
+ self._setAtoms(self.loader.keys())
class WorldSet(StaticFileSet):
description = "Set of packages that were directly installed by the user"
import os
from portage.util import grabfile_package, stack_lists
-
-from portage.sets import PackageSet
+from portage.sets.dbapi import PackageSet
class PackagesSystemSet(PackageSet):
_operations = ["merge"]
# Distributed under the terms of the GNU General Public License v2
# $Id$
+import os
import portage.glsa as glsa
-from portage.util import grabfile
+from portage.util import grabfile, write_atomic
from portage.const import CACHE_PATH
-import os
-
-from portage.sets import PackageSet
+from portage.sets.dbapi import PackageSet
class SecuritySet(PackageSet):
_operations = ["merge"]
# Distributed under the terms of the GNU General Public License v2
# $Id$
-import subprocess, os
+import subprocess
+import os
-from portage.sets import PackageSet
+from portage.sets.dbapi import PackageSet
class CommandOutputSet(PackageSet):
+ """This class creates a PackageSet from the output of a shell command.
+ The shell command should produce one atom per line, that is:
+
+ >>> atom1
+ atom2
+ ...
+ atomN
+
+ Args:
+ name: A string that identifies the set.
+ command: A string or sequence identifying the command to run
+ (see the subprocess.Popen documentaion for the format)
+ """
_operations = ["merge", "unmerge"]
def __init__(self, name, command):
# Distributed under the terms of the GNU General Public License v2
# $Id$
-import os, sys, time, unittest
-import portage.tests
+import os
+import sys
+import time
+import unittest
def main():
testDirs = ["bin", "dep", "ebuild",
- "env/config", "util", "versions", "xpak"]
+ "env/config", "util", "versions", "xpak", "sets/shell"]
suite = unittest.TestSuite()
basedir = os.path.dirname(__file__)
for mydir in testDirs:
suite.addTests(getTests(os.path.join(basedir, mydir), basedir) )
- return portage.tests.TextTestRunner(verbosity=2).run(suite)
+ return TextTestRunner(verbosity=2).run(suite)
def my_import(name):
mod = __import__(name)
mod = getattr(mod, comp)
return mod
-def getTests( path, base_path ):
+def getTests(path, base_path):
"""
path is the path to a given subdir ( 'portage/' for example)
to import
"""
- import os
- files = os.listdir( path )
- files = [ f[:-3] for f in files if f.startswith("test_") and f.endswith(".py") ]
+ files = os.listdir(path)
+ files = [ f[:-3] for f in files if f.startswith("test") and f.endswith(".py") ]
parent_path = path[len(base_path)+1:]
- parent_module = ".".join(("portage","tests", parent_path))
- parent_module = parent_module.replace('/','.')
+ parent_module = ".".join(("portage", "tests", parent_path))
+ parent_module = parent_module.replace('/', '.')
result = []
for mymodule in files:
# Make the trailing / a . for module importing
modname = ".".join((parent_module, mymodule))
mod = my_import(modname)
- result.append( unittest.TestLoader().loadTestsFromModule(mod) )
+ result.append(unittest.TestLoader().loadTestsFromModule(mod))
return result
class TextTestResult(unittest._TextTestResult):
by the test runner.
"""
- def __init__( self, stream, descriptions, verbosity ):
+ def __init__(self, stream, descriptions, verbosity):
unittest._TextTestResult.__init__( self, stream, descriptions, verbosity )
self.todoed = []
- def addTodo( self, test, info ):
+ def addTodo(self, test, info):
self.todoed.append((test,info))
if self.showAll:
self.stream.writeln("TODO")
elif self.dots:
self.stream.write(".")
- def printErrors( self ):
+ def printErrors(self):
if self.dots or self.showAll:
self.stream.writeln()
self.printErrorList('ERROR', self.errors)
def defaultTestResult(self):
return TextTestResult()
- def run( self, result=None ):
+ def run(self, result=None):
if result is None: result = self.defaultTestResult()
result.startTest(self)
testMethod = getattr(self, self._testMethodName)
def _makeResult(self):
return TextTestResult(self.stream, self.descriptions, self.verbosity)
- def run( self, test ):
+ def run(self, test):
"""
Run the given test case or test suite.
"""
import os
from portage.env.config import PackageMaskFile
-from portage.tests import TestCase
+from portage.tests import TestCase, test_cps
from tempfile import mkstemp
class PackageMaskFileTestCase(TestCase):
-
- atoms = ['sys-apps/portage','dev-util/diffball','not@va1id@t0m']
def testPackageMaskFile(self):
self.BuildFile()
f = PackageMaskFile(self.fname)
f.load()
for atom in f:
- self.assertTrue(atom in self.atoms)
+ self.assertTrue(atom in test_cps)
finally:
self.NukeFile()
def BuildFile(self):
fd, self.fname = mkstemp()
f = os.fdopen(fd, 'w')
- f.write("\n".join(self.atoms))
+ f.write("\n".join(test_cps))
f.close()
def NukeFile(self):
-import os
from portage.tests import TestCase
from portage.env.config import PortageModulesFile
from tempfile import mkstemp
from itertools import izip
+import os
class PortageModulesFileTestCase(TestCase):
keys = ['foo.bar','baz','bob','extra_key']
- modules = ['spanky','zmedico','antarus','ricer']
+ invalid_keys = ['',""]
+ modules = ['spanky','zmedico','antarus','ricer','5','6']
def setUp(self):
self.items = {}
- for k,v in izip(self.keys, self.modules):
+ for k, v in izip(self.keys + self.invalid_keys,
+ self.modules):
self.items[k] = v
def testPortageModulesFile(self):
self.BuildFile()
f = PortageModulesFile(self.fname)
- for k in f:
- self.assertEqual( f[k], self.items[k] )
+ f.load()
+ for k in self.keys:
+ self.assertEqual(f[k], [self.items[k]])
+ for ik in self.invalid_keys:
+ self.assertEqual(False, ik in f)
self.NukeFile()
def BuildFile(self):
fd, self.fname = mkstemp()
f = os.fdopen(fd, 'wb')
- for k,v in self.items.iteritems():
+ for k, v in self.items.iteritems():
f.write('%s=%s\n' % (k,v))
f.close()
def NukeFile(self):
- import os
os.unlink(self.fname)
--- /dev/null
+# testCommandOututSet.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+from portage.process import find_binary
+from portage.tests import TestCase, test_cps
+from portage.sets.shell import CommandOutputSet
+
+class CommandOutputSetTestCase(TestCase):
+ """Simple Test Case for CommandOutputSet"""
+
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def testCommand(self):
+
+ input = set(test_cps)
+ command = find_binary("echo")
+ command += " -e "
+ for a in input:
+ command += "\"%s\n\"" % a
+ s = CommandOutputSet('testset', command)
+ atoms = s.getAtoms()
+ self.assertEqual(atoms, input)
# Distributed under the terms of the GNU General Public License v2
# $Id: portage_util.py 4603 2006-10-06 03:28:25Z zmedico $
+
+import os
+import errno
+import shlex
+import stat
+import string
+import sys
+
from portage.exception import PortageException, FileNotFound, \
OperationNotPermitted, PermissionDenied, ReadOnlyFileSystem
import portage.exception
from portage.dep import isvalidatom
from portage.const import EPREFIX
-import os, errno, shlex, stat, string, sys
try:
import cPickle
except ImportError:
return newdict
def grabdict_package(myfilename, juststrings=0, recursive=0):
+ """ Does the same thing as grabdict except it validates keys
+ with isvalidatom()"""
pkgs=grabdict(myfilename, juststrings, empty=1, recursive=recursive)
# We need to call keys() here in order to avoid the possibility of
# "RuntimeError: dictionary changed size during iteration"
pkgs=grabfile(myfilename, compatlevel, recursive=recursive)
for x in range(len(pkgs)-1, -1, -1):
pkg = pkgs[x]
- if pkg[0] == "-":
- pkg = pkg[1:]
- if pkg[0] == "*": # Kill this so we can deal the "packages" file too
+ if pkg[0] in ["-","*"]: # -atom *pkg for packages file
pkg = pkg[1:]
if not isvalidatom(pkg):
writemsg("--- Invalid atom in %s: %s\n" % (myfilename, pkgs[x]),
if mydat[-8:]!="XPAKSTOP":
return None
indexsize=decodeint(mydat[8:12])
- datasize=decodeint(mydat[12:16])
return (mydat[16:indexsize+16], mydat[indexsize+16:-8])
def getindex(infile):
return self.unpackinfo(datadir)
def compose(self,datadir,cleanup=0):
"""Alias for recompose()."""
- return recompose(datadir,cleanup)
+ return self.recompose(datadir,cleanup)
def recompose(self,datadir,cleanup=0):
"""Creates an xpak segment from the datadir provided, truncates the tbz2
to the end of regular data if an xpak segment already exists, and adds