# Copyright 2005 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Id: $ import os.path,string,re from portage_util import grabfile,writemsg class use_desc: """ A simple class to access the use.desc and use.local.desc files. """ def __init__(self,portdir): # Initialize use_desc.desc dictionnary from profiles/use.desc use_desc_path=os.path.join(portdir,"profiles/use.desc") if not os.access(use_desc_path, os.R_OK): raise Exception, "use_desc: Can't read "+use_desc_path use_desc_lines=grabfile(use_desc_path) self.desc={} use_desc_re=re.compile('^\s*(?P[\w\-\+\.]+)\s+-\s*(?P.+)\s*$') for myline in use_desc_lines: mymatch=use_desc_re.match(myline) if not mymatch: writemsg("--- Invalid use.desc entry:\n") writemsg("--- "+myline+"\n") continue (myflag,mydesc)=(mymatch.group("flag"),mymatch.group("desc")) if myflag in self.desc: writemsg("--- USE flag \""+myflag+"\" has several descriptions in use.desc.\n") continue self.desc[myflag]=mydesc # Initialize use_desc.local_desc dictionnary from profiles/use.local.desc use_local_desc_path=os.path.join(portdir,"profiles/use.local.desc") if not os.access(use_local_desc_path, os.R_OK): raise Exception, "use_desc: Can't read "+use_local_desc_path use_local_desc_lines=grabfile(use_local_desc_path) self.local_desc={} use_local_desc_re=re.compile('^\s*(?P[\w\-\+/]+):(?P[\w\-\+\.]+)\s+-\s*(?P.+)\s*$') for myline in use_local_desc_lines: mymatch=use_local_desc_re.match(myline) if not mymatch: writemsg("--- Invalid use.local.desc entry:\n") writemsg("--- "+myline+"\n") continue (mypkg,myflag,mydesc)=(mymatch.group("pkg"),mymatch.group("flag"),mymatch.group("desc")) if mypkg not in self.local_desc: self.local_desc[mypkg]={} if myflag in self.local_desc[mypkg]: writemsg("--- USE flag \""+myflag+"\" has several descriptions for package "+mypkg+" in use.local.desc.\n") continue self.local_desc[mypkg][myflag]=mydesc # Initialize use_desc.local_flag_to_pkgs, a "local flag -> list of pkgs" dictionnary. # (may be useful for some repoman checks, but i'm not sure yet) self.local_flag_to_pkgs={} for mypkg in self.local_desc: for myflag in self.local_desc[mypkg]: if myflag not in self.local_flag_to_pkgs: self.local_flag_to_pkgs[myflag]=[] self.local_flag_to_pkgs[myflag].append(mypkg) def get_local_desc(self,flag,pkg): """ Returns flag description only if it is a local flag for this pkg. """ if pkg in self.local_desc \ and flag in self.local_desc[pkg]: return self.local_desc[pkg][flag] return None def get_special_desc(self,flag,pkg): """ Returns flag description only if it is a global flag overridden for this pkg. """ if flag not in self.desc: return None return self.get_local_desc(flag,pkg) def get_global_desc(self,flag,pkg): """ Returns flag description only if it is a global flag which is not overridden in use.local.desc. """ if pkg in self.local_desc and flag in self.local_desc[pkg]: return None if flag in self.desc: return self.desc[flag] return None def get_desc(self,flag,pkg=None): """ Returns flag description. With the optionnal pkg parameter, try to find a local description first. """ if pkg and pkg in self.local_desc and flag in self.local_desc[pkg]: return self.local_desc[pkg][flag] if flag in self.desc: return self.desc[flag] return None def get_pkg_flags_desc(self,flagslist,pkg,level="all",mark_local=False): """ Returns a dictionnary of flags descriptions for a given package. The optional level parameter can be "all", "global", "local" or "special", and defaults to "all". Optionnaly, if mark_local is set, the keys from use.local.desc will be "cat/pkg:flag" instead of simply "flag". """ desc_dict={} remaningflags=[] # Get descriptions from use.local.desc first: if level != "global": get_method=self.get_local_desc if level == "special": get_method=self.get_special_desc for myflag in flagslist: mydesc=get_method(myflag,pkg) if mydesc: if mark_local: desc_dict[pkg+":"+myflag]=mydesc else: desc_dict[myflag]=mydesc else: remaningflags.append(myflag) # Then get descriptions from use.desc if in "all" or "global" mode: if level == "global": remaningflags=flagslist if level in ("all","global"): for myflag in remaningflags: if myflag in self.desc: desc_dict[myflag]=self.desc[myflag] return desc_dict def get_all_special_flags(self): """ This helper function returns a "local flag -> cat/pkg -> description" dictionnary of dictionnaries of flags that also have a description in use.desc. May be useful to advice some use.local.desc cleanups. """ my_dict={} for myflag in self.local_flag_to_pkgs: if myflag in self.desc: my_dict[myflag]={} for mypkg in self.local_flag_to_pkgs[myflag]: my_dict[myflag][mypkg] = self.local_desc[mypkg][myflag] return my_dict def get_multiple_local_flags(self,multiplicity=2): """ This helper function returns a "local flag -> cat/pkg -> description" dictionnary of dictionnaries of flags that are local to several packages. The optionnal multiplicity parameter (integer >= 2) is a bound on the number of occurences required to be in the result. May be useful to advice some local->global flags moves. """ my_dict={} if multiplicity < 2: multiplicity=2 for myflag in self.local_flag_to_pkgs: if myflag in self.desc: continue if len(self.local_flag_to_pkgs[myflag]) >= multiplicity: my_dict[myflag]={} for mypkg in self.local_flag_to_pkgs[myflag]: my_dict[myflag][mypkg] = self.local_desc[mypkg][myflag] return my_dict