diff options
Diffstat (limited to 'pym/gentoolkit/eclean/exclude.py')
-rw-r--r-- | pym/gentoolkit/eclean/exclude.py | 483 |
1 files changed, 256 insertions, 227 deletions
diff --git a/pym/gentoolkit/eclean/exclude.py b/pym/gentoolkit/eclean/exclude.py index 1da9523..a5c29d4 100644 --- a/pym/gentoolkit/eclean/exclude.py +++ b/pym/gentoolkit/eclean/exclude.py @@ -13,254 +13,283 @@ from portage import _encodings, _unicode_encode # Misc. shortcuts to some portage stuff: listdir = portage.listdir -FILENAME_RE = [re.compile(r'(?P<pkgname>[-a-zA-z0-9\+]+)(?P<ver>-\d+\S+)'), - re.compile(r'(?P<pkgname>[-a-zA-z]+)(?P<ver>_\d+\S+)'), - re.compile(r'(?P<pkgname>[-a-zA-z_]+)(?P<ver>\d\d+\S+)'), - re.compile(r'(?P<pkgname>[-a-zA-z0-9_]+)(?P<ver>-default\S+)'), - re.compile(r'(?P<pkgname>[-a-zA-z0-9]+)(?P<ver>_\d\S+)'), - re.compile(r'(?P<pkgname>[-a-zA-z0-9\+\.]+)(?P<ver>-\d+\S+)'), - re.compile(r'(?P<pkgname>[-a-zA-z0-9\+\.]+)(?P<ver>.\d+\S+)')] +FILENAME_RE = [ + re.compile(r"(?P<pkgname>[-a-zA-z0-9\+]+)(?P<ver>-\d+\S+)"), + re.compile(r"(?P<pkgname>[-a-zA-z]+)(?P<ver>_\d+\S+)"), + re.compile(r"(?P<pkgname>[-a-zA-z_]+)(?P<ver>\d\d+\S+)"), + re.compile(r"(?P<pkgname>[-a-zA-z0-9_]+)(?P<ver>-default\S+)"), + re.compile(r"(?P<pkgname>[-a-zA-z0-9]+)(?P<ver>_\d\S+)"), + re.compile(r"(?P<pkgname>[-a-zA-z0-9\+\.]+)(?P<ver>-\d+\S+)"), + re.compile(r"(?P<pkgname>[-a-zA-z0-9\+\.]+)(?P<ver>.\d+\S+)"), +] debug_modules = [] + def dprint(module, message): - if module in debug_modules: - print(message) + if module in debug_modules: + print(message) + def isValidCP(cp): - """Check whether a string is a valid cat/pkg-name. + """Check whether a string is a valid cat/pkg-name. - This is for 2.0.51 vs. CVS HEAD compatibility, I've not found any function - for that which would exists in both. Weird... + This is for 2.0.51 vs. CVS HEAD compatibility, I've not found any function + for that which would exists in both. Weird... - @param cp: catageory/package string - @rtype: bool - """ + @param cp: catageory/package string + @rtype: bool + """ - if not '/' in cp: - return False - try: - portage.cpv_getkey(cp+"-0") - except: - return False - else: - return True + if not "/" in cp: + return False + try: + portage.cpv_getkey(cp + "-0") + except: + return False + else: + return True class ParseExcludeFileException(Exception): - """For parseExcludeFile() -> main() communication. + """For parseExcludeFile() -> main() communication. + + @param value: Error message string + """ + + def __init__(self, value): + self.value = value - @param value: Error message string - """ - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) + def __str__(self): + return repr(self.value) def parseExcludeFile(filepath, output): - """Parses an exclusion file. - - @param filepath: file containing the list of cat/pkg's to exclude - @param output: --verbose enabled output method or "lambda x: None" - - @rtype: dict - @return: an exclusion dict - @raise ParseExcludeFileException: in case of fatal error - """ - - exclude = { - 'categories': {}, - 'packages': {}, - 'anti-packages': {}, - 'filenames': {} - } - output("Parsing Exclude file: " + filepath) - try: - file_ = open(_unicode_encode(filepath, - encoding=_encodings['fs']), mode="r", encoding=_encodings['content']) - except IOError: - raise ParseExcludeFileException("Could not open exclusion file: " + - filepath) - filecontents = file_.readlines() - file_.close() - cat_re = re.compile(r'^(?P<cat>[a-zA-Z0-9]+-[a-zA-Z0-9]+)(/\*)?$') - cp_re = re.compile(r'^(?P<cp>[-a-zA-Z0-9_]+/[-a-zA-Z0-9_]+)$') - # used to output the line number for exception error reporting - linenum = 0 - for line in filecontents: - # need to increment it here due to continue statements. - linenum += 1 - line = line.strip() - if not len(line): # skip blank a line - continue - if line[0] == '#': # skip a comment line - continue - #print( "parseExcludeFile: line=", line) - try: # category matching - cat = cat_re.match(line).group('cat') - #print( "parseExcludeFile: found cat=", cat) - except: - pass - else: - if not cat in portage.settings.categories: - raise ParseExcludeFileException("Invalid category: "+cat + - " @line # " + str(linenum)) - exclude['categories'][cat] = None - continue - dict_key = 'packages' - if line[0] == '!': # reverses category setting - dict_key = 'anti-packages' - line = line[1:] - try: # cat/pkg matching - cp = cp_re.match(line).group('cp') - #print( "parseExcludeFile: found cp=", cp) - if isValidCP(cp): - exclude[dict_key][cp] = None - continue - else: - raise ParseExcludeFileException("Invalid cat/pkg: "+cp + - " @line # " + str(linenum)) - except: - pass - #raise ParseExcludeFileException("Invalid line: "+line) - try: # filename matching. - exclude['filenames'][line] = re.compile(line) - #print( "parseExcludeFile: found filenames", line) - except: - try: - exclude['filenames'][line] = re.compile(re.escape(line)) - #print( "parseExcludeFile: found escaped filenames", line) - except: - raise ParseExcludeFileException("Invalid file name/regular " + - "expression: @line # " + str(linenum) + " line=" +line) - output("Exclude file parsed. Found " + - "%d categories, %d packages, %d anti-packages %d filenames" - %(len(exclude['categories']), len(exclude['packages']), - len(exclude['anti-packages']), len(exclude['filenames']))) - #print() - #print( "parseExcludeFile: final exclude_dict = ", exclude) - #print() - return exclude - -def cp_all(categories, portdb=portage.portdb ): - """temp function until the new portdb.cp_all([cat,...]) - behaviour is fully available. - - @param categories: list of categories to get all packages for - eg. ['app-portage', 'sys-apps',...] - @rtype: list of cat/pkg's ['foo/bar', 'foo/baz'] - """ - try: - cps = portdb.cp_all(categories) - # NOTE: the following backup code should be removed - # when all available versions of portage have the - # categories parameter in cp_all() - except: # new behaviour not available - #~ message = "Exception: eclean.exclude.cp_all() " +\ - #~ "new portdb.cp_all() behavior not found. using fallback code" - #~ print( warn(message), file=sys.stderr) - cps = [] - # XXX: i smell an access to something which is really out of API... - _pkg_dir_name_re = re.compile(r'^\w[-+\w]*$') - for tree in portdb.porttrees: - for cat in categories: - for pkg in listdir(os.path.join(tree,cat), - EmptyOnError=1, ignorecvs=1, dirsonly=1): - if not _pkg_dir_name_re.match(pkg) or pkg == "CVS": - continue - cps.append(cat+'/'+pkg) - #print( "cp_all: new cps list=", cps) - return cps + """Parses an exclusion file. + + @param filepath: file containing the list of cat/pkg's to exclude + @param output: --verbose enabled output method or "lambda x: None" + + @rtype: dict + @return: an exclusion dict + @raise ParseExcludeFileException: in case of fatal error + """ + + exclude = {"categories": {}, "packages": {}, "anti-packages": {}, "filenames": {}} + output("Parsing Exclude file: " + filepath) + try: + file_ = open( + _unicode_encode(filepath, encoding=_encodings["fs"]), + mode="r", + encoding=_encodings["content"], + ) + except IOError: + raise ParseExcludeFileException("Could not open exclusion file: " + filepath) + filecontents = file_.readlines() + file_.close() + cat_re = re.compile(r"^(?P<cat>[a-zA-Z0-9]+-[a-zA-Z0-9]+)(/\*)?$") + cp_re = re.compile(r"^(?P<cp>[-a-zA-Z0-9_]+/[-a-zA-Z0-9_]+)$") + # used to output the line number for exception error reporting + linenum = 0 + for line in filecontents: + # need to increment it here due to continue statements. + linenum += 1 + line = line.strip() + if not len(line): # skip blank a line + continue + if line[0] == "#": # skip a comment line + continue + # print( "parseExcludeFile: line=", line) + try: # category matching + cat = cat_re.match(line).group("cat") + # print( "parseExcludeFile: found cat=", cat) + except: + pass + else: + if not cat in portage.settings.categories: + raise ParseExcludeFileException( + "Invalid category: " + cat + " @line # " + str(linenum) + ) + exclude["categories"][cat] = None + continue + dict_key = "packages" + if line[0] == "!": # reverses category setting + dict_key = "anti-packages" + line = line[1:] + try: # cat/pkg matching + cp = cp_re.match(line).group("cp") + # print( "parseExcludeFile: found cp=", cp) + if isValidCP(cp): + exclude[dict_key][cp] = None + continue + else: + raise ParseExcludeFileException( + "Invalid cat/pkg: " + cp + " @line # " + str(linenum) + ) + except: + pass + # raise ParseExcludeFileException("Invalid line: "+line) + try: # filename matching. + exclude["filenames"][line] = re.compile(line) + # print( "parseExcludeFile: found filenames", line) + except: + try: + exclude["filenames"][line] = re.compile(re.escape(line)) + # print( "parseExcludeFile: found escaped filenames", line) + except: + raise ParseExcludeFileException( + "Invalid file name/regular " + + "expression: @line # " + + str(linenum) + + " line=" + + line + ) + output( + "Exclude file parsed. Found " + + "%d categories, %d packages, %d anti-packages %d filenames" + % ( + len(exclude["categories"]), + len(exclude["packages"]), + len(exclude["anti-packages"]), + len(exclude["filenames"]), + ) + ) + # print() + # print( "parseExcludeFile: final exclude_dict = ", exclude) + # print() + return exclude + + +def cp_all(categories, portdb=portage.portdb): + """temp function until the new portdb.cp_all([cat,...]) + behaviour is fully available. + + @param categories: list of categories to get all packages for + eg. ['app-portage', 'sys-apps',...] + @rtype: list of cat/pkg's ['foo/bar', 'foo/baz'] + """ + try: + cps = portdb.cp_all(categories) + # NOTE: the following backup code should be removed + # when all available versions of portage have the + # categories parameter in cp_all() + except: # new behaviour not available + # ~ message = "Exception: eclean.exclude.cp_all() " +\ + # ~ "new portdb.cp_all() behavior not found. using fallback code" + # ~ print( warn(message), file=sys.stderr) + cps = [] + # XXX: i smell an access to something which is really out of API... + _pkg_dir_name_re = re.compile(r"^\w[-+\w]*$") + for tree in portdb.porttrees: + for cat in categories: + for pkg in listdir( + os.path.join(tree, cat), EmptyOnError=1, ignorecvs=1, dirsonly=1 + ): + if not _pkg_dir_name_re.match(pkg) or pkg == "CVS": + continue + cps.append(cat + "/" + pkg) + # print( "cp_all: new cps list=", cps) + return cps + def exclDictExpand(exclude): - """Returns a dictionary of all CP/CPV from porttree which match - the exclusion dictionary. - """ - d = {} - if 'categories' in exclude: - # replace the following cp_all call with - # portage.portdb.cp_all([cat1, cat2]) - # when it is available in all portage versions. - cps = cp_all(exclude['categories']) - for cp in cps: - d[cp] = None - if 'packages' in exclude: - for cp in exclude['packages']: - d[cp] = None - if 'anti-packages' in exclude: - for cp in exclude['anti-packages']: - if cp in d: - del d[cp] - return d - -def exclDictMatchCP(exclude,pkg): - """Checks whether a CP matches the exclusion rules.""" - if pkg is None: - return False - if 'anti-packages' in exclude and pkg in exclude['anti-packages']: - return False - if 'packages' in exclude and pkg in exclude['packages']: - return True - try: - cat = pkg.split('/')[0] - except: - dprint( "exclude", "exclDictMatchCP: Invalid package name: " +\ - "%s, Could not determine category" %pkg) - cat = '' - if 'categories' in exclude and cat in exclude['categories']: - return True - return False + """Returns a dictionary of all CP/CPV from porttree which match + the exclusion dictionary. + """ + d = {} + if "categories" in exclude: + # replace the following cp_all call with + # portage.portdb.cp_all([cat1, cat2]) + # when it is available in all portage versions. + cps = cp_all(exclude["categories"]) + for cp in cps: + d[cp] = None + if "packages" in exclude: + for cp in exclude["packages"]: + d[cp] = None + if "anti-packages" in exclude: + for cp in exclude["anti-packages"]: + if cp in d: + del d[cp] + return d + + +def exclDictMatchCP(exclude, pkg): + """Checks whether a CP matches the exclusion rules.""" + if pkg is None: + return False + if "anti-packages" in exclude and pkg in exclude["anti-packages"]: + return False + if "packages" in exclude and pkg in exclude["packages"]: + return True + try: + cat = pkg.split("/")[0] + except: + dprint( + "exclude", + "exclDictMatchCP: Invalid package name: " + + "%s, Could not determine category" % pkg, + ) + cat = "" + if "categories" in exclude and cat in exclude["categories"]: + return True + return False + def exclDictExpandPkgname(exclude): - """Returns a set of all pkgnames from porttree which match - the exclusion dictionary. - """ - p = set() - if 'categories' in exclude: - # replace the following cp_all call with - # portage.portdb.cp_all([cat1, cat2]) - # when it is available in all portage versions. - cps = cp_all(exclude['categories']) - for cp in cps: - pkgname = cp.split('/')[1] - p.add(pkgname) - if 'packages' in exclude: - for cp in exclude['packages']: - pkgname = cp.split('/')[1] - p.add(pkgname) - if 'anti-packages' in exclude: - for cp in exclude['anti-packages']: - if cp in p: - p.remove(cp) - return p + """Returns a set of all pkgnames from porttree which match + the exclusion dictionary. + """ + p = set() + if "categories" in exclude: + # replace the following cp_all call with + # portage.portdb.cp_all([cat1, cat2]) + # when it is available in all portage versions. + cps = cp_all(exclude["categories"]) + for cp in cps: + pkgname = cp.split("/")[1] + p.add(pkgname) + if "packages" in exclude: + for cp in exclude["packages"]: + pkgname = cp.split("/")[1] + p.add(pkgname) + if "anti-packages" in exclude: + for cp in exclude["anti-packages"]: + if cp in p: + p.remove(cp) + return p def exclMatchFilename(exclude_names, filename): - """Attempts to split the package name out of a filename - and then checks if it matches any exclusion rules. - - This is intended to be run on the cleaning list after all - normal checks and removal of protected files. This will reduce - the number of files to perform this last minute check on - - @param exclude_names: a set of pkgnames to exlcude - @param filename: - - @rtype: bool - """ - found = False - index = 0 - while not found and index < len(FILENAME_RE): - found = FILENAME_RE[index].match(filename) - index += 1 - if not found: - dprint( "exclude", "exclMatchFilename: filename: " +\ - "%s, Could not determine package name" %filename) - return False - pkgname = found.group('pkgname') - dprint("exclude", "exclMatchFilename: found pkgname = " + - "%s, %s, %d, %s" %(pkgname, str(pkgname in exclude_names), - index-1, filename)) - return (pkgname in exclude_names) + """Attempts to split the package name out of a filename + and then checks if it matches any exclusion rules. + + This is intended to be run on the cleaning list after all + normal checks and removal of protected files. This will reduce + the number of files to perform this last minute check on + + @param exclude_names: a set of pkgnames to exlcude + @param filename: + @rtype: bool + """ + found = False + index = 0 + while not found and index < len(FILENAME_RE): + found = FILENAME_RE[index].match(filename) + index += 1 + if not found: + dprint( + "exclude", + "exclMatchFilename: filename: " + + "%s, Could not determine package name" % filename, + ) + return False + pkgname = found.group("pkgname") + dprint( + "exclude", + "exclMatchFilename: found pkgname = " + + "%s, %s, %d, %s" + % (pkgname, str(pkgname in exclude_names), index - 1, filename), + ) + return pkgname in exclude_names |