From 74e6944a93674636b9ae5826a27218c30be335b5 Mon Sep 17 00:00:00 2001 From: necoro <> Date: Fri, 29 Sep 2006 19:15:41 +0000 Subject: Moved backend stuff into own backend-package --- geneticone/__init__.py | 32 --- geneticone/backend/__init__.py | 32 +++ geneticone/backend/exceptions.py | 22 ++ geneticone/backend/flags.py | 525 +++++++++++++++++++++++++++++++++++ geneticone/backend/package.py | 293 +++++++++++++++++++ geneticone/backend/portage_helper.py | 154 ++++++++++ geneticone/exceptions.py | 22 -- geneticone/flags.py | 525 ----------------------------------- geneticone/package.py | 293 ------------------- geneticone/portage_helper.py | 154 ---------- 10 files changed, 1026 insertions(+), 1026 deletions(-) delete mode 100644 geneticone/__init__.py create mode 100644 geneticone/backend/__init__.py create mode 100644 geneticone/backend/exceptions.py create mode 100644 geneticone/backend/flags.py create mode 100644 geneticone/backend/package.py create mode 100644 geneticone/backend/portage_helper.py delete mode 100644 geneticone/exceptions.py delete mode 100644 geneticone/flags.py delete mode 100644 geneticone/package.py delete mode 100644 geneticone/portage_helper.py diff --git a/geneticone/__init__.py b/geneticone/__init__.py deleted file mode 100644 index 2478ddf..0000000 --- a/geneticone/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -# -# File: geneticone/__init__.py -# This file is part of the Genetic/One-Project, a graphical portage-frontend. -# -# Copyright (C) 2006 Necoro d.M. -# This is free software. You may redistribute copies of it under the terms of -# the GNU General Public License version 2. -# There is NO WARRANTY, to the extent permitted by law. -# -# Written by Necoro d.M. - -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 exceptions import * -from portage_helper import * -from package import * diff --git a/geneticone/backend/__init__.py b/geneticone/backend/__init__.py new file mode 100644 index 0000000..2478ddf --- /dev/null +++ b/geneticone/backend/__init__.py @@ -0,0 +1,32 @@ +# +# File: geneticone/__init__.py +# This file is part of the Genetic/One-Project, a graphical portage-frontend. +# +# Copyright (C) 2006 Necoro d.M. +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by Necoro d.M. + +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 exceptions import * +from portage_helper import * +from package import * diff --git a/geneticone/backend/exceptions.py b/geneticone/backend/exceptions.py new file mode 100644 index 0000000..5780de6 --- /dev/null +++ b/geneticone/backend/exceptions.py @@ -0,0 +1,22 @@ +# +# File: geneticone/exceptions.py +# This file is part of the Genetic/One-Project, a graphical portage-frontend. +# +# Copyright (C) 2006 Necoro d.M. +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by Necoro d.M. + +class BlockedException (Exception): + """An exception marking, that some package is blocking another one.""" + pass + +class PackageNotFoundException (Exception): + """An exception marking that a package could not be found.""" + pass + +class DependencyCalcError (Exception): + """An error occured during dependency calculation.""" + pass diff --git a/geneticone/backend/flags.py b/geneticone/backend/flags.py new file mode 100644 index 0000000..8899fc5 --- /dev/null +++ b/geneticone/backend/flags.py @@ -0,0 +1,525 @@ +# +# File: geneticone/flags.py +# This file is part of the Genetic/One-Project, a graphical portage-frontend. +# +# Copyright (C) 2006 Necoro d.M. +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by Necoro d.M. + +import os +import os.path +from subprocess import Popen, PIPE # needed for grep + +import geneticone +from helper import * +import portage +from portage_util import unique_array + +### GENERAL PART ### + +def grep (pkg, path): + """Grep runs "egrep" on a given path and looks for occurences of a given package. + @param pkg: the package + @type pkg: string (cpv) or L{geneticone.Package}-object + @param path: path to look in + @type path: string + + @returns: occurences of pkg in the format: "file:line-no:complete_line_found" + @rtype: string""" + + if not isinstance(pkg, geneticone.Package): + pkg = geneticone.Package(pkg) # assume it is a cpv or a gentoolkit.Package + + command = "egrep -x -n -r -H '^[<>!=~]{0,2}%s(-[0-9].*)?[[:space:]]?.*$' %s" + return Popen((command % (pkg.get_cp(), path)), shell = True, stdout = PIPE).communicate()[0].splitlines() + +def get_data(pkg, path): + """This splits up the data of L{grep} and builds tuples in the format (file,line,criterion,list_of_flags). + @param pkg: package to find + @type pkg: string (cpv) or L{geneticone.Package}-object + @param path: path to look in + @type path: string + + @returns: a list of tuples in the form (file,line,criterion,list_of_flags) + @rtype: list""" + + flags = [] + + # do grep + list = grep(pkg, path) + + for i in range(len(list)): + file, line, fl = tuple(list[i].split(":")) # get file, line and flag-list + fl = fl.split() + crit = fl[0] + fl = fl[1:] + # stop after first comment + for i in range(len(fl)): + if fl[i][0] == "#": #comment - stop here + fl = fl[:i] + break + flags.append((file,line,crit,fl)) + + return flags + +### USE FLAG PART ### +USE_PATH = os.path.join(portage.USER_CONFIG_PATH,"package.use") +USE_PATH_IS_DIR = os.path.isdir(USE_PATH) +useFlags = {} # useFlags in the file +newUseFlags = {} # useFlags as we want them to be: format: cpv -> [(file, line, useflag, (true if removed from list / false if added))] + +def invert_use_flag (flag): + """Invertes a flag. + + >>> invert_use_flag("foo") + -foo + >>> invert_use_flag("-bar") + bar + + @param flag: the flag + @type flag: string + @returns: inverted flag + @rtype: string + """ + if flag[0] == "-": + return flag[1:] + else: + return "-"+flag + +def set_use_flag (pkg, flag): + """Sets the useflag for a given package. + + @param pkg: the package + @type pkg: string (cpv) or L{geneticone.Package}-object + @param flag: the flag to set + @type flag: string""" + + global useFlags, newUseFlags + + if not isinstance(pkg, geneticone.Package): + pkg = geneticone.Package(pkg) # assume cpv or gentoolkit.Package + + cpv = pkg.get_cpv() + invFlag = invert_use_flag(flag) + + # if not saved in useFlags, get it by calling get_data() which calls grep() + data = None + if not cpv in useFlags: + data = get_data(pkg, USE_PATH) + useFlags[cpv] = data + else: + data = useFlags[cpv] + + if not cpv in newUseFlags: + newUseFlags[cpv] = [] + + debug("data: "+str(data)) + # add a useflag / delete one + added = False + for file, line, crit, flags in data: + if pkg.matches(crit): + # we have the inverted flag in the uselist/newuselist --> delete it + if invFlag in flags or (file, line, invFlag, False) in newUseFlags[cpv] or (file, line, flag, True) in newUseFlags[cpv]: + if added: del newUseFlags[-1] # we currently added it as an extra option - delete it + added = True + jumpOut = False + for t in [(file, line, invFlag, False),(file, line, flag, True)]: + if t in newUseFlags[cpv]: + newUseFlags[cpv].remove(t) + jumpOut = True + break + if not jumpOut: newUseFlags[cpv].append((file, line, invFlag, True)) + break + + # we want to duplicate the flag --> ignore + elif flag in flags: + added = True # emulate adding + break + + # add as an extra flag + else: + if not added: newUseFlags[cpv].append((file, line, flag, False)) + added = True + + # create a new line + if not added: + path = USE_PATH + if USE_PATH_IS_DIR: + path = os.path.join(USE_PATH,"geneticone") + + try: + newUseFlags[cpv].remove((path, -1, invFlag, False)) + except ValueError: # not in UseFlags + newUseFlags[cpv].append((path, -1, flag, False)) + + newUseFlags[cpv] = unique_array(newUseFlags[cpv]) + debug("newUseFlags: "+str(newUseFlags)) + +def remove_new_use_flags (cpv): + """Removes all new use-flags for a specific package. + @param cpv: the package for which to remove the flags + @type cpv: string (cpv) or L{geneticone.Package}-object""" + if isinstance(cpv, geneticone.Package): + cpv = cpv.get_cpv() + + try: + del newUseFlags[cpv] + except KeyError: + pass + +def get_new_use_flags (cpv): + """Gets all the new use-flags for a specific package. + @param cpv: the package for which to remove the flags + @type cpv: string (cpv) or L{geneticone.Package}-object + @returns: list of flags + @rtype: list""" + + if isinstance(cpv, geneticone.Package): + cpv = cpv.get_cpv() + + list2return = [] + try: + for file, line, flag, remove in newUseFlags[cpv]: + if remove: + list2return.append(invert_use_flag(flag)) + else: + list2return.append(flag) + except KeyError: + pass + + return list2return + +def write_use_flags (): + """This writes our changed useflags into the file.""" + global newUseFlags, useFlags + + def insert (flag, list): + """Shortcut for inserting a new flag right after the package-name.""" + list.insert(1,flag) + + def remove (flag, list): + """Removes a flag.""" + try: + list.remove(flag) + except ValueError: # flag is given as flag\n + list.remove(flag+"\n") + list.append("\n") #re-insert the newline + + # no more flags there - comment it out + if len(list) == 1 or list[1][0] in ("#","\n"): + list[0] = "#"+list[0] + insert("#removed by geneticone#",list) + + file_cache = {} # cache for having to read the file only once: name->[lines] + for cpv in newUseFlags: + for file, line, flag, delete in newUseFlags[cpv]: + line = int(line) # it is saved as a string so far! + + # add new line + if line == -1: + msg = "\n#geneticone update#\n=%s %s\n" % (cpv, flag) + if not file in file_cache: + f = open(file, "a") + f.write(msg) + f.close() + else: + file_cache[file].append(msg) + # change a line + else: + if not file in file_cache: + # read file + f = open(file, "r") + lines = [] + i = 1 + while i < line: # stop at the given line + lines.append(f.readline()) + i = i+1 + l = f.readline().split(" ") + # delete or insert + if delete: + remove(flag,l) + else: + insert(flag,l) + lines.append(" ".join(l)) + + # read the rest + lines.extend(f.readlines()) + + file_cache[file] = lines + f.close() + else: # in cache + l = file_cache[file][line-1].split(" ") + if delete: + remove(flag,l) + else: + insert(flag,l) + file_cache[file][line-1] = " ".join(l) + + # write to disk + for file in file_cache.keys(): + f = open(file, "w") + f.writelines(file_cache[file]) + f.close() + # reset + useFlags = {} + newUseFlags = {} + +# +# +# NOTHING IS WORKING / IN USE BELOW THIS LINE +# +# +### MASKING PART ### +MASK_PATH = os.path.join(portage.USER_CONFIG_PATH,"package.mask") +UNMASK_PATH = os.path.join(portage.USER_CONFIG_PATH,"package.unmask") +MASK_PATH_IS_DIR = os.path.isdir(MASK_PATH) +UNMASK_PATH_IS_DIR = os.path.isdir(UNMASK_PATH) + +new_masked = {} +new_unmasked = {} + +def set_masked (pkg): + global new_masked, newunmasked + if not isinstance(pkg, geneticone.Package): + pkg = geneticone.Package(pkg) + + cpv = pkg.get_cpv() + + if not cpv in new_unmasked: + new_unmasked[cpv] = [] + if not cpv in new_masked: + new_masked[cpv] = [] + + nu = new_unmasked[cpv][:] + for file, line in nu: + if line == "-1": + new_unmasked[cpv].remove(file, line) + + nm = new_masked[cpv][:] + for file, line in nm: + if line != "-1": + new_masked[cpv].remove(file, line) + + if pkg.is_masked(): + return + + unmasked = get_data(pkg, UNMASK_PATH) + debug("data (unmasked): "+str(unmasked)) + done = False + for file, line, crit, flags in unmasked: + if pkg.matches(crit): + new_unmasked[cpv].append((file, line)) + done = True + + if done: return + + if MASK_PATH_IS_DIR: + file = os.path.join(MASK_PATH, "geneticone") + else: + file = MASK_PATH + + new_masked[cpv].append((file, "-1")) + new_masked[cpv] = unique_array(new_masked[cpv]) + debug("new_masked: "+str(new_masked)) + +def set_unmasked (pkg): + global new_masked, new_unmasked + if not isinstance(pkg, geneticone.Package): + pkg = geneticone.Package(pkg) + + cpv = pkg.get_cpv() + + if not cpv in new_unmasked: + new_unmasked[cpv] = [] + if not cpv in new_masked: + new_masked[cpv] = [] + + nu = new_unmasked[cpv][:] + for file, line in nu: + if line != "-1": + new_unmasked[cpv].remove(file, line) + + nm = new_masked[cpv][:] + for file, line in nm: + if line == "-1": + new_masked[cpv].remove(file, line) + + if not pkg.is_masked(): + return + + masked = get_data(pkg, MASK_PATH) + debug("data (masked): "+str(masked)) + done = False + for file, line, crit, fl in masked: + if pkg.matches(crit): + new_masked[cpv].append((file, line)) + done = True + + if done: return + + if UNMASK_PATH_IS_DIR: + file = os.path.join(UNMASK_PATH, "geneticone") + else: + file = UNMASK_PATH + + new_unmasked[cpv].append((file, "-1")) + new_unmasked[cpv] = unique_array(new_unmasked[cpv]) + debug("new_unmasked: "+str(new_unmasked)) + +def write_masked_unmasked (): + global new_unmasked, new_masked + file_cache = {} + + def write(cpv, file, line): + line = int(line) + # add new line + if line == -1: + msg = "\n#geneticone update#\n=%s\n" % cpv + if not file in file_cache: + f = open(file, "a") + f.write(msg) + f.close() + else: + file_cache[file].append(msg) + # change a line + else: + if not file in file_cache: + # read file + f = open(file, "r") + lines = [] + i = 1 + while i < line: # stop at the given line + lines.append(f.readline()) + i = i+1 + # delete + l = f.readline() + l = "#"+l[:-1]+" # removed by geneticone\n" + lines.append(l) + + # read the rest + lines.extend(f.readlines()) + + file_cache[file] = lines + f.close() + else: # in cache + l = file_cache[file][line-1] + # delete: + l = "#"+l[:-1]+" # removed by geneticone\n" + file_cache[file][line-1] = l + + + for cpv in new_masked: + for file, line in new_masked[cpv]: + write(cpv, file, line) + + for cpv in new_unmasked: + for file, line in new_unmasked[cpv]: + write(cpv, file, line) + + # write to disk + for file in file_cache.keys(): + f = open(file, "w") + f.writelines(file_cache[file]) + f.close() + # reset + new_masked = {} + new_unmasked = {} + +### TESTING PART ### +TESTING_PATH = os.path.join(portage.USER_CONFIG_PATH, "package.keywords") +TESTING_PATH_IS_DIR = os.path.isdir(TESTING_PATH) +newTesting = {} +arch = "" + +def set_testing (pkg, enable): + """Enables the package for installing when it is marked as testing (~ARCH). + @param pkg: the package + @type pkg: string (cpv) or L{geneticone.Package}-object + @param enable: controls whether to enable (True) or disable (False) for test-installing + @type enable: boolean""" + + global arch, newTesting + if not isinstance(pkg, geneticone.Package): + pkg = geneticone.Package(pkg) + + arch = pkg.get_settings("ARCH") + cpv = pkg.get_cpv() + if not cpv in newTesting: + newTesting[cpv] = [] + + debug("arch: "+arch) + for file, line in newTesting[cpv]: + if (enable and line != "-1") or (not enable and line == "-1"): + newTesting[cpv].remove((file, line)) + + if (enable and (pkg.get_mask_status() % 3 == 0)) or (not enable and (pkg.get_mask_status() % 3 != 0)): + return + + if not enable: + test = get_data(pkg, TESTING_PATH) + debug("data (test): "+str(test)) + for file, line, crit, flags in test: + if pkg.matches(crit) and flags[0] == "~"+arch: + newTesting[cpv].append((file, line)) + else: + if TESTING_PATH_IS_DIR: + file = os.path.join(TESTING_PATH, "geneticone") + else: + file = TESTING_PATH + newTesting[cpv].append((file, "-1")) + + newTesting[cpv] = unique_array(newTesting[cpv]) + debug("newTesting: "+str(newTesting)) + +def write_testing (): + global arch, newTesting + file_cache = {} + + for cpv in newTesting: + for file, line in newTesting[cpv]: + line = int(line) + # add new line + if line == -1: + msg = "\n#geneticone update#\n=%s ~%s\n" % (cpv, arch) + if not file in file_cache: + f = open(file, "a") + f.write(msg) + f.close() + else: + file_cache[file].append(msg) + # change a line + else: + if not file in file_cache: + # read file + f = open(file, "r") + lines = [] + i = 1 + while i < line: # stop at the given line + lines.append(f.readline()) + i = i+1 + # delete + l = f.readline() + l = "#"+l[:-1]+" # removed by geneticone\n" + lines.append(l) + + # read the rest + lines.extend(f.readlines()) + + file_cache[file] = lines + f.close() + else: # in cache + l = file_cache[file][line-1] + # delete: + l = "#"+l[:-1]+" # removed by geneticone\n" + file_cache[file][line-1] = l + + # write to disk + for file in file_cache.keys(): + f = open(file, "w") + f.writelines(file_cache[file]) + f.close() + # reset + newTesting = {} diff --git a/geneticone/backend/package.py b/geneticone/backend/package.py new file mode 100644 index 0000000..73355ed --- /dev/null +++ b/geneticone/backend/package.py @@ -0,0 +1,293 @@ +# +# File: geneticone/package.py +# This file is part of the Genetic/One-Project, a graphical portage-frontend. +# +# Copyright (C) 2006 Necoro d.M. +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by Necoro d.M. + +from geneticone import * +from geneticone import flags +import geneticone + +import gentoolkit +import portage +from portage_util import unique_array + +class Package (gentoolkit.Package): + """This is a subclass of the gentoolkit.Package-class which a lot of additional functionality we need in Genetic/One.""" + + def __init__ (self, cpv): + """Constructor. + + @param cpv: The cpv or gentoolkit.Package which describes the package to create. + @type cpv: string (cat/pkg-ver) or gentoolkit.Package-object.""" + + if isinstance(cpv, gentoolkit.Package): + cpv = cpv.get_cpv() + gentoolkit.Package.__init__(self, cpv) + + def get_mask_status(self): + """Gets the numeric mask status of a package. The return value can be translated as a string when taking the following list of modes: [ " ", " ~", " -", "M ", "M~", "M-" ] + + This method adapted from equery 0.1.4 + Original author: Karl Trygve Kalleberg + + @returns: mask status + @rtype: int""" + + 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_all_use_flags (self): + """Returns a list of _all_ useflags for this package, i.e. all useflags you can set for this package. + + @returns: list of use-flags + @rtype: list""" + + return unique_array(self.get_env_var("IUSE").split()) + + def get_installed_use_flags (self): + """Returns a list of the useflags enabled at installation time. If package is not installed, it returns an empty list. + + @returns: list of useflags enabled at installation time or an empty list + @rtype: list""" + if self.is_installed(): + uses = self.get_use_flags().split() + iuses = self.get_all_use_flags() + set = [] + for u in iuses: + if u in uses: + set.append(u) + return set + else: + return [] + + def get_new_use_flags (self): + """Returns a list of the new useflags, i.e. these flags which are not written to the portage-system yet. + + @returns: list of flags or [] + @rtype: list""" + return flags.get_new_use_flags(self) + + def get_actual_use_flags (self): + """This returns the result of installed_use_flags + new_use_flags. If the package is not installed, it returns only the new flags. + + @return: list of flags + @rtype: list""" + + if self.is_installed(): + i_flags = self.get_installed_use_flags() + for f in self.get_new_use_flags(): + if flags.invert_flag(f) in i_flags: + i_flags.remove(flags.invert_flag(f)) + elif f not in i_flags: + i_flags.append(f) + return i_flags + else: + return self.get_new_flags() + + def set_use_flag (self, flag): + """Set a use-flag. + + @param flag: the flag to set + @type flag: string""" + flags.set_use_flag(self, flag) + + def remove_new_use_flags (self): + """Remove all the new use-flags.""" + flags.remove_new_use_flags(self) + + def get_dep_packages (self): + """Returns a cpv-list of packages on which this package depends and which have not been installed yet. This does not check the dependencies in a recursive manner. + + @returns: list of cpvs on which the package depend + @rtype: list + @raises geneticone.BlockedException: when a package in the dependency-list is blocked by an installed one + @raises geneticone.PackageNotFoundException: when a package in the dependency list could not be found in the system + @raises geneticone.DependencyCalcError: when an error occured during executing portage.dep_check()""" + + dep_pkgs = [] # the package list + + # check whether we got use-flags which are not visible for portage yet + newUseFlags = self.get_new_use_flags() + actual = self.get_settings("USE").split() + if newUseFlags: + depUses = [] + for u in newUseFlags: + if u[0] == "-" and flags.invert_use_flag(u) in actual: + actual.remove(flags.invert_use_flag(u)) + elif u not in actual: + actual.append(u) + + # 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")+" "+self.get_env_var("PDEPEND"), vartree.dbapi, self._settings, myuse = actual) + + if not deps: # what is the difference to [1, []] ? + return [] + + if deps[0] == 0: # error + raise DependencyCalcError, deps[1] + + deps = deps[1] + + for dep in deps: + if dep[0] == '!': # blocking sth + 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 get_cp (self): + """Returns the cp-string. + @returns: category/package. + @rtype: string""" + return self.get_category()+"/"+self.get_name() + + def is_masked (self): + """Returns True if either masked by package.mask or by profile. + @returns: mask-status + @rtype: boolean""" + # 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 matches (self, criterion): + """This checks, whether this package matches a specific verisioning criterion - e.g.: "<=net-im/foobar-1.2". + @param criterion: the criterion to match against + @type criterion: string""" + if portage.match_from_list(criterion, [self.get_cpv()]) == []: + return False + else: + return True +# +# OBSOLETE DEPENDENCY-CALCULATION-METHODS - kept in the case the above ones do not work +# + + #def own_get_dep_packages (self, old_cpv_dict = {}): + # # XXX: after having finished this, i realized, that there is already a portage function -.- ; + # """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_installed_use_flags() + # 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_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 _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/backend/portage_helper.py b/geneticone/backend/portage_helper.py new file mode 100644 index 0000000..aab9426 --- /dev/null +++ b/geneticone/backend/portage_helper.py @@ -0,0 +1,154 @@ +# +# File: geneticone/portage_helper.py +# This file is part of the Genetic/One-Project, a graphical portage-frontend. +# +# Copyright (C) 2006 Necoro d.M. +# This is free software. You may redistribute copies of it under the terms of +# the GNU General Public License version 2. +# There is NO WARRANTY, to the extent permitted by law. +# +# Written by Necoro d.M. et.al. + +from geneticone import * +import geneticone + +import re +import os + +import gentoolkit +import portage +from portage_util import unique_array + +def find_lambda (name): + """Returns the function needed by all the find_all_*-functions. Returns None if no name is given. + @param name: name to build the function of + @type name: string + @returns: + 1. None if no name is given + 2. a lambda function + @rtype: function""" + if name != None: + return lambda x: re.match(".*"+name+".*",x) + else: + return lambda x: True + +def geneticize_list (list_of_packages): + """Convertes a list of gentoolkit.Packages into L{geneticone.Packages}. + @param list_of_packages: the list of packages + @type list_of_packages: list of gentoolkit.Packages + @returns: converted list + @rtype: list of geneticone.Packages""" + return [geneticone.Package(x) for x in list_of_packages] + +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) + +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/exceptions.py b/geneticone/exceptions.py deleted file mode 100644 index 5780de6..0000000 --- a/geneticone/exceptions.py +++ /dev/null @@ -1,22 +0,0 @@ -# -# File: geneticone/exceptions.py -# This file is part of the Genetic/One-Project, a graphical portage-frontend. -# -# Copyright (C) 2006 Necoro d.M. -# This is free software. You may redistribute copies of it under the terms of -# the GNU General Public License version 2. -# There is NO WARRANTY, to the extent permitted by law. -# -# Written by Necoro d.M. - -class BlockedException (Exception): - """An exception marking, that some package is blocking another one.""" - pass - -class PackageNotFoundException (Exception): - """An exception marking that a package could not be found.""" - pass - -class DependencyCalcError (Exception): - """An error occured during dependency calculation.""" - pass diff --git a/geneticone/flags.py b/geneticone/flags.py deleted file mode 100644 index 8899fc5..0000000 --- a/geneticone/flags.py +++ /dev/null @@ -1,525 +0,0 @@ -# -# File: geneticone/flags.py -# This file is part of the Genetic/One-Project, a graphical portage-frontend. -# -# Copyright (C) 2006 Necoro d.M. -# This is free software. You may redistribute copies of it under the terms of -# the GNU General Public License version 2. -# There is NO WARRANTY, to the extent permitted by law. -# -# Written by Necoro d.M. - -import os -import os.path -from subprocess import Popen, PIPE # needed for grep - -import geneticone -from helper import * -import portage -from portage_util import unique_array - -### GENERAL PART ### - -def grep (pkg, path): - """Grep runs "egrep" on a given path and looks for occurences of a given package. - @param pkg: the package - @type pkg: string (cpv) or L{geneticone.Package}-object - @param path: path to look in - @type path: string - - @returns: occurences of pkg in the format: "file:line-no:complete_line_found" - @rtype: string""" - - if not isinstance(pkg, geneticone.Package): - pkg = geneticone.Package(pkg) # assume it is a cpv or a gentoolkit.Package - - command = "egrep -x -n -r -H '^[<>!=~]{0,2}%s(-[0-9].*)?[[:space:]]?.*$' %s" - return Popen((command % (pkg.get_cp(), path)), shell = True, stdout = PIPE).communicate()[0].splitlines() - -def get_data(pkg, path): - """This splits up the data of L{grep} and builds tuples in the format (file,line,criterion,list_of_flags). - @param pkg: package to find - @type pkg: string (cpv) or L{geneticone.Package}-object - @param path: path to look in - @type path: string - - @returns: a list of tuples in the form (file,line,criterion,list_of_flags) - @rtype: list""" - - flags = [] - - # do grep - list = grep(pkg, path) - - for i in range(len(list)): - file, line, fl = tuple(list[i].split(":")) # get file, line and flag-list - fl = fl.split() - crit = fl[0] - fl = fl[1:] - # stop after first comment - for i in range(len(fl)): - if fl[i][0] == "#": #comment - stop here - fl = fl[:i] - break - flags.append((file,line,crit,fl)) - - return flags - -### USE FLAG PART ### -USE_PATH = os.path.join(portage.USER_CONFIG_PATH,"package.use") -USE_PATH_IS_DIR = os.path.isdir(USE_PATH) -useFlags = {} # useFlags in the file -newUseFlags = {} # useFlags as we want them to be: format: cpv -> [(file, line, useflag, (true if removed from list / false if added))] - -def invert_use_flag (flag): - """Invertes a flag. - - >>> invert_use_flag("foo") - -foo - >>> invert_use_flag("-bar") - bar - - @param flag: the flag - @type flag: string - @returns: inverted flag - @rtype: string - """ - if flag[0] == "-": - return flag[1:] - else: - return "-"+flag - -def set_use_flag (pkg, flag): - """Sets the useflag for a given package. - - @param pkg: the package - @type pkg: string (cpv) or L{geneticone.Package}-object - @param flag: the flag to set - @type flag: string""" - - global useFlags, newUseFlags - - if not isinstance(pkg, geneticone.Package): - pkg = geneticone.Package(pkg) # assume cpv or gentoolkit.Package - - cpv = pkg.get_cpv() - invFlag = invert_use_flag(flag) - - # if not saved in useFlags, get it by calling get_data() which calls grep() - data = None - if not cpv in useFlags: - data = get_data(pkg, USE_PATH) - useFlags[cpv] = data - else: - data = useFlags[cpv] - - if not cpv in newUseFlags: - newUseFlags[cpv] = [] - - debug("data: "+str(data)) - # add a useflag / delete one - added = False - for file, line, crit, flags in data: - if pkg.matches(crit): - # we have the inverted flag in the uselist/newuselist --> delete it - if invFlag in flags or (file, line, invFlag, False) in newUseFlags[cpv] or (file, line, flag, True) in newUseFlags[cpv]: - if added: del newUseFlags[-1] # we currently added it as an extra option - delete it - added = True - jumpOut = False - for t in [(file, line, invFlag, False),(file, line, flag, True)]: - if t in newUseFlags[cpv]: - newUseFlags[cpv].remove(t) - jumpOut = True - break - if not jumpOut: newUseFlags[cpv].append((file, line, invFlag, True)) - break - - # we want to duplicate the flag --> ignore - elif flag in flags: - added = True # emulate adding - break - - # add as an extra flag - else: - if not added: newUseFlags[cpv].append((file, line, flag, False)) - added = True - - # create a new line - if not added: - path = USE_PATH - if USE_PATH_IS_DIR: - path = os.path.join(USE_PATH,"geneticone") - - try: - newUseFlags[cpv].remove((path, -1, invFlag, False)) - except ValueError: # not in UseFlags - newUseFlags[cpv].append((path, -1, flag, False)) - - newUseFlags[cpv] = unique_array(newUseFlags[cpv]) - debug("newUseFlags: "+str(newUseFlags)) - -def remove_new_use_flags (cpv): - """Removes all new use-flags for a specific package. - @param cpv: the package for which to remove the flags - @type cpv: string (cpv) or L{geneticone.Package}-object""" - if isinstance(cpv, geneticone.Package): - cpv = cpv.get_cpv() - - try: - del newUseFlags[cpv] - except KeyError: - pass - -def get_new_use_flags (cpv): - """Gets all the new use-flags for a specific package. - @param cpv: the package for which to remove the flags - @type cpv: string (cpv) or L{geneticone.Package}-object - @returns: list of flags - @rtype: list""" - - if isinstance(cpv, geneticone.Package): - cpv = cpv.get_cpv() - - list2return = [] - try: - for file, line, flag, remove in newUseFlags[cpv]: - if remove: - list2return.append(invert_use_flag(flag)) - else: - list2return.append(flag) - except KeyError: - pass - - return list2return - -def write_use_flags (): - """This writes our changed useflags into the file.""" - global newUseFlags, useFlags - - def insert (flag, list): - """Shortcut for inserting a new flag right after the package-name.""" - list.insert(1,flag) - - def remove (flag, list): - """Removes a flag.""" - try: - list.remove(flag) - except ValueError: # flag is given as flag\n - list.remove(flag+"\n") - list.append("\n") #re-insert the newline - - # no more flags there - comment it out - if len(list) == 1 or list[1][0] in ("#","\n"): - list[0] = "#"+list[0] - insert("#removed by geneticone#",list) - - file_cache = {} # cache for having to read the file only once: name->[lines] - for cpv in newUseFlags: - for file, line, flag, delete in newUseFlags[cpv]: - line = int(line) # it is saved as a string so far! - - # add new line - if line == -1: - msg = "\n#geneticone update#\n=%s %s\n" % (cpv, flag) - if not file in file_cache: - f = open(file, "a") - f.write(msg) - f.close() - else: - file_cache[file].append(msg) - # change a line - else: - if not file in file_cache: - # read file - f = open(file, "r") - lines = [] - i = 1 - while i < line: # stop at the given line - lines.append(f.readline()) - i = i+1 - l = f.readline().split(" ") - # delete or insert - if delete: - remove(flag,l) - else: - insert(flag,l) - lines.append(" ".join(l)) - - # read the rest - lines.extend(f.readlines()) - - file_cache[file] = lines - f.close() - else: # in cache - l = file_cache[file][line-1].split(" ") - if delete: - remove(flag,l) - else: - insert(flag,l) - file_cache[file][line-1] = " ".join(l) - - # write to disk - for file in file_cache.keys(): - f = open(file, "w") - f.writelines(file_cache[file]) - f.close() - # reset - useFlags = {} - newUseFlags = {} - -# -# -# NOTHING IS WORKING / IN USE BELOW THIS LINE -# -# -### MASKING PART ### -MASK_PATH = os.path.join(portage.USER_CONFIG_PATH,"package.mask") -UNMASK_PATH = os.path.join(portage.USER_CONFIG_PATH,"package.unmask") -MASK_PATH_IS_DIR = os.path.isdir(MASK_PATH) -UNMASK_PATH_IS_DIR = os.path.isdir(UNMASK_PATH) - -new_masked = {} -new_unmasked = {} - -def set_masked (pkg): - global new_masked, newunmasked - if not isinstance(pkg, geneticone.Package): - pkg = geneticone.Package(pkg) - - cpv = pkg.get_cpv() - - if not cpv in new_unmasked: - new_unmasked[cpv] = [] - if not cpv in new_masked: - new_masked[cpv] = [] - - nu = new_unmasked[cpv][:] - for file, line in nu: - if line == "-1": - new_unmasked[cpv].remove(file, line) - - nm = new_masked[cpv][:] - for file, line in nm: - if line != "-1": - new_masked[cpv].remove(file, line) - - if pkg.is_masked(): - return - - unmasked = get_data(pkg, UNMASK_PATH) - debug("data (unmasked): "+str(unmasked)) - done = False - for file, line, crit, flags in unmasked: - if pkg.matches(crit): - new_unmasked[cpv].append((file, line)) - done = True - - if done: return - - if MASK_PATH_IS_DIR: - file = os.path.join(MASK_PATH, "geneticone") - else: - file = MASK_PATH - - new_masked[cpv].append((file, "-1")) - new_masked[cpv] = unique_array(new_masked[cpv]) - debug("new_masked: "+str(new_masked)) - -def set_unmasked (pkg): - global new_masked, new_unmasked - if not isinstance(pkg, geneticone.Package): - pkg = geneticone.Package(pkg) - - cpv = pkg.get_cpv() - - if not cpv in new_unmasked: - new_unmasked[cpv] = [] - if not cpv in new_masked: - new_masked[cpv] = [] - - nu = new_unmasked[cpv][:] - for file, line in nu: - if line != "-1": - new_unmasked[cpv].remove(file, line) - - nm = new_masked[cpv][:] - for file, line in nm: - if line == "-1": - new_masked[cpv].remove(file, line) - - if not pkg.is_masked(): - return - - masked = get_data(pkg, MASK_PATH) - debug("data (masked): "+str(masked)) - done = False - for file, line, crit, fl in masked: - if pkg.matches(crit): - new_masked[cpv].append((file, line)) - done = True - - if done: return - - if UNMASK_PATH_IS_DIR: - file = os.path.join(UNMASK_PATH, "geneticone") - else: - file = UNMASK_PATH - - new_unmasked[cpv].append((file, "-1")) - new_unmasked[cpv] = unique_array(new_unmasked[cpv]) - debug("new_unmasked: "+str(new_unmasked)) - -def write_masked_unmasked (): - global new_unmasked, new_masked - file_cache = {} - - def write(cpv, file, line): - line = int(line) - # add new line - if line == -1: - msg = "\n#geneticone update#\n=%s\n" % cpv - if not file in file_cache: - f = open(file, "a") - f.write(msg) - f.close() - else: - file_cache[file].append(msg) - # change a line - else: - if not file in file_cache: - # read file - f = open(file, "r") - lines = [] - i = 1 - while i < line: # stop at the given line - lines.append(f.readline()) - i = i+1 - # delete - l = f.readline() - l = "#"+l[:-1]+" # removed by geneticone\n" - lines.append(l) - - # read the rest - lines.extend(f.readlines()) - - file_cache[file] = lines - f.close() - else: # in cache - l = file_cache[file][line-1] - # delete: - l = "#"+l[:-1]+" # removed by geneticone\n" - file_cache[file][line-1] = l - - - for cpv in new_masked: - for file, line in new_masked[cpv]: - write(cpv, file, line) - - for cpv in new_unmasked: - for file, line in new_unmasked[cpv]: - write(cpv, file, line) - - # write to disk - for file in file_cache.keys(): - f = open(file, "w") - f.writelines(file_cache[file]) - f.close() - # reset - new_masked = {} - new_unmasked = {} - -### TESTING PART ### -TESTING_PATH = os.path.join(portage.USER_CONFIG_PATH, "package.keywords") -TESTING_PATH_IS_DIR = os.path.isdir(TESTING_PATH) -newTesting = {} -arch = "" - -def set_testing (pkg, enable): - """Enables the package for installing when it is marked as testing (~ARCH). - @param pkg: the package - @type pkg: string (cpv) or L{geneticone.Package}-object - @param enable: controls whether to enable (True) or disable (False) for test-installing - @type enable: boolean""" - - global arch, newTesting - if not isinstance(pkg, geneticone.Package): - pkg = geneticone.Package(pkg) - - arch = pkg.get_settings("ARCH") - cpv = pkg.get_cpv() - if not cpv in newTesting: - newTesting[cpv] = [] - - debug("arch: "+arch) - for file, line in newTesting[cpv]: - if (enable and line != "-1") or (not enable and line == "-1"): - newTesting[cpv].remove((file, line)) - - if (enable and (pkg.get_mask_status() % 3 == 0)) or (not enable and (pkg.get_mask_status() % 3 != 0)): - return - - if not enable: - test = get_data(pkg, TESTING_PATH) - debug("data (test): "+str(test)) - for file, line, crit, flags in test: - if pkg.matches(crit) and flags[0] == "~"+arch: - newTesting[cpv].append((file, line)) - else: - if TESTING_PATH_IS_DIR: - file = os.path.join(TESTING_PATH, "geneticone") - else: - file = TESTING_PATH - newTesting[cpv].append((file, "-1")) - - newTesting[cpv] = unique_array(newTesting[cpv]) - debug("newTesting: "+str(newTesting)) - -def write_testing (): - global arch, newTesting - file_cache = {} - - for cpv in newTesting: - for file, line in newTesting[cpv]: - line = int(line) - # add new line - if line == -1: - msg = "\n#geneticone update#\n=%s ~%s\n" % (cpv, arch) - if not file in file_cache: - f = open(file, "a") - f.write(msg) - f.close() - else: - file_cache[file].append(msg) - # change a line - else: - if not file in file_cache: - # read file - f = open(file, "r") - lines = [] - i = 1 - while i < line: # stop at the given line - lines.append(f.readline()) - i = i+1 - # delete - l = f.readline() - l = "#"+l[:-1]+" # removed by geneticone\n" - lines.append(l) - - # read the rest - lines.extend(f.readlines()) - - file_cache[file] = lines - f.close() - else: # in cache - l = file_cache[file][line-1] - # delete: - l = "#"+l[:-1]+" # removed by geneticone\n" - file_cache[file][line-1] = l - - # write to disk - for file in file_cache.keys(): - f = open(file, "w") - f.writelines(file_cache[file]) - f.close() - # reset - newTesting = {} diff --git a/geneticone/package.py b/geneticone/package.py deleted file mode 100644 index 73355ed..0000000 --- a/geneticone/package.py +++ /dev/null @@ -1,293 +0,0 @@ -# -# File: geneticone/package.py -# This file is part of the Genetic/One-Project, a graphical portage-frontend. -# -# Copyright (C) 2006 Necoro d.M. -# This is free software. You may redistribute copies of it under the terms of -# the GNU General Public License version 2. -# There is NO WARRANTY, to the extent permitted by law. -# -# Written by Necoro d.M. - -from geneticone import * -from geneticone import flags -import geneticone - -import gentoolkit -import portage -from portage_util import unique_array - -class Package (gentoolkit.Package): - """This is a subclass of the gentoolkit.Package-class which a lot of additional functionality we need in Genetic/One.""" - - def __init__ (self, cpv): - """Constructor. - - @param cpv: The cpv or gentoolkit.Package which describes the package to create. - @type cpv: string (cat/pkg-ver) or gentoolkit.Package-object.""" - - if isinstance(cpv, gentoolkit.Package): - cpv = cpv.get_cpv() - gentoolkit.Package.__init__(self, cpv) - - def get_mask_status(self): - """Gets the numeric mask status of a package. The return value can be translated as a string when taking the following list of modes: [ " ", " ~", " -", "M ", "M~", "M-" ] - - This method adapted from equery 0.1.4 - Original author: Karl Trygve Kalleberg - - @returns: mask status - @rtype: int""" - - 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_all_use_flags (self): - """Returns a list of _all_ useflags for this package, i.e. all useflags you can set for this package. - - @returns: list of use-flags - @rtype: list""" - - return unique_array(self.get_env_var("IUSE").split()) - - def get_installed_use_flags (self): - """Returns a list of the useflags enabled at installation time. If package is not installed, it returns an empty list. - - @returns: list of useflags enabled at installation time or an empty list - @rtype: list""" - if self.is_installed(): - uses = self.get_use_flags().split() - iuses = self.get_all_use_flags() - set = [] - for u in iuses: - if u in uses: - set.append(u) - return set - else: - return [] - - def get_new_use_flags (self): - """Returns a list of the new useflags, i.e. these flags which are not written to the portage-system yet. - - @returns: list of flags or [] - @rtype: list""" - return flags.get_new_use_flags(self) - - def get_actual_use_flags (self): - """This returns the result of installed_use_flags + new_use_flags. If the package is not installed, it returns only the new flags. - - @return: list of flags - @rtype: list""" - - if self.is_installed(): - i_flags = self.get_installed_use_flags() - for f in self.get_new_use_flags(): - if flags.invert_flag(f) in i_flags: - i_flags.remove(flags.invert_flag(f)) - elif f not in i_flags: - i_flags.append(f) - return i_flags - else: - return self.get_new_flags() - - def set_use_flag (self, flag): - """Set a use-flag. - - @param flag: the flag to set - @type flag: string""" - flags.set_use_flag(self, flag) - - def remove_new_use_flags (self): - """Remove all the new use-flags.""" - flags.remove_new_use_flags(self) - - def get_dep_packages (self): - """Returns a cpv-list of packages on which this package depends and which have not been installed yet. This does not check the dependencies in a recursive manner. - - @returns: list of cpvs on which the package depend - @rtype: list - @raises geneticone.BlockedException: when a package in the dependency-list is blocked by an installed one - @raises geneticone.PackageNotFoundException: when a package in the dependency list could not be found in the system - @raises geneticone.DependencyCalcError: when an error occured during executing portage.dep_check()""" - - dep_pkgs = [] # the package list - - # check whether we got use-flags which are not visible for portage yet - newUseFlags = self.get_new_use_flags() - actual = self.get_settings("USE").split() - if newUseFlags: - depUses = [] - for u in newUseFlags: - if u[0] == "-" and flags.invert_use_flag(u) in actual: - actual.remove(flags.invert_use_flag(u)) - elif u not in actual: - actual.append(u) - - # 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")+" "+self.get_env_var("PDEPEND"), vartree.dbapi, self._settings, myuse = actual) - - if not deps: # what is the difference to [1, []] ? - return [] - - if deps[0] == 0: # error - raise DependencyCalcError, deps[1] - - deps = deps[1] - - for dep in deps: - if dep[0] == '!': # blocking sth - 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 get_cp (self): - """Returns the cp-string. - @returns: category/package. - @rtype: string""" - return self.get_category()+"/"+self.get_name() - - def is_masked (self): - """Returns True if either masked by package.mask or by profile. - @returns: mask-status - @rtype: boolean""" - # 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 matches (self, criterion): - """This checks, whether this package matches a specific verisioning criterion - e.g.: "<=net-im/foobar-1.2". - @param criterion: the criterion to match against - @type criterion: string""" - if portage.match_from_list(criterion, [self.get_cpv()]) == []: - return False - else: - return True -# -# OBSOLETE DEPENDENCY-CALCULATION-METHODS - kept in the case the above ones do not work -# - - #def own_get_dep_packages (self, old_cpv_dict = {}): - # # XXX: after having finished this, i realized, that there is already a portage function -.- ; - # """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_installed_use_flags() - # 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_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 _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/portage_helper.py b/geneticone/portage_helper.py deleted file mode 100644 index aab9426..0000000 --- a/geneticone/portage_helper.py +++ /dev/null @@ -1,154 +0,0 @@ -# -# File: geneticone/portage_helper.py -# This file is part of the Genetic/One-Project, a graphical portage-frontend. -# -# Copyright (C) 2006 Necoro d.M. -# This is free software. You may redistribute copies of it under the terms of -# the GNU General Public License version 2. -# There is NO WARRANTY, to the extent permitted by law. -# -# Written by Necoro d.M. et.al. - -from geneticone import * -import geneticone - -import re -import os - -import gentoolkit -import portage -from portage_util import unique_array - -def find_lambda (name): - """Returns the function needed by all the find_all_*-functions. Returns None if no name is given. - @param name: name to build the function of - @type name: string - @returns: - 1. None if no name is given - 2. a lambda function - @rtype: function""" - if name != None: - return lambda x: re.match(".*"+name+".*",x) - else: - return lambda x: True - -def geneticize_list (list_of_packages): - """Convertes a list of gentoolkit.Packages into L{geneticone.Packages}. - @param list_of_packages: the list of packages - @type list_of_packages: list of gentoolkit.Packages - @returns: converted list - @rtype: list of geneticone.Packages""" - return [geneticone.Package(x) for x in list_of_packages] - -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) - -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 -- cgit v1.2.3-70-g09d2