completely rewrite file bits, use Loader classes to push loading functionality down
authorAlec Warner <antarus@gentoo.org>
Sun, 25 Mar 2007 05:55:29 +0000 (05:55 -0000)
committerAlec Warner <antarus@gentoo.org>
Sun, 25 Mar 2007 05:55:29 +0000 (05:55 -0000)
svn path=/main/trunk/; revision=6280

pym/portage/env/config.py

index 675e0105793539e33fbead8712cdcce64a27dae9..9f81d633fc852cab7e6045d4c48e7e5541415cd8 100644 (file)
@@ -6,6 +6,171 @@
 import os
 from UserDict import UserDict
 
+class DataLoader(object):
+
+       def load(self):
+               """
+               Function to do the actual work of a Loader
+               """
+               pass
+
+class AtomFileLoader(DataLoader):
+       """
+       Class to load data from a file full of atoms one per line
+       
+       >>> atom1
+       >>> atom2
+       >>> atom3
+       
+       becomes ['atom1', 'atom2', 'atom3']
+       """
+       
+       _recursive = False
+
+       def __init__(self, filename):
+               DataLoader.__init__(self)
+               self.fname = filename
+       
+       def load(self):
+                data = {}
+                errors = {}
+                line_count = 0
+                file_list = None
+                if self._recursive and os.path.isdir(self.fname):
+                        for root, dirs, files in os.walk(self.fname):
+                                if 'CVS' in dirs:
+                                        dirs.remove('CVS')
+                                files = filter(files,startswith('.'))
+                                file_list.append([f.join(root,f) for f in files])
+                else:
+                        file_list = [self.fname]
+               
+               for file in file_list:
+                       f = open(file, 'rb')
+                       for line in f:
+                               line_count = line_count + 1
+                               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_count, split))
+                               key = split[0]
+                               data[key] = None                        
+               return (data,errors)
+
+class KeyListFileLoader(DataLoader):
+       """
+       Class to load data from a file full of key [list] tuples
+       
+       >>>>key foo1 foo2 foo3
+       becomes
+       {'key':['foo1','foo2','foo3']}
+       """
+
+       _recursive = False
+
+       def __init__(self, filename):
+               DataLoader.__init__(self)
+               self.fname = filename
+
+       def load(self):
+               data = {}
+               errors = {}
+               line_count = 0
+               file_list = None
+               if self._recursive and os.path.isdir(self.fname):
+                       for root, dirs, files in os.walk(self.fname):
+                               if 'CVS' in dirs:
+                                       dirs.remove('CVS')
+                               files = filter(files,startswith('.'))
+                               file_list.append([f.join(root,f) for f in files])
+               else:
+                       file_list = [self.fname]
+
+               for file in file_list:
+                       f = open(file, 'rb')
+                       for line in f:
+                               line_count = line_count + 1
+                               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_count, split))
+                               key = split[0]
+                               value = split[1:]
+                               if key in data:
+                                       data[key].append(value)
+                               else:
+                                       data[key] = value
+               return (data,errors)
+
+class KeyValuePairFileLoader(DataLoader):
+       """
+       Class to load data from a file full of key=value pairs
+       
+       >>>>key=value
+       >>>>foo=bar
+       becomes:
+       {'key':'value',
+        'foo':'bar'}
+       """
+
+       _recursive = False
+
+       def __init__(self, filename):
+               DataLoader.__init__(self)
+               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.
+               """
+
+               DataLoader.load(self)
+               data = {}
+               errors = {}
+               line_count = 0
+                file_list = None
+                if self._recursive and os.path.isdir(self.fname):
+                        for root, dirs, files in os.walk(self.fname):
+                                if 'CVS' in dirs:
+                                        dirs.remove('CVS')
+                                files = filter(files,startswith('.'))
+                                file_list.append([f.join(root,f) for f in files])
+                else:
+                        file_list = [self.fname]
+
+                for file in file_list:
+                       f = open(file, 'rb')
+                       for line in f:
+                               line_count = line_count + 1 # Increment line count
+                               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_count, split))
+                               key = split[0]
+                               value = split[1:]
+                               if key in data:
+                                       data[key].append(value)
+                               else:
+                                       data[key] = value
+               return (data,errors)
+
 class PackageKeywords(UserDict):
        """
        A base class stub for things to inherit from; some people may want a database based package.keywords or something
@@ -16,6 +181,12 @@ class PackageKeywords(UserDict):
        
        data = {}
        
+       def __init__(self, loader):
+               self._loader = loader
+
+       def load(self):
+               self.data, self.errors = self._loader.load()
+
        def iteritems(self):
                return self.data.iteritems()
        
@@ -32,33 +203,13 @@ 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
 
+       default_loader = KeyListFileLoader
+
+       def __init__(self, filename):
+               self.loader = self.default_loader(filename)
+               PackageKeywords.__init__(self, self.loader)
+       
 class PackageUse(UserDict):
        """
        A base class stub for things to inherit from; some people may want a database based package.keywords or something
@@ -69,6 +220,12 @@ class PackageUse(UserDict):
        
        data = {}
        
+       def __init__(self, loader):
+               self._loader = loader
+
+       def load( self):
+               self.data, self.errors = self._loader.load()
+
        def iteritems(self):
                return self.data.iteritems()
        
@@ -85,40 +242,24 @@ class PackageUseFile(PackageUse):
        """
        Inherits from PackageUse; implements a file-based backend.  Doesn't handle recursion yet.
        """
+
+       default_loader = KeyListFileLoader
        def __init__(self, filename):
-               self.fname = filename
+               self.loader = self.default_loader(filename)
+               PackageUse.__init__(self, self.loader)
        
-       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 __init__(self, loader):
+               self._loader = loader
+       
+       def load(self):
+               self.data, self.errors = self._loader.load()
+               
        def iteritems(self):
                return self.data.iteritems()
        
@@ -146,24 +287,8 @@ class PackageMaskFile(PackageMask):
        to revert a previous mask; this only works when masking files are stacked
        """
        
+       default_loader = KeyValuePairFileLoader
+
        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
+               self.loader = self.default_loader(filename)
+               PackageMask.__init__(self, self.loader)