portage-2.1.3
-------------
+* Legacy "masked by: profile" support has been removed. Profiles should use
+ package.mask to mask unwanted versions of system packages.
* Allow per-module setting of PORTAGE_ELOG_CLASSES
* Add ** as new token for package.keywords to bypass the keyword visibility layer
* Namespace sanitizing: move all portage related code into portage.* namespace,
.PD 1
.TP
.BR packages
-This file serves two purposes. The first is to mask out specific
-packages/versions on a per\-profile basis. The second is to provide the
-list of packages that compose the special \fIsystem\fR set.
+Provides the list of packages that compose the special \fIsystem\fR set.
.I Format:
.nf
\- comments begin with #
-\- one DEPEND atom per line of what to mask OUT
+\- one DEPEND atom per line
\- packages to be added to the system set begin with a *
.fi
.I Note:
.I Example:
.nf
# i am a comment !
-# only allow versions of glibc less than 2.3
-<sys\-libs/glibc\-2.3
-# add any version of bash to the system set
+# pull in a version of glibc less than 2.3
+*<sys\-libs/glibc\-2.3
+# pull in any version of bash
*app\-shells/bash
-# only allow versions of readline earlier than 4.2
-# and add it to the system set
+# pull in a version of readline earlier than 4.2
*<sys\-libs/readline\-4.2
.fi
.TP
else:
#world mode
worldlist = getlist(self.settings, "world")
- sysdict = genericdict(getlist(self.settings, "system"))
+ mylist = getlist(self.settings, "system")
worlddict=genericdict(worldlist)
for x in worlddict.keys():
elif not self.trees[self.target_root]["vartree"].dbapi.match(x):
world_problems = True
else:
- sysdict[x]=worlddict[x]
-
- mylist = sysdict.keys()
+ mylist.append(x)
newlist = []
for atom in mylist:
if verbosity == 3:
# size verbose
mysize=0
- if x[0] == "ebuild" and x[-1]!="nomerge":
+ if x[0] == "ebuild" and ordered and x[-1] != "nomerge":
try:
myfilesdict = portdb.getfetchsizes(pkg_key,
useflags=self.useFlags[myroot][pkg_key],
if myfetchfile not in myfetchlist:
mysize+=myfilesdict[myfetchfile]
myfetchlist.append(myfetchfile)
- if ordered:
- counters.totalsize += mysize
+ counters.totalsize += mysize
verboseadd+=format_size(mysize)+" "
# overlay verbose
else:
mydepgraph.display(
mydepgraph.altlist(reversed=("--tree" in myopts)))
+ if ("--buildpkgonly" in myopts):
+ if not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
+ print "\n!!! --buildpkgonly requires all dependencies to be merged."
+ print "!!! You have to merge the dependencies before you can build this package.\n"
+ sys.exit(1)
else:
if ("--buildpkgonly" in myopts):
if not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
virts = settings.getvirtuals("/")
virts_p = settings.get_virts_p("/")
if len(mysplit)==1:
- if mydb and type(mydb)==types.InstanceType:
+ if hasattr(mydb, "cp_list"):
for x in settings.categories:
if mydb.cp_list(x+"/"+mykey,use_cache=use_cache):
return x+"/"+mykey
return(virts_p[mykey][0])
return "null/"+mykey
elif mydb:
- if type(mydb)==types.InstanceType:
+ if hasattr(mydb, "cp_list"):
if (not mydb.cp_list(mykey,use_cache=use_cache)) and virts and virts.has_key(mykey):
return virts[mykey][0]
return mykey
rValue = []
- # profile checking
- revmaskdict=settings.prevmaskdict
- if revmaskdict.has_key(mycp):
- for x in revmaskdict[mycp]:
- if x[0]=="*":
- myatom = x[1:]
- else:
- myatom = x
- if not match_to_list(mycpv, [myatom]):
- rValue.append("profile")
- break
-
# package.mask checking
maskdict=settings.pmaskdict
unmaskdict=settings.punmaskdict
except ValueError:
pass
- revmaskdict = self.mysettings.prevmaskdict
- if revmaskdict.has_key(mycp):
- for x in revmaskdict[mycp]:
- #important: only match against the still-unmasked entries...
- #notice how we pass "newlist" to the xmatch() call below....
- #Without this, ~ deps in the packages files are broken.
- mymatches = self.xmatch("match-list", x, mylist=newlist)
- if mymatches is None:
- #error in packages file; print warning and continue:
- print "emerge: visible(): profile packages entry \""+x+"\" is invalid, ignoring..."
- continue
- pos = 0
- while pos < len(newlist):
- if newlist[pos] not in mymatches:
- del newlist[pos]
- else:
- pos += 1
return newlist
def gvisible(self,mylist):
--- /dev/null
+# Copyright: 2007 Gentoo Foundation
+# License: GPL2
+# $Id$
+
--- /dev/null
+# config.py -- Portage Config
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+import os
+from UserDict import UserDict
+
+class PackageKeywords(UserDict):
+ """
+ A base class stub for things to inherit from; some people may want a database based package.keywords or something
+
+ Internally dict has pairs of the form
+ {'cpv':['keyword1','keyword2','keyword3'...]
+ """
+
+ data = {}
+
+ def iteritems(self):
+ return self.data.iteritems()
+
+ def keys(self):
+ return self.data.keys()
+
+ def __contains__(self, other):
+ return other in self.data
+
+ def __hash__( self ):
+ return self.data.__hash__()
+
+class PackageKeywordsFile(PackageKeywords):
+ """
+ Inherits from PackageKeywords; implements a file-based backend. Doesn't handle recursion yet.
+ """
+ def __init__( self, filename ):
+ self.fname = filename
+
+ def load(self, recursive):
+ """
+ Package.keywords files have comments that begin with #.
+ The entries are of the form:
+ >>> cpv [-~]keyword1 [-~]keyword2 keyword3
+ >>> Exceptions include -*, ~*, and ** for keywords.
+ """
+
+ if os.path.exists( self.fname ):
+ f = open(self.fname, 'rb')
+ for line in f:
+ if line.startswith('#'):
+ continue
+ split = line.split()
+ if len(split):
+ # Surprisingly this works for iterables of length 1
+ # fex ['sys-apps/portage','x86','amd64'] becomes {'sys-apps/portage':['x86','amd64']}
+ key, items = split[0],split[1:]
+ # if they specify the same cpv twice; stack the values (append) instead of overwriting.
+ if key in self.data:
+ self.data[key].append(items)
+ else:
+ self.data[key] = items
+
+class PackageUse(UserDict):
+ """
+ A base class stub for things to inherit from; some people may want a database based package.keywords or something
+
+ Internally dict has pairs of the form
+ {'cpv':['flag1','flag22','flag3'...]
+ """
+
+ data = {}
+
+ def iteritems(self):
+ return self.data.iteritems()
+
+ def __hash__(self):
+ return hash(self.data)
+
+ def __contains__(self, other):
+ return other in self.data
+
+ def keys(self):
+ return self.data.keys()
+
+class PackageUseFile(PackageUse):
+ """
+ Inherits from PackageUse; implements a file-based backend. Doesn't handle recursion yet.
+ """
+ def __init__(self, filename):
+ self.fname = filename
+
+ def load(self, recursive):
+ """
+ Package.keywords files have comments that begin with #.
+ The entries are of the form:
+ >>> atom useflag1 useflag2 useflag3..
+ useflags may optionally be negative with a minus sign (-)
+ >>> atom useflag1 -useflag2 useflag3
+ """
+
+ if os.path.exists( self.fname ):
+ f = open(self.fname, 'rb')
+ for line in f:
+ if line.startswith('#'):
+ continue
+ split = line.split()
+ if len(split):
+ # Surprisingly this works for iterables of length 1
+ # fex ['sys-apps/portage','foo','bar'] becomes {'sys-apps/portage':['foo','bar']}
+ key, items = split[0],split[1:]
+ # if they specify the same cpv twice; stack the values (append) instead of overwriting.
+ if key in self.data:
+ self.data[key].append(items)
+ else:
+ self.data[key] = items
+
+class PackageMask(UserDIct):
+ """
+ A base class for Package.mask functionality
+ """
+ data = {}
+
+ def iteritems(self):
+ return self.data.iteritems()
+
+ def __hash__(self):
+ return hash(self.data)
+
+ def __contains__(self, other):
+ return other in self.data
+
+ def keys(self):
+ return self.data.keys()
+
+ def iterkeys(self):
+ return self.data.iterkeys()
+
+class PackageMaskFile(PackageMask):
+ """
+ A class that implements a file-based package.mask
+
+ Entires in package.mask are of the form:
+ atom1
+ atom2
+ or optionally
+ -atom3
+ to revert a previous mask; this only works when masking files are stacked
+ """
+
+ def __init__(self, filename):
+ self.fname = filename
+
+ def load(self, recursive):
+ """
+ Package.keywords files have comments that begin with #.
+ The entries are of the form:
+ >>> atom useflag1 useflag2 useflag3..
+ useflags may optionally be negative with a minus sign (-)
+ >>> atom useflag1 -useflag2 useflag3
+ """
+
+ if os.path.exists( self.fname ):
+ f = open(self.fname, 'rb')
+ for line in f:
+ if line.startswith('#'):
+ continue
+ split = line.split()
+ if len(split):
+ atom = split[0] # This is an extra assignment, but I think it makes the code more explicit in what goes into the dict
+ self.data[atom] = None # we only care about keys in the dict, basically abusing it as a list
import portage.tests
def main():
- testDirs = ["util","versions", "dep", "xpak"]
+ testDirs = ["util","versions", "dep", "xpak", "env/config"]
suite = unittest.TestSuite()
basedir = os.path.dirname(__file__)
for mydir in testDirs:
parent_module = parent_module.replace('/','.')
result = []
for mymodule in files:
- try:
- # Make the trailing / a . for module importing
- modname = ".".join((parent_module, mymodule))
- mod = my_import(modname)
- result.append( unittest.TestLoader().loadTestsFromModule(mod) )
- except ImportError:
- raise
+ # Make the trailing / a . for module importing
+ modname = ".".join((parent_module, mymodule))
+ mod = my_import(modname)
+ result.append( unittest.TestLoader().loadTestsFromModule(mod) )
return result
-class SkipException(Exception):
- pass
-
class TextTestResult(unittest._TextTestResult):
"""
- We need a subclass of unittest._TextTestResult to handle skipped
- tests.
+ We need a subclass of unittest._TextTestResult to handle tests with TODO
- This just adds an addSkip method that can be used to add
- skipped tests to the result; these can be displayed later
+ This just adds an addTodo method that can be used to add tests
+ that are marked TODO; these can be displayed later
by the test runner.
"""
def __init__( self, stream, descriptions, verbosity ):
unittest._TextTestResult.__init__( self, stream, descriptions, verbosity )
- self.skipped = []
+ self.todoed = []
- def addSkip( self, test, info ):
- self.skipped.append((test,info))
+ def addTodo( self, test, info ):
+ self.todoed.append((test,info))
if self.showAll:
- self.stream.writeln("FAIL AND SKIP")
+ self.stream.writeln("TODO")
elif self.dots:
self.stream.write(".")
self.stream.writeln()
self.printErrorList('ERROR', self.errors)
self.printErrorList('FAIL', self.failures)
- self.printErrorList('SKIP', self.skipped)
+ self.printErrorList('TODO', self.todoed)
class TestCase(unittest.TestCase):
"""
(broken code!!??!11oneone) but it does happen at times.
"""
- SkipException = SkipException
-
def __init__(self, methodName='runTest'):
# This method exists because unittest.py in python 2.4 stores
# the methodName as __testMethodName while 2.5 uses
# _testMethodName.
self._testMethodName = methodName
unittest.TestCase.__init__(self, methodName)
+ self.todo = False
def defaultTestResult(self):
return TextTestResult()
testMethod()
ok = True
except self.failureException:
- result.addFailure(self, self._exc_info())
- except self.SkipException:
- result.addSkip(self,"%s: Failed but Skippable" % testMethod)
+ if self.todo:
+ result.addTodo(self,"%s: TODO" % testMethod)
+ else:
+ result.addFailure(self, self._exc_info())
except KeyboardInterrupt:
raise
except:
"""
def testIsValidAtom(self):
-
+
+ self.todo = True
tests = [ ( "sys-apps/portage", True ),
( "=sys-apps/portage-2.1", True ),
( "=sys-apps/portage-2.1*", True ),
( "portage", False ) ]
for test in tests:
- raise self.SkipException()
if test[1]:
atom_type = "valid"
else:
--- /dev/null
+# tests/portage/env/__init__.py -- Portage Unit Test functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
--- /dev/null
+# tests/portage/env/config/__init__.py -- Portage Unit Test functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
--- /dev/null
+# test_PackageKeywordsFile.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id: test_PackageKeywordsFile.py 6182 2007-03-06 07:35:22Z antarus $
+
+from portage.tests import TestCase
+from portage.env.config import PackageKeywordsFile
+
+class PackageKeywordsFileTestCase(TestCase):
+
+ fname = 'package.keywords'
+ cpv = 'sys-apps/portage'
+ keywords = ['~x86', 'amd64', '-mips']
+
+ def testPackageKeywordsLoad(self):
+ """
+ A simple test to ensure the load works properly
+ """
+
+ self.BuildFile()
+ try:
+ f = PackageKeywordsFile(self.fname)
+ f.load(recursive=False)
+ for cpv, keyword in f.iteritems():
+ self.assertEqual( cpv, self.cpv )
+ [k for k in keyword if self.assertTrue(k in self.keywords)]
+ finally:
+ self.NukeFile()
+
+ def BuildFile(self):
+ f = open(self.fname, 'wb')
+ f.write('%s %s\n' % (self.cpv, ' '.join(self.keywords)))
+ f.close()
+
+ def NukeFile(self):
+ import os
+ os.unlink(self.fname)
--- /dev/null
+# test_PackageMaskFile.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id: test_PackageMaskFile.py 6182 2007-03-06 07:35:22Z antarus $
+
+from portage.env.config import PackageMaskFile
+from portage.tests import TestCase
+
+class PackageMaskFileTestCase(TestCase):
+
+ fname = 'package.mask'
+ atoms = ['sys-apps/portage','dev-util/diffball','not@va1id@t0m']
+
+ def testPackageMaskLoad(self):
+ self.BuildFile()
+ try:
+ f = PackageMaskFile(self.fname)
+ f.load(recursive=False)
+ [atom for atom in f.iterkeys() if self.assertTrue(atom in self.atoms)]
+ finally:
+ self.NukeFile()
+
+ def BuildFile(self):
+ f = open(self.fname, 'wb')
+ f.write("\n".join(atoms))
+ f.close()
+
+ def NukeFile(self):
+ import os
+ os.unlink(self.fname)
--- /dev/null
+# test_PackageUseFile.py -- Portage Unit Testing Functionality
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id: test_PackageUseFile.py 6182 2007-03-06 07:35:22Z antarus $
+
+from portage.tests import TestCase
+from portage.env.config import PackageUseFile
+
+class PackageUseFileTestCase(TestCase):
+
+ fname = 'package.use'
+ cpv = 'sys-apps/portage'
+ useflags = ['cdrom', 'far', 'boo', 'flag', 'blat']
+
+ def testPackageUseLoad(self):
+ """
+ A simple test to ensure the load works properly
+ """
+ self.BuildFile()
+ try:
+ f = PackageUseFile(self.fname)
+ f.load(recursive=False)
+ for cpv, use in f.iteritems():
+ self.assertEqual( cpv, self.cpv )
+ [flag for flag in use if self.assertTrue(flag in self.useflags)]
+ finally:
+ self.NukeFile()
+
+ def BuildFile(self):
+ f = open(self.fname, 'wb')
+ f.write("%s %s" % (self.cpv, ' '.join(self.useflags)))
+
+ def NukeFile(self):
+ import os
+ os.unlink(self.fname)