Merged from trunk 6185:6199
authorFabian Groffen <grobian@gentoo.org>
Fri, 9 Mar 2007 11:23:18 +0000 (11:23 -0000)
committerFabian Groffen <grobian@gentoo.org>
Fri, 9 Mar 2007 11:23:18 +0000 (11:23 -0000)
For bug #169620, in --tree display always show the dowload size on the
node that is "ordered" rather than one of it's "nomerge" counterparts.

Fix 2 more types.InstanceType comparisons that are broken by the
transition of dbapi to new-style classes.

Take marien's advice, turn Skips into Todos for clarity sake

Part of my attempt now involves cleaning up config; this means for me;
removing the file-based stuff from it (config_path) and encapsulating
that into classes.  This is the first one, a simple PackageKeywords
class that does file-based stuff, no recursion yet but soon. Trying to
do TDD here as well,so tests first then code.

Change load() to have no default arguments, makes caller specifiy
explicitly...I think assuming a default arg is bad here.  Also add
PackageUse and PackageUseFile, change up the comments a bit.  I've
started to notice code re-use here; these are basically the same
code.  I think I will write up the rest of the package* classes and
then perform code merges to save LOC and memory and whatnot

add PackageMask{File} classes, change unit tests to use try/finally,
makes sure the tempfile gets destroyed even if something weird
happens

whoopse, s/;/:/ (WarnerBro)

Remove legacy "masked by: profile" support as per bug #149508.
Profiles should use package.mask to mask unwanted versions of system
packages.

Use the full atoms from the system set, since profile masking does
not automatically constrain the matches anymore.

Remove the "masked by: profile" support from getmaskingstatus().

Remove profile masking of system packages from the docs.

Display message about --buildpkgonly restriction in pretend mode as
well

svn path=/main/branches/prefix/; revision=6200

14 files changed:
NEWS
man/portage.5
pym/emerge/__init__.py
pym/portage/__init__.py
pym/portage/dbapi/porttree.py
pym/portage/env/__init__.py [new file with mode: 0644]
pym/portage/env/config.py [new file with mode: 0644]
pym/portage/tests/__init__.py
pym/portage/tests/dep/test_isvalidatom.py
pym/portage/tests/env/__init__.py [new file with mode: 0644]
pym/portage/tests/env/config/__init__.py [new file with mode: 0644]
pym/portage/tests/env/config/test_PackageKeywordsFile.py [new file with mode: 0644]
pym/portage/tests/env/config/test_PackageMaskFile.py [new file with mode: 0644]
pym/portage/tests/env/config/test_PackageUseFile.py [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index d0d6886aebb83fc00aed2bc94c6c5b416f53f128..52fc11b48d54bebd0be65148e88e7f3cf8a4beed 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ News (mainly features/major bug fixes)
 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,
index b59eb0a0e1a1112a7fce6ab008cd12efe4823dc1..9c3ae32cf765027045c560a37787df5f2309a947 100644 (file)
@@ -165,14 +165,12 @@ Special USE flags used by catalyst for building a stage3 and GRP sets.
 .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:
@@ -183,12 +181,11 @@ a '\-'.
 .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
index 0ad0f7f6911e2251f1e7b861083a0aafd7719ff8..9da322b847564c116236a3951a617cd570b06235 100644 (file)
@@ -2163,7 +2163,7 @@ class depgraph:
                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():
@@ -2172,9 +2172,7 @@ class depgraph:
                                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:
@@ -2604,7 +2602,7 @@ class depgraph:
                                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],
@@ -2621,8 +2619,7 @@ class depgraph:
                                                                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
@@ -4995,6 +4992,11 @@ def action_build(settings, trees, mtimedb,
                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):
index de8d0be9178777ad3bfe2f33562e6ee586b0badf..c7affe743499dfc3032f630c61b937c621e9db1f 100644 (file)
@@ -4336,7 +4336,7 @@ def key_expand(mykey, mydb=None, use_cache=1, settings=None):
        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
@@ -4344,7 +4344,7 @@ def key_expand(mykey, mydb=None, use_cache=1, settings=None):
                                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
@@ -4499,18 +4499,6 @@ def getmaskingstatus(mycpv, settings=None, portdb=None):
 
        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
index be170fed8f55bf45d106ffff12bc3a5e90297257..08e6961492adf2463e7246ec31ec62cce423fd42 100644 (file)
@@ -613,23 +613,6 @@ class portdbapi(dbapi):
                                                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):
diff --git a/pym/portage/env/__init__.py b/pym/portage/env/__init__.py
new file mode 100644 (file)
index 0000000..63f6f9e
--- /dev/null
@@ -0,0 +1,4 @@
+# Copyright: 2007 Gentoo Foundation
+# License: GPL2
+# $Id$
+
diff --git a/pym/portage/env/config.py b/pym/portage/env/config.py
new file mode 100644 (file)
index 0000000..e3898c5
--- /dev/null
@@ -0,0 +1,169 @@
+# 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
index 56fc869c2beabe99d4875b53bbbb6acf9c1cfce8..7d13af1e6cc7a4f55ab9afb30c5e4f00a9d377ef 100644 (file)
@@ -7,7 +7,7 @@ import os, unittest, time
 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:
@@ -37,36 +37,29 @@ def getTests( path, base_path ):
        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(".")
        
@@ -75,7 +68,7 @@ class TextTestResult(unittest._TextTestResult):
                        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):
        """
@@ -85,14 +78,13 @@ 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()
@@ -114,9 +106,10 @@ class TestCase(unittest.TestCase):
                                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:
index 5f0149120f736b76878d1cc3a91238a4cf8f4530..512d9b4656005588d102589197c6e5991540ab8a 100644 (file)
@@ -13,7 +13,8 @@ class IsValidAtom(TestCase):
        """
 
        def testIsValidAtom(self):
-               
+       
+               self.todo = True        
                tests = [ ( "sys-apps/portage", True ),
                          ( "=sys-apps/portage-2.1", True ),
                          ( "=sys-apps/portage-2.1*", True ),
@@ -33,7 +34,6 @@ class IsValidAtom(TestCase):
                          ( "portage", False ) ]
 
                for test in tests:
-                       raise self.SkipException()
                        if test[1]:
                                atom_type = "valid"
                        else:
diff --git a/pym/portage/tests/env/__init__.py b/pym/portage/tests/env/__init__.py
new file mode 100644 (file)
index 0000000..50e38af
--- /dev/null
@@ -0,0 +1,5 @@
+# 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$
+
diff --git a/pym/portage/tests/env/config/__init__.py b/pym/portage/tests/env/config/__init__.py
new file mode 100644 (file)
index 0000000..7fc0d0e
--- /dev/null
@@ -0,0 +1,5 @@
+# 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$
+
diff --git a/pym/portage/tests/env/config/test_PackageKeywordsFile.py b/pym/portage/tests/env/config/test_PackageKeywordsFile.py
new file mode 100644 (file)
index 0000000..32e9c30
--- /dev/null
@@ -0,0 +1,37 @@
+# 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)
diff --git a/pym/portage/tests/env/config/test_PackageMaskFile.py b/pym/portage/tests/env/config/test_PackageMaskFile.py
new file mode 100644 (file)
index 0000000..f17eaf0
--- /dev/null
@@ -0,0 +1,30 @@
+# 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)
diff --git a/pym/portage/tests/env/config/test_PackageUseFile.py b/pym/portage/tests/env/config/test_PackageUseFile.py
new file mode 100644 (file)
index 0000000..4638923
--- /dev/null
@@ -0,0 +1,35 @@
+# 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)