From: Alec Warner Date: Sun, 25 Mar 2007 05:55:29 +0000 (-0000) Subject: completely rewrite file bits, use Loader classes to push loading functionality down X-Git-Tag: v2.2_pre1~1542 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=8bbd809c5e2e6c3d417a499ead858ea357eead9f;p=portage.git completely rewrite file bits, use Loader classes to push loading functionality down svn path=/main/trunk/; revision=6280 --- diff --git a/pym/portage/env/config.py b/pym/portage/env/config.py index 675e01057..9f81d633f 100644 --- a/pym/portage/env/config.py +++ b/pym/portage/env/config.py @@ -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)