From c7993113d10ec8412cf60663d3afcbb9643fbb2a Mon Sep 17 00:00:00 2001 From: necoro <> Date: Wed, 6 Sep 2006 19:11:50 +0000 Subject: --- geneticone/__init__.py | 20 +++++ geneticone/__init__.pyc | Bin 0 -> 454 bytes geneticone/helper.py | 190 +++++++++++++++++++++++++++++++++++++++++++++ geneticone/helper.pyc | Bin 0 -> 9391 bytes geneticone/package.py | 202 ++++++++++++++++++++++++++++++++++++++++++++++++ geneticone/package.pyc | Bin 0 -> 6488 bytes 6 files changed, 412 insertions(+) create mode 100644 geneticone/__init__.py create mode 100644 geneticone/__init__.pyc create mode 100644 geneticone/helper.py create mode 100644 geneticone/helper.pyc create mode 100644 geneticone/package.py create mode 100644 geneticone/package.pyc (limited to 'geneticone') diff --git a/geneticone/__init__.py b/geneticone/__init__.py new file mode 100644 index 0000000..b1ec682 --- /dev/null +++ b/geneticone/__init__.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +import sys + +# insert the gentoolkit-location into syspath +sys.path.insert(0, "/usr/lib/gentoolkit/pym") + +# import gentoolkit and portage +import gentoolkit +import portage + +# this is set to "var/lib/portage/world" by default - so we add the leading / +portage.WORLD_FILE = "/"+portage.WORLD_FILE + +# portage tree vars +porttree = gentoolkit.porttree +vartree = gentoolkit.vartree + +# import our packages +from helper import * +from package import * diff --git a/geneticone/__init__.pyc b/geneticone/__init__.pyc new file mode 100644 index 0000000..b0b671e Binary files /dev/null and b/geneticone/__init__.pyc differ diff --git a/geneticone/helper.py b/geneticone/helper.py new file mode 100644 index 0000000..8f801ce --- /dev/null +++ b/geneticone/helper.py @@ -0,0 +1,190 @@ +#!/usr/bin/python + +from geneticone import * +import geneticone + +import re +import os + +import gentoolkit +import portage +from portage_util import unique_array + +class BlockedException (Exception): + pass + +class PackageNotFoundException (Exception): + pass + +def find_lambda (name): + """Returns the function needed by all the find_all_*-functions. Returns None if no name is given.""" + if name != None: + return lambda x: re.match(".*"+name+".*",x) + else: + return lambda x: True + +def geneticize_list (list_of_packages): + '''to convert the output of each gentoolkit helper function is a list of *geneticone* Package objects + ''' + cpvs=[x.get_cpv() for x in list_of_packages] + return [geneticone.Package(x) for x in cpvs] + +def find_best_match (search_key, only_installed = False): + """Finds the best match in the portage tree.""" + t = None + if not only_installed: + t = porttree.dep_bestmatch(search_key) + else: + t = vartree.dep_bestmatch(search_key) + if t: + return geneticone.Package(t) + return None + +def find_packages (search_key, masked=False): + """This returns a list of packages which have to fit exactly. Additionally ranges like '<,>,=,~,!' et. al. are possible.""" + return geneticize_list(gentoolkit.find_packages(search_key, masked)) + +def find_installed_packages (search_key, masked=False): + """This returns a list of installed packages which have to fit exactly. Additionally ranges like '<,>,=,~,!' et. al. are possible.""" + return geneticize_list(gentoolkit.find_installed_packages(search_key, masked)) + +def find_system_packages (name=None): + """Returns a list-tuple (resolved_packages, unresolved_packages) for all system packages.""" + list = gentoolkit.find_system_packages() + return (geneticize_list(list[0]), geneticize_list(list[1])) + +def find_world_packages (): + """Returns a list-tuple (resolved_packages, unresolved_packages) for all packages in the world-file.""" + list = gentoolkit.find_world_packages() + return geneticize_list(list[0]),geneticize_list(list[1]) + +def find_all_installed_packages (name=None): + """Returns a list of all installed packages matching ".*name.*". + Returns ALL installed packages if name is None.""" + return geneticize_list(gentoolkit.find_all_installed_packages(find_lambda(name))) + +def find_all_uninstalled_packages (name=None): + """Returns a list of all uninstalled packages matching ".*name.*". + Returns ALL uninstalled packages if name is None.""" + return geneticize_list(gentoolkit.find_all_uninstalled_packages(find_lambda(name))) + +def find_all_packages (name=None): + """Returns a list of all packages matching ".*name.*". + Returns ALL packages if name is None.""" + return geneticize_list(gentoolkit.find_all_packages(find_lambda(name))) + +def find_all_world_files (name=None): + """Returns a list of all world packages matching ".*name.*". + Returns ALL world packages if name is None.""" + world = filter(find_lambda(name), [x.get_cpv() for x in find_world_packages()[0]]) + world = unique_array(world) + return [geneticone.Package(x) for x in world] + +def find_all_system_files (name=None): + """Returns a list of all system packages matching ".*name.*". + Returns ALL system packages if name is None.""" + sys = filter(find_lambda(name), [x.get_cpv() for x in find_system_packages()[0]]) + sys = unique_array(sys) + return [geneticone.Package(x) for x in sys] + +def list_categories (name=None): + """Returns a list of categories matching ".*name.*" or all categories.""" + categories = gentoolkit.settings.categories + return filter(find_lambda(name), categories) + +def split_package_name (name): + """Returns a list in the form [category, name, version, revision]. Revision will + be 'r0' if none can be inferred. Category and version will be empty, if none can + be inferred.""" + return gentoolkit.split_package_name(name) + +def sort_package_list(pkglist): + """Sorts a package list in the same manner portage does.""" + return gentoolkit.sort_package_list(pkglist) + +def am_i_root (): + """Returns True if the current user is root, False otherwise.""" + if os.getuid() == 0: + return True + else: + return False + +def old_export_to_dictionaries (list_of_packages): + '''DEPRECATED: + Exports some of the intrinsic data of a list of Package objects to a list of dictionaries. + This is meant to transmit data back to the genetic-client, just by eval()-uating the output.''' + dictionaries=[] + keys=['name','version','category','cpv','runtime_deps','compiletime_deps','postmerge_deps','is_installed', 'is_overlay', 'is_masked','mask_status', 'package_path', 'size','use_flags_when_installed','all_useflags','set_useflags'] + package_methods=['get_name','get_version','get_category','get_cpv','get_runtime_deps', 'get_compiletime_deps','get_postmerge_deps','is_installed','is_overlay','is_masked','get_mask_status','get_package_path','size','get_use_flags','get_all_useflags','get_set_useflags'] + + for item in list_of_packages: + dictionaries.append({}) + for key,method in zip(keys,package_methods): + try: + dictionaries[-1][key]=eval('item.'+method+'()') + except AttributeError: #this may happen if, for example, package is not installed and I look for the path... + dictionaries[-1][key]=None + return dictionaries + +def export_to_dictionaries (packages): + '''Exports some of the intrinsic data of a list of Package objects to a list of dictionaries. + This is meant to transmit data back to the genetic-client, just by eval()-uating the output.''' + dictionaries=[] + + for item in packages: + dictionaries.append({}) + for method in dir(item): + if (method.startswith('get_') or method.startswith('is_'))\ + and method != 'get_dependants': # bug in gentoolkit.Package.get_dependants --> see bug #137783 + key = method[method.index('_')+1:] # the key is everything after the first underscore + try: + dictionaries[-1][key] = eval("item."+method+"()") + except AttributeError: # this may happen if, for example, package is not installed and I look for the path... + dictionaries[-1][key] = None + except TypeError: + pass # this method takes an argument - ignore it + except NotImplementedError: + pass # this method is not implemented - ignore + except "Not implemented yet!": + pass + return dictionaries + +use_descs = {} +local_use_descs = {} +def get_use_desc (flag, package = None): + """Returns the description of a specific useflag or None if no desc was found. + If a package is given (in the / format) the local use descriptions are searched too. + In the first run the dictionaries 'use_descs' and 'local_use_descs' are filled.""" + # fill cache if needed + if use_descs == {} or local_use_descs == {}: + # read use.desc + fd = open(gentoolkit.settings["PORTDIR"]+"/profiles/use.desc") + for line in fd.readlines(): + line = line.strip() + if line != "" and line[0] != '#': + fields = [x.strip() for x in line.split(" - ",1)] + if len(fields) == 2: + use_descs[fields[0]] = fields[1] + + # read use.local.desc + fd = open(gentoolkit.settings["PORTDIR"]+"/profiles/use.local.desc") + for line in fd.readlines(): + line = line.strip() + if line != "" and line[0] != '#': + fields = [x.strip() for x in line.split(":",1)] + if len(fields) == 2: + if not fields[0] in local_use_descs: # create + local_use_descs[fields[0]] = {} + subfields = [x.strip() for x in fields[1].split(" - ",1)] + if len(subfields) == 2: + local_use_descs[fields[0]][subfields[0]] = subfields[1] + + # start + desc = None + if flag in use_descs: + desc = use_descs[flag] + if package != None: + if package in local_use_descs: + if flag in local_use_descs[package]: + desc = local_use_descs[package][flag] + return desc diff --git a/geneticone/helper.pyc b/geneticone/helper.pyc new file mode 100644 index 0000000..50fb7e8 Binary files /dev/null and b/geneticone/helper.pyc differ diff --git a/geneticone/package.py b/geneticone/package.py new file mode 100644 index 0000000..6ec2299 --- /dev/null +++ b/geneticone/package.py @@ -0,0 +1,202 @@ +#!/usr/bin/python + +from geneticone import * + +import gentoolkit +import portage +from portage_util import unique_array + +class Package (gentoolkit.Package): + """This is just a subclass of the Package-class of gentoolkit.""" + + def __init__ (self, cpv): + gentoolkit.Package.__init__(self, cpv) + + def get_mask_status(self): + '''gets the numeric mask status of a package + can be translated as string: + maskmodes = [ " ", " ~", " -", "M ", "M~", "M-" ] + (0=unmasked 1=~arch 2=-arch etc.) + + This method adapted from equery 0.1.4 + Original author: Karl Trygve Kalleberg + ''' + + pkgmask = 0 + if self.is_masked(): + pkgmask = pkgmask + 3 + keywords = self.get_env_var("KEYWORDS").split() + if "~" + gentoolkit.settings["ARCH"] in keywords: + pkgmask = pkgmask + 1 + elif "-*" in keywords or "-" + gentoolkit.settings["ARCH"] in keywords: + pkgmask = pkgmask + 2 + return pkgmask + + def get_size (self): + return self.size() + + def get_all_useflags (self): + """Returns a list of _all_ useflags for this package.""" + return self.get_env_var("IUSE").split() + + def get_all_deps (self): + """Returns a linearised list of all first-level dependencies for this package, on + the form [(comparator, [use flags], cpv), ...]""" + return unique_array(self.get_compiletime_deps()+self.get_runtime_deps()+self.get_postmerge_deps()) + + def get_dep_packages (self): + """Returns a cpv-list of packages on which this package depends and which have not been installed yet. + raises: BlockedException, PackageNotFoundException.""" + dep_pkgs = [] # the package list + + # let portage do the main stuff ;) + # pay attention to any changes here + deps = portage.dep_check (self.get_env_var("RDEPEND")+" "+self.get_env_var("DEPEND"), vartree.dbapi, self._settings) + + if not deps: # what is the difference to [1, []] ? + return [] + + deps = deps[1] + + for dep in deps: + if dep[0] == '!': + blocked = find_installed_packages(dep[1:]) + if blocked != []: + raise BlockedException, blocked[0].get_cpv() + else: # next flag + continue + + pkg = find_best_match(dep) + if not dep: + raise PackageNotFoundException, dep + else: + dep_pkgs.append(pkg.get_cpv()) + + return dep_pkgs + + def own_get_dep_packages (self, old_cpv_dict = {}): + # XXX: after having finished this, i realized, that there is already a portage function -.- ; + # will keep this in case portage changes anything + """Returns a list of all packages (i.e. package-cpvs) which this package depends on and which not have been installed yet. + Param old_cpv_dict is a {cp: version}-dictionary holding already found deps. + Raises a BlockedException if the package is being blocked by another installed package.""" + # XXX: This won't find blocking dependencies + # XXX: Has some problems with modular X (this has a very strange ebuild) ... we should enhance _parse_deps + print "Actual: "+self._cpv # debug output + + uses = [] # list of actual useflags / useflags the package has been installed with + dep_packages = [] # list of packages returned + dep_cpv_dict = {} # all dependencies are inserted here + + # get useflags + if self.is_installed(): + uses = self.get_set_useflags() + else: + uses = self.get_settings("USE") + + # cycle through dependencies + for (comp, flags, dep_cpv) in self.get_all_deps(): + + # find blocking packages + if comp and comp[0] == '!': + blocked = find_installed_packages(comp[1:]+dep_cpv) + if blocked != []: + raise BlockedException, blocked[0].get_cpv() + else: # next flag + continue + + # look whether this package is really required + needDep = True + for flag in flags: + if (flag[0] == '!' and flag[1:] in uses) or (flag[0] != '!' and flag not in uses): + needDep = False + break + + if needDep: # it is ... + if find_installed_packages(comp+dep_cpv) == []: # ... and not installed yet + d = find_best_match(comp+dep_cpv) + if not d: # no package found + raise PackageNotFoundException, dep_cpv + if d.get_cp() not in old_cpv_dict: # ... and not found already by an other package + dep_cpv_dict[d.get_cp()] = d.get_version() + print "Dep: "+d.get_cpv() # debug + dep_packages.append(d.get_cpv()) + + for dep in dep_packages: # find dependencies for each package + old_cpv_dict.update(dep_cpv_dict) + old_cpv_dict.update({self.get_cp() : self.get_version()}) + dep_packages += find_packages("="+dep)[0].own_get_dep_packages(old_cpv_dict) + + return unique_array(dep_packages) + + def get_set_useflags (self): + """Returns a list of the useflags enabled at installation time. If package is not installed, it returns an empty list.""" + if self.is_installed(): + uses = self.get_use_flags().split() + iuses = self.get_all_useflags() + set = [] + for u in iuses: + if u in uses: + set.append(u) + return set + else: + return [] + + def get_cp (self): + """Returns category/package.""" + return self.get_category()+"/"+self.get_name() + + def is_masked (self): + """Returns True if either masked by package.mask or by profile.""" + # XXX: Better solution than string comparison? + status = portage.getmaskingstatus(self._cpv) + if "profile" in status or "package.mask" in status: + return True + return False + + def _parse_deps(self,deps,curuse=[],level=0): + """Modified method "_parse_deps" of gentoolkit.Package. + Do NOT ignore blocks.""" + # store (comparator, [use predicates], cpv) + r = [] + comparators = ["~","<",">","=","<=",">="] + end = len(deps) + i = 0 + while i < end: + blocked = False + tok = deps[i] + if tok == ')': + return r,i + if tok[-1] == "?": + tok = tok.replace("?","") + sr,l = self._parse_deps(deps[i+2:],curuse=curuse+[tok],level=level+1) + r += sr + i += l + 3 + continue + if tok == "||": + sr,l = self._parse_deps(deps[i+2:],curuse,level=level+1) + r += sr + i += l + 3 + continue + # conjonction, like in "|| ( ( foo bar ) baz )" => recurse + if tok == "(": + sr,l = self._parse_deps(deps[i+1:],curuse,level=level+1) + r += sr + i += l + 2 + continue + # pkg block "!foo/bar" => ignore it + if tok[0] == "!": + #i += 1 + #continue + blocked = True # added + tok = tok[1:] # added + # pick out comparator, if any + cmp = "" + for c in comparators: + if tok.find(c) == 0: + cmp = c + if blocked: cmp = "!"+cmp # added + tok = tok[len(cmp):] + r.append((cmp,curuse,tok)) + i += 1 + return r,i diff --git a/geneticone/package.pyc b/geneticone/package.pyc new file mode 100644 index 0000000..977ef4e Binary files /dev/null and b/geneticone/package.pyc differ -- cgit v1.2.3-70-g09d2