From afa1de13f0576ace6dcbb0176490fd20922950cd Mon Sep 17 00:00:00 2001 From: René 'Necoro' Neumann Date: Tue, 2 Sep 2008 13:01:17 +0200 Subject: Switch from tabs to 4 spaces --- portato/backend/__init__.py | 64 +- portato/backend/exceptions.py | 16 +- portato/backend/flags.py | 1308 ++++++++++++++++---------------- portato/backend/package.py | 786 +++++++++---------- portato/backend/portage/__init__.py | 8 +- portato/backend/portage/package.py | 572 +++++++------- portato/backend/portage/package_22.py | 10 +- portato/backend/portage/sets.py | 168 ++-- portato/backend/portage/settings.py | 78 +- portato/backend/portage/settings_22.py | 12 +- portato/backend/portage/system.py | 768 +++++++++---------- portato/backend/portage/system_22.py | 60 +- portato/backend/system_interface.py | 492 ++++++------ 13 files changed, 2171 insertions(+), 2171 deletions(-) (limited to 'portato/backend') diff --git a/portato/backend/__init__.py b/portato/backend/__init__.py index b2a5a43..1f62d6b 100644 --- a/portato/backend/__init__.py +++ b/portato/backend/__init__.py @@ -20,52 +20,52 @@ SYSTEM = "portage" # the name of the current system _sys = None # the SystemInterface-instance class _Package (object): - """Wrapping class from which L{portato.backend.Package} inherits. This is used by the flags module to check - whether an object is a package. It cannot use the normal Package class as this results in cyclic dependencies.""" + """Wrapping class from which L{portato.backend.Package} inherits. This is used by the flags module to check + whether an object is a package. It cannot use the normal Package class as this results in cyclic dependencies.""" - def __init__ (self): - raise TypeError, "Calling __init__ on portato.backend._Package objects is not allowed." + def __init__ (self): + raise TypeError, "Calling __init__ on portato.backend._Package objects is not allowed." class SystemWrapper (SystemInterface): - """This is a wrapper to the different system interfaces, allowing the direct import via C{from portato.backend import system}. - With this wrapper a change of the system is propagated to all imports.""" - - def __getattribute__ (self, name): - """Just pass all attribute accesses directly to _sys.""" - return getattr(_sys, name) + """This is a wrapper to the different system interfaces, allowing the direct import via C{from portato.backend import system}. + With this wrapper a change of the system is propagated to all imports.""" + + def __getattribute__ (self, name): + """Just pass all attribute accesses directly to _sys.""" + return getattr(_sys, name) def set_system (new_sys): - """Sets the current system to a new one. + """Sets the current system to a new one. - @param new_sys: the name of the system to take - @type new_sys: string""" + @param new_sys: the name of the system to take + @type new_sys: string""" - global SYSTEM - if new_sys != SYSTEM: - SYSTEM = new_sys - load_system() + global SYSTEM + if new_sys != SYSTEM: + SYSTEM = new_sys + load_system() def load_system (): - """Loads the current chosen system. + """Loads the current chosen system. - @raises InvalidSystemError: if an inappropriate system is set""" - - global _sys + @raises InvalidSystemError: if an inappropriate system is set""" + + global _sys - if SYSTEM == "portage": - debug("Setting Portage System") - from .portage import PortageSystem - _sys = PortageSystem () - elif SYSTEM == "catapult": - debug("Setting Catapult System") - from .catapult import CatapultSystem - _sys = CatapultSystem() - else: - raise InvalidSystemError, SYSTEM + if SYSTEM == "portage": + debug("Setting Portage System") + from .portage import PortageSystem + _sys = PortageSystem () + elif SYSTEM == "catapult": + debug("Setting Catapult System") + from .catapult import CatapultSystem + _sys = CatapultSystem() + else: + raise InvalidSystemError, SYSTEM system = SystemWrapper() def is_package(what): - return isinstance(what, _Package) + return isinstance(what, _Package) load_system() diff --git a/portato/backend/exceptions.py b/portato/backend/exceptions.py index 42f9d44..37e9bda 100644 --- a/portato/backend/exceptions.py +++ b/portato/backend/exceptions.py @@ -11,17 +11,17 @@ # Written by René 'Necoro' Neumann class BlockedException (Exception): - """An exception marking, that some package is blocking another one.""" - pass + """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 + """An exception marking that a package could not be found.""" + pass class DependencyCalcError (Exception): - """An error occured during dependency calculation.""" - pass + """An error occured during dependency calculation.""" + pass class InvalidSystemError (Exception): - """An invalid system is set.""" - pass + """An invalid system is set.""" + pass diff --git a/portato/backend/flags.py b/portato/backend/flags.py index b151665..4aa6b8e 100644 --- a/portato/backend/flags.py +++ b/portato/backend/flags.py @@ -20,738 +20,738 @@ from . import system, is_package from ..helper import debug, error, unique_array CONFIG = { - "usefile" : "portato", - "maskfile" : "portato", - "testingfile" : "portato", - "usePerVersion" : True, - "maskPerVersion" : True, - "testingPerVersion" : True - } + "usefile" : "portato", + "maskfile" : "portato", + "testingfile" : "portato", + "usePerVersion" : True, + "maskPerVersion" : True, + "testingPerVersion" : True + } class Constants: - def __init__ (self): - self.clear() - - def clear (self): - self._use_path = None - self._mask_path = None - self._unmask_path = None - self._testing_path = None - self._use_path_is_dir = None - self._mask_path_is_dir = None - self._unmask_path_is_dir = None - self._testing_path_is_dir = None + def __init__ (self): + self.clear() + + def clear (self): + self._use_path = None + self._mask_path = None + self._unmask_path = None + self._testing_path = None + self._use_path_is_dir = None + self._mask_path_is_dir = None + self._unmask_path_is_dir = None + self._testing_path_is_dir = None - def __get (self, name, path): - if self.__dict__[name] is None: - self.__dict__[name] = os.path.join(system.get_config_path(), path) + def __get (self, name, path): + if self.__dict__[name] is None: + self.__dict__[name] = os.path.join(system.get_config_path(), path) - return self.__dict__[name] + return self.__dict__[name] - def __is_dir(self, path): - name = "_" + path + "_is_dir" - if self.__dict__[name] is None: - self.__dict__[name] = os.path.isdir(self.__class__.__dict__[path](self)) - return self.__dict__[name] - - def use_path (self): - return self.__get("_use_path", "package.use") + def __is_dir(self, path): + name = "_" + path + "_is_dir" + if self.__dict__[name] is None: + self.__dict__[name] = os.path.isdir(self.__class__.__dict__[path](self)) + return self.__dict__[name] + + def use_path (self): + return self.__get("_use_path", "package.use") - def use_path_is_dir (self): - return self.__is_dir("use_path") + def use_path_is_dir (self): + return self.__is_dir("use_path") - def mask_path (self): - return self.__get("_mask_path", "package.mask") + def mask_path (self): + return self.__get("_mask_path", "package.mask") - def mask_path_is_dir (self): - return self.__is_dir("mask_path") + def mask_path_is_dir (self): + return self.__is_dir("mask_path") - def unmask_path (self): - return self.__get("_unmask_path", "package.unmask") + def unmask_path (self): + return self.__get("_unmask_path", "package.unmask") - def unmask_path_is_dir (self): - return self.__is_dir("unmask_path") + def unmask_path_is_dir (self): + return self.__is_dir("unmask_path") - def testing_path (self): - return self.__get("_testing_path", "package.keywords") + def testing_path (self): + return self.__get("_testing_path", "package.keywords") - def testing_path_is_dir (self): - return self.__is_dir("testing_path") + def testing_path_is_dir (self): + return self.__is_dir("testing_path") CONST = Constants() ### 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{backend.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 is_package(pkg): - pkg = system.new_package(pkg) # assume it is a cpv or a gentoolkit.Package - - if os.path.exists(path): - command = "egrep -x -n -r -H '^[<>!=~]{0,2}%s(-[0-9].*)?[[:space:]]?.*$' %s" # %s is replaced in the next line ;) - return Popen((command % (pkg.get_cp(), path)), shell = True, stdout = PIPE).communicate()[0].splitlines() - else: - return [] + """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{backend.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 is_package(pkg): + pkg = system.new_package(pkg) # assume it is a cpv or a gentoolkit.Package + + if os.path.exists(path): + command = "egrep -x -n -r -H '^[<>!=~]{0,2}%s(-[0-9].*)?[[:space:]]?.*$' %s" # %s is replaced in the next line ;) + return Popen((command % (pkg.get_cp(), path)), shell = True, stdout = PIPE).communicate()[0].splitlines() + else: + return [] 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{backend.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: (string,string,string,string[])[]""" - - 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 j in range(len(fl)): - if fl[j][0] == "#": # comment - stop here - fl = fl[:j] - break - flags.append((file,line,crit,fl)) - - return flags + """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{backend.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: (string,string,string,string[])[]""" + + 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 j in range(len(fl)): + if fl[j][0] == "#": # comment - stop here + fl = fl[:j] + break + flags.append((file,line,crit,fl)) + + return flags def set_config (cfg): - """This function sets the CONFIG-variable for the whole module. Use this instead of modifying L{CONFIG} directly. - @param cfg: a dictionary with at least all the keys of the CONFIG-var - @type cfg: dict - @raises KeyError: if a keyword is missing in the new cfg""" + """This function sets the CONFIG-variable for the whole module. Use this instead of modifying L{CONFIG} directly. + @param cfg: a dictionary with at least all the keys of the CONFIG-var + @type cfg: dict + @raises KeyError: if a keyword is missing in the new cfg""" - for i in CONFIG.keys(): - if not i in cfg: - raise KeyError, "Missing keyword in config: "+i + for i in CONFIG.keys(): + if not i in cfg: + raise KeyError, "Missing keyword in config: "+i - for i in CONFIG: - CONFIG[i] = cfg[i] + for i in CONFIG: + CONFIG[i] = cfg[i] def generate_path (cpv, exp): - """Generates the correct path out of given wildcards. - These wildcards can be: - - $(cat) : category - - $(cat-1): first part of the category (e.g. "app") - - $(cat-2): second part of the category - - $(pkg) : name of the package - - $(version) : version of the package - - @param cpv: the cpv of the current package - @type cpv: string (cat/pkg-ver) - @param exp: the expression to render the path from - @type exp: string - @returns: rendered path - @rtype string""" - - if exp.find("$(") != -1: - cat, pkg, ver, rev = system.split_cpv(cpv) - if rev != "r0": - ver = "%s-%s" % (ver, rev) - exp = exp.replace("$(cat)",cat).\ - replace("$(pkg)",pkg).\ - replace("$(cat-1)",cat.split("-")[0]).\ - replace("$(cat-2)",cat.split("-")[1]).\ - replace("$(version)",ver) - return exp + """Generates the correct path out of given wildcards. + These wildcards can be: + - $(cat) : category + - $(cat-1): first part of the category (e.g. "app") + - $(cat-2): second part of the category + - $(pkg) : name of the package + - $(version) : version of the package + + @param cpv: the cpv of the current package + @type cpv: string (cat/pkg-ver) + @param exp: the expression to render the path from + @type exp: string + @returns: rendered path + @rtype string""" + + if exp.find("$(") != -1: + cat, pkg, ver, rev = system.split_cpv(cpv) + if rev != "r0": + ver = "%s-%s" % (ver, rev) + exp = exp.replace("$(cat)",cat).\ + replace("$(pkg)",pkg).\ + replace("$(cat-1)",cat.split("-")[0]).\ + replace("$(cat-2)",cat.split("-")[1]).\ + replace("$(version)",ver) + return exp ### USE FLAG PART ### 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 + """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 sort_use_flag_list (flaglist): - """ - Sorts a list of useflags. If a use flag starts with "+" or "-" this one is ignored for the matter of sorting. - This functions sorts the list itself - thus does not create a new one. But for convenience it returns the list too. - - @param flaglist: the list of useflags - @type flaglist: string[] - - @returns: the sorted list (Note: it is the same as the one passed in) - @rtype: string[] - """ - - def flag_key (flag): - if flag.startswith(("+","-")): - return flag[1:] - else: - return flag - - flaglist.sort(key = flag_key) - return flaglist + """ + Sorts a list of useflags. If a use flag starts with "+" or "-" this one is ignored for the matter of sorting. + This functions sorts the list itself - thus does not create a new one. But for convenience it returns the list too. + + @param flaglist: the list of useflags + @type flaglist: string[] + + @returns: the sorted list (Note: it is the same as the one passed in) + @rtype: string[] + """ + + def flag_key (flag): + if flag.startswith(("+","-")): + return flag[1:] + else: + return flag + + flaglist.sort(key = flag_key) + return flaglist def filter_defaults (flaglist): - """ - Removes "+" and "-" from IUSE defaults. + """ + Removes "+" and "-" from IUSE defaults. - @param flaglist: the list of useflags - @type flaglist: string + @param flaglist: the list of useflags + @type flaglist: string - @returns: the "cleaned" list - @rtype: string - """ + @returns: the "cleaned" list + @rtype: string + """ - for flag in flaglist: - if flag.startswith(("+","-")): - yield flag[1:] - else: - yield flag + for flag in flaglist: + if flag.startswith(("+","-")): + yield flag[1:] + else: + yield flag def set_use_flag (pkg, flag): - """Sets the useflag for a given package. - - @param pkg: the package - @type pkg: string (cpv) or L{backend.Package}-object - @param flag: the flag to set - @type flag: string""" - - global useFlags, newUseFlags - - if not is_package(pkg): - pkg = system.new_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, CONST.use_path()) - useFlags[cpv] = data - else: - data = useFlags[cpv] - - if not cpv in newUseFlags: - newUseFlags[cpv] = [] - - debug("data: %s", 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 # don't break as both cases can be valid (see below) - if not jumpOut: - newUseFlags[cpv].append((file, line, invFlag, True)) - - # we removed the inverted from package.use - but it is still enabled somewhere else - # so set it explicitly here - if invFlag in pkg.get_actual_use_flags(): - newUseFlags[cpv].append((file, line, flag, False)) - 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 = CONST.use_path() - if CONST.use_path_is_dir(): - path = os.path.join(CONST.use_path(), generate_path(cpv, CONFIG["usefile"])) - 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: %s", str(newUseFlags)) + """Sets the useflag for a given package. + + @param pkg: the package + @type pkg: string (cpv) or L{backend.Package}-object + @param flag: the flag to set + @type flag: string""" + + global useFlags, newUseFlags + + if not is_package(pkg): + pkg = system.new_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, CONST.use_path()) + useFlags[cpv] = data + else: + data = useFlags[cpv] + + if not cpv in newUseFlags: + newUseFlags[cpv] = [] + + debug("data: %s", 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 # don't break as both cases can be valid (see below) + if not jumpOut: + newUseFlags[cpv].append((file, line, invFlag, True)) + + # we removed the inverted from package.use - but it is still enabled somewhere else + # so set it explicitly here + if invFlag in pkg.get_actual_use_flags(): + newUseFlags[cpv].append((file, line, flag, False)) + 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 = CONST.use_path() + if CONST.use_path_is_dir(): + path = os.path.join(CONST.use_path(), generate_path(cpv, CONFIG["usefile"])) + 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: %s", 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{backend.Package}-object""" - - if is_package(cpv): - cpv = cpv.get_cpv() - - try: - del newUseFlags[cpv] - except KeyError: - pass + """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{backend.Package}-object""" + + if is_package(cpv): + 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 from which to get the flags - @type cpv: string (cpv) or L{backend.Package}-object - @returns: list of flags - @rtype: string[]""" - - if is_package(cpv): - cpv = cpv.get_cpv() - - list2return = set() - try: - for file, line, flag, remove in newUseFlags[cpv]: - if remove: - list2return.add("~"+invert_use_flag(flag)) - else: - list2return.add(flag) - except KeyError: - pass - - return list(list2return) + """Gets all the new use-flags for a specific package. + + @param cpv: the package from which to get the flags + @type cpv: string (cpv) or L{backend.Package}-object + @returns: list of flags + @rtype: string[]""" + + if is_package(cpv): + cpv = cpv.get_cpv() + + list2return = set() + try: + for file, line, flag, remove in newUseFlags[cpv]: + if remove: + list2return.add("~"+invert_use_flag(flag)) + else: + list2return.add(flag) + except KeyError: + pass + + return list(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 portato#",list) - - file_cache = {} # cache for having to read the file only once: name->[lines] - for cpv in newUseFlags: - flagsToAdd = [] # this is used for collecting the flags to be inserted in a _new_ line - - newUseFlags[cpv].sort(key = lambda x: x[3]) # now the flags are sorted in a manner, that removal comes after appending - - 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: - flagsToAdd.append(flag) - # change a line - else: - if not file in file_cache: - # read file - with open(file, "r") as f: - lines = [] - i = 1 - while i < line: # stop at the given line - lines.append(f.readline()) - 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 - - 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) - - if flagsToAdd: - # write new lines - msg = "\n#portato update#\n" - if CONFIG["usePerVersion"]: # add on a per-version-base - msg += "=%s %s\n" % (cpv, ' '.join(flagsToAdd)) - else: # add on a per-package-base - list = system.split_cpv(cpv) - msg += "%s/%s %s\n" % (list[0], list[1], ' '.join(flagsToAdd)) - if not file in file_cache: - f = open(file, "a") - f.write(msg) - f.close() - else: - file_cache[file].append(msg) - - # write to disk - for file in file_cache.keys(): - f = open(file, "w") - f.writelines(file_cache[file]) - f.close() - # reset - useFlags = {} - newUseFlags = {} - system.reload_settings() + """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 portato#",list) + + file_cache = {} # cache for having to read the file only once: name->[lines] + for cpv in newUseFlags: + flagsToAdd = [] # this is used for collecting the flags to be inserted in a _new_ line + + newUseFlags[cpv].sort(key = lambda x: x[3]) # now the flags are sorted in a manner, that removal comes after appending + + 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: + flagsToAdd.append(flag) + # change a line + else: + if not file in file_cache: + # read file + with open(file, "r") as f: + lines = [] + i = 1 + while i < line: # stop at the given line + lines.append(f.readline()) + 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 + + 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) + + if flagsToAdd: + # write new lines + msg = "\n#portato update#\n" + if CONFIG["usePerVersion"]: # add on a per-version-base + msg += "=%s %s\n" % (cpv, ' '.join(flagsToAdd)) + else: # add on a per-package-base + list = system.split_cpv(cpv) + msg += "%s/%s %s\n" % (list[0], list[1], ' '.join(flagsToAdd)) + if not file in file_cache: + f = open(file, "a") + f.write(msg) + f.close() + else: + file_cache[file].append(msg) + + # write to disk + for file in file_cache.keys(): + f = open(file, "w") + f.writelines(file_cache[file]) + f.close() + # reset + useFlags = {} + newUseFlags = {} + system.reload_settings() ### MASKING PART ### new_masked = {} new_unmasked = {} def set_masked (pkg, masked = True): - """Sets the masking status of the package. - - @param pkg: the package from which to get the flags - @type pkg: string (cpv) or L{backend.Package}-object - @param masked: if True: mask it; if False: unmask it - @type masked: boolean""" - - global new_masked, newunmasked - - if not is_package(pkg): - pkg = system.new_package(pkg) - - cpv = pkg.get_cpv() - - if not cpv in new_unmasked: - new_unmasked[cpv] = [] - if not cpv in new_masked: - new_masked[cpv] = [] - - if masked: - link_neq = new_masked - link_eq = new_unmasked - path = CONST.unmask_path() - else: - link_neq = new_unmasked - link_eq = new_masked - path = CONST.mask_path() - - copy = link_eq[cpv][:] - for file, line in copy: - if line == "-1": - link_eq[cpv].remove((file, line)) - - copy = link_neq[cpv][:] - for file, line in copy: - if line != "-1": - link_neq[cpv].remove((file, line)) - - if masked == pkg.is_masked(): - return - - data = get_data(pkg, path) - debug("data: %s", str(data)) - done = False - for file, line, crit, flags in data: - if pkg.matches(crit): - link_eq[cpv].append((file, line)) - done = True - - if done: return - - if masked: - is_dir = CONST.mask_path_is_dir() - path = CONST.mask_path() - else: - is_dir = CONST.unmask_path_is_dir() - path = CONST.unmask_path() - - if is_dir: - file = os.path.join(path, generate_path(cpv, CONFIG["maskfile"])) - else: - file = path - - link_neq[cpv].append((file, "-1")) - link_neq[cpv] = unique_array(link_neq[cpv]) - debug("new_(un)masked: %s",str(link_neq)) + """Sets the masking status of the package. + + @param pkg: the package from which to get the flags + @type pkg: string (cpv) or L{backend.Package}-object + @param masked: if True: mask it; if False: unmask it + @type masked: boolean""" + + global new_masked, newunmasked + + if not is_package(pkg): + pkg = system.new_package(pkg) + + cpv = pkg.get_cpv() + + if not cpv in new_unmasked: + new_unmasked[cpv] = [] + if not cpv in new_masked: + new_masked[cpv] = [] + + if masked: + link_neq = new_masked + link_eq = new_unmasked + path = CONST.unmask_path() + else: + link_neq = new_unmasked + link_eq = new_masked + path = CONST.mask_path() + + copy = link_eq[cpv][:] + for file, line in copy: + if line == "-1": + link_eq[cpv].remove((file, line)) + + copy = link_neq[cpv][:] + for file, line in copy: + if line != "-1": + link_neq[cpv].remove((file, line)) + + if masked == pkg.is_masked(): + return + + data = get_data(pkg, path) + debug("data: %s", str(data)) + done = False + for file, line, crit, flags in data: + if pkg.matches(crit): + link_eq[cpv].append((file, line)) + done = True + + if done: return + + if masked: + is_dir = CONST.mask_path_is_dir() + path = CONST.mask_path() + else: + is_dir = CONST.unmask_path_is_dir() + path = CONST.unmask_path() + + if is_dir: + file = os.path.join(path, generate_path(cpv, CONFIG["maskfile"])) + else: + file = path + + link_neq[cpv].append((file, "-1")) + link_neq[cpv] = unique_array(link_neq[cpv]) + debug("new_(un)masked: %s",str(link_neq)) def remove_new_masked (cpv): - if is_package(cpv): - cpv = cpv.get_cpv() - - try: - del new_masked[cpv] - except KeyError: - pass - - try: - del new_unmasked[cpv] - except KeyError: - pass + if is_package(cpv): + cpv = cpv.get_cpv() + + try: + del new_masked[cpv] + except KeyError: + pass + + try: + del new_unmasked[cpv] + except KeyError: + pass def new_masking_status (cpv): - if is_package(cpv): - cpv = cpv.get_cpv() - - def get(list): - ret = None - if cpv in list and list[cpv] != []: - for file, line in list[cpv]: - _ret = (int(line) == -1) - if ret is not None and _ret != ret: - error(_("Conflicting values for masking status: %s"), list) - else: - ret = _ret - return ret - - masked = get(new_masked) - if masked is None: - masked = get(new_unmasked) - if masked is not None: - masked = not masked # revert for new_unmasked - - if masked is not None: - if masked: return "masked" - else: return "unmasked" - else: - return None + if is_package(cpv): + cpv = cpv.get_cpv() + + def get(list): + ret = None + if cpv in list and list[cpv] != []: + for file, line in list[cpv]: + _ret = (int(line) == -1) + if ret is not None and _ret != ret: + error(_("Conflicting values for masking status: %s"), list) + else: + ret = _ret + return ret + + masked = get(new_masked) + if masked is None: + masked = get(new_unmasked) + if masked is not None: + masked = not masked # revert for new_unmasked + + if masked is not None: + if masked: return "masked" + else: return "unmasked" + else: + return None def is_locally_masked (pkg, changes = True): - if not is_package(pkg): - pkg = system.new_package(pkg) # assume it is a cpv or a gentoolkit.Package + if not is_package(pkg): + pkg = system.new_package(pkg) # assume it is a cpv or a gentoolkit.Package - if changes: - if new_masking_status(pkg) == "masked": # we masked it ourselves, but did not save it yet - # but sometimes, new_masking_status() returns "masked" if a package's unmask is removed - # then it is masked by the system but not locally (except rarely exotic cases) - if pkg.get_cpv() in new_unmasked: - if new_unmasked[pkg.get_cpv()]: return False # assume that there only exists one entry for this package - # else new_masking_status should have printed an error - return True + if changes: + if new_masking_status(pkg) == "masked": # we masked it ourselves, but did not save it yet + # but sometimes, new_masking_status() returns "masked" if a package's unmask is removed + # then it is masked by the system but not locally (except rarely exotic cases) + if pkg.get_cpv() in new_unmasked: + if new_unmasked[pkg.get_cpv()]: return False # assume that there only exists one entry for this package + # else new_masking_status should have printed an error + return True - if new_masking_status(pkg) == "unmasked": # we unmasked it - return False - - list = get_data(pkg, CONST.mask_path()) + if new_masking_status(pkg) == "unmasked": # we unmasked it + return False + + list = get_data(pkg, CONST.mask_path()) - if not list: return False + if not list: return False - for file, line, crit, fl in list: - if pkg.matches(crit): - return True + for file, line, crit, fl in list: + if pkg.matches(crit): + return True - return False - + return False + def write_masked (): - global new_unmasked, new_masked - file_cache = {} - - def write(cpv, file, line): - line = int(line) - # add new line - if line == -1: - msg = "\n#portato update#\n" - if CONFIG["maskPerVersion"]: - msg += "=%s\n" % cpv - else: - list = system.split_cpv(cpv) - msg += "%s/%s\n" % (list[0],list[1]) - 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 portato\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 portato\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 = {} - system.reload_settings() + global new_unmasked, new_masked + file_cache = {} + + def write(cpv, file, line): + line = int(line) + # add new line + if line == -1: + msg = "\n#portato update#\n" + if CONFIG["maskPerVersion"]: + msg += "=%s\n" % cpv + else: + list = system.split_cpv(cpv) + msg += "%s/%s\n" % (list[0],list[1]) + 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 portato\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 portato\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 = {} + system.reload_settings() ### TESTING PART ### newTesting = {} arch = "" def remove_new_testing (cpv): - if is_package(cpv): - cpv = cpv.get_cpv() - - try: - del newTesting[cpv] - except KeyError: - pass + if is_package(cpv): + cpv = cpv.get_cpv() + + try: + del newTesting[cpv] + except KeyError: + pass def new_testing_status (cpv): - if is_package(cpv): - cpv = cpv.get_cpv() + if is_package(cpv): + cpv = cpv.get_cpv() - if cpv in newTesting: - for file, line in newTesting[cpv]: - if line == "-1": return False - else: return True + if cpv in newTesting: + for file, line in newTesting[cpv]: + if line == "-1": return False + else: return True - return None + return None 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{backend.Package}-object - @param enable: controls whether to enable (True) or disable (False) for test-installing - @type enable: boolean""" - - global arch, newTesting - if not is_package(pkg): - pkg = system.new_package(pkg) - - arch = pkg.get_global_settings("ARCH") - cpv = pkg.get_cpv() - if not cpv in newTesting: - newTesting[cpv] = [] - - 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 not pkg.is_testing()) or (not enable and pkg.is_testing()): - return - - if not enable: - test = get_data(pkg, CONST.testing_path()) - debug("data (test): %s", str(test)) - for file, line, crit, flags in test: - if pkg.matches(crit) and flags[0] == "~"+arch: - newTesting[cpv].append((file, line)) - else: - if CONST.testing_path_is_dir(): - file = os.path.join(CONST.testing_path(), generate_path(cpv, CONFIG["testingfile"])) - else: - file = CONST.testing_path() - newTesting[cpv].append((file, "-1")) - - newTesting[cpv] = unique_array(newTesting[cpv]) - debug("newTesting: %s",str(newTesting)) + """Enables the package for installing when it is marked as testing (~ARCH). + @param pkg: the package + @type pkg: string (cpv) or L{backend.Package}-object + @param enable: controls whether to enable (True) or disable (False) for test-installing + @type enable: boolean""" + + global arch, newTesting + if not is_package(pkg): + pkg = system.new_package(pkg) + + arch = pkg.get_global_settings("ARCH") + cpv = pkg.get_cpv() + if not cpv in newTesting: + newTesting[cpv] = [] + + 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 not pkg.is_testing()) or (not enable and pkg.is_testing()): + return + + if not enable: + test = get_data(pkg, CONST.testing_path()) + debug("data (test): %s", str(test)) + for file, line, crit, flags in test: + if pkg.matches(crit) and flags[0] == "~"+arch: + newTesting[cpv].append((file, line)) + else: + if CONST.testing_path_is_dir(): + file = os.path.join(CONST.testing_path(), generate_path(cpv, CONFIG["testingfile"])) + else: + file = CONST.testing_path() + newTesting[cpv].append((file, "-1")) + + newTesting[cpv] = unique_array(newTesting[cpv]) + debug("newTesting: %s",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#portato update#\n" - if CONFIG["testingPerVersion"]: - msg += "=%s ~%s\n" % (cpv, arch) - else: - list = system.split_cpv(cpv) - msg += "%s/%s ~%s\n" % (list[0],list[1],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 portato\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 portato\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 = {} - system.reload_settings() + 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#portato update#\n" + if CONFIG["testingPerVersion"]: + msg += "=%s ~%s\n" % (cpv, arch) + else: + list = system.split_cpv(cpv) + msg += "%s/%s ~%s\n" % (list[0],list[1],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 portato\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 portato\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 = {} + system.reload_settings() diff --git a/portato/backend/package.py b/portato/backend/package.py index 6d73a42..e4b2082 100644 --- a/portato/backend/package.py +++ b/portato/backend/package.py @@ -18,396 +18,396 @@ from ..dependency import DependencyTree from . import _Package, system, flags class Package (_Package): - """This is a class abstracting a normal package which can be installed.""" - - def __init__ (self, cpv): - """Constructor. - - @param cpv: The cpv which describes the package to create. - @type cpv: string (cat/pkg-ver)""" - - self._cpv = cpv - - # - # implemented - # - - def set_testing(self, enable = True): - """Sets the actual testing status of the package. - - @param enable: if True it is masked as stable; if False it is marked as testing - @type enable: boolean""" - - flags.set_testing(self, enable) - - def remove_new_testing(self): - """Removes possible changed testing status.""" - - flags.remove_new_testing(self.get_cpv()) - - def set_masked (self, masking = False): - """Sets the masking status of the package. - - @param masking: if True: mask it; if False: unmask it - @type masking: boolean""" - - flags.set_masked(self, masked = masking) - - def remove_new_masked (self): - """Removes possible changed masking status.""" - - flags.remove_new_masked(self.get_cpv()) - - def is_locally_masked (self): - """Checks whether the package is masked by the user. - - @returns: True if masked by the user; False if not - @rtype: bool""" - - return flags.is_locally_masked(self) - - 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: string[]""" - - return flags.get_new_use_flags(self) - - def get_actual_use_flags (self): - """This returns all currently set use-flags including the new ones. - - @return: list of flags - @rtype: string[]""" - - i_flags = self.get_global_settings("USE", installed = False).split() - m_flags = system.get_global_settings("USE").split() - for f in self.get_new_use_flags(): - removed = False - - if f[0] == "~": - f = f[1:] - removed = True - - invf = flags.invert_use_flag(f) - - if f[0] == '-': - if invf in i_flags and not (removed and invf in m_flags): - i_flags.remove(invf) - - elif f not in i_flags: - if not (removed and invf in m_flags): - i_flags.append(f) - - return i_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 use_expanded (self, flag, suggest = None): - """Tests whether a useflag is an expanded one. If it is, this method returns the USE_EXPAND-value. - - @param flag: the flag to check - @type flag: string - @param suggest: try this suggestion first - @type suggest: string - @returns: USE_EXPAND-value on success - @rtype: string or None""" - - if suggest is not None: - if flag.startswith(suggest.lower()): - return suggest - - for exp in self.get_global_settings("USE_EXPAND").split(): - lexp = exp.lower() - if flag.startswith(lexp): - return exp - - return None - - def get_cpv(self): - """Returns full Category/Package-Version string. - - @returns: the cpv - @rtype: string""" - - return self._cpv - - def get_cp (self): - """Returns the cp-string. - - @returns: category/package. - @rtype: string""" - - return self.get_category()+"/"+self.get_name() - - def get_slot_cp (self): - """Returns the current cp followed by a colon and the slot-number. - - @returns: cp:slot - @rtype: string""" - - return ("%s:%s" % (self.get_cp(), self.get_package_settings("SLOT"))) - - def get_package_path(self): - """Returns the path to where the ChangeLog, Manifest, .ebuild files reside. - - @returns: path to the package files - @rtype: string""" - - p = self.get_ebuild_path() - sp = p.split("/") - if sp: - return "/".join(sp[:-1]) - - def get_dependencies (self): - """ - Returns the tree of dependencies that this package needs. - - @rtype: L{DependencyTree} - """ - deps = " ".join(map(self.get_package_settings, ("RDEPEND", "PDEPEND", "DEPEND"))) - deps = paren_reduce(deps) - - tree = DependencyTree() - - def add (tree, deps): - it = iter(deps) - for dep in it: - if hasattr(dep, "__iter__"): - debug("Following dep is an unsupposed list: %s", dep) - assert(len(dep) == 1) - dep = dep[0] - if dep.endswith("?"): - ntree = tree.add_flag(dep[:-1]) - n = it.next() - if not hasattr(n, "__iter__"): - n = (n,) - add(ntree, n) - - elif dep == "||": - n = it.next() # skip - if not hasattr(n, "__iter__"): - n = [n] - else: - n = list(n) - - tree.add_or(n) - - else: - tree.add(dep) - - add(tree, deps) - return tree - - # - # Not implemented - # - - def get_name(self): - """Returns base name of package, no category nor version. - - @returns: base-name - @rtype: string""" - - raise NotImplementedError - - def get_version(self): - """Returns version of package, with (optional) revision number. - - @returns: version-rev - @rtype: string""" - - raise NotImplementedError - - def get_category(self): - """Returns category of package. - - @returns: category - @rtype: string""" - - raise NotImplementedError - - def is_installed(self): - """Returns true if this package is installed (merged). - @rtype: boolean""" - - raise NotImplementedError - - def is_in_overlay(self): - """Returns true if the package is in an overlay. - @rtype: boolean""" - - raise NotImplementedError - - def get_overlay_path(self): - """Returns the path to the current overlay. - @rtype: string""" - - raise NotImplementedError - - def is_in_system (self): - """Returns False if the package could not be found in the portage system. - - @return: True if in portage system; else False - @rtype: boolean""" - - raise NotImplementedError - - def is_missing_keyword(self): - """Returns True if the package is missing the needed keyword. - - @return: True if keyword is missing; else False - @rtype: boolean""" - - raise NotImplementedError - - def is_testing(self, use_keywords = True): - """Checks whether a package is marked as testing. - - @param use_keywords: Controls whether possible keywords are taken into account or not. - @type use_keywords: boolean - @returns: True if the package is marked as testing; else False. - @rtype: boolean""" - - raise NotImplementedError - - def is_masked (self, use_changed = True): - """Returns True if either masked by package.mask or by profile. - - @param use_changed: Controls, whether changes applied to masking keywords are taken into account. - @type use_changed: boolean - @returns: True if masked / False otherwise - @rtype: boolean""" - - raise NotImplementedError - - def get_masking_reason (self): - """Returns the reason for masking the package. If this is not possible for the system, return None. - - @returns: the reason for masking the package - @rtype: string""" - - def get_iuse_flags (self, installed = False, removeForced = True): - """Returns a list of _all_ useflags for this package, i.e. all useflags you can set for this package. - - @param installed: do not take the ones stated in the ebuild, but the ones it has been installed with - @type installed: boolean - @param removeForced: remove forced flags (i.e. usemask / useforce) from the iuse flags as they cannot be set from the user - @type removeForced: boolean - - @returns: list of use-flags - @rtype: string[]""" - - raise NotImplementedError - - def get_matched_dep_packages (self, depvar): - """This function looks for all dependencies which are resolved. In normal case it makes only sense for installed packages, but should work for uninstalled ones too. - - @param depvar: the dependency variables (RDEPEND, PDEPEND, DEPEND) to use - @type depvar: string[] - - @returns: unique list of dependencies resolved (with elements like "<=net-im/foobar-1.2.3") - @rtype: string[] - - @raises portato.DependencyCalcError: when an error occured during executing portage.dep_check()""" - - raise NotImplementedError - - def get_dep_packages (self, depvar = ["RDEPEND", "PDEPEND", "DEPEND"], with_criterions = False): - """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. - - @param depvar: the dependency variables (RDEPEND, PDEPEND, DEPEND) to use - @type depvar: string[] - @param with_criterions: return also the criterions - @type with_criterions: boolean - - @returns: list of cpvs on which the package depend (and if wanted also the criterions) - @rtype: string[] or (string, string)[] - - @raises portato.BlockedException: when a package in the dependency-list is blocked by an installed one - @raises portato.PackageNotFoundException: when a package in the dependency list could not be found in the system - @raises portato.DependencyCalcError: when an error occured during executing portage.dep_check()""" - - raise NotImplementedError - - def get_global_settings(self, key, installed = True): - """Returns the value of a global setting, i.e. ARCH, USE, ROOT, DISTDIR etc. - - @param key: the setting to return - @type key: string - @param installed: get the installed settings or the ebuild settings - @type installed: boolean - @returns: the value of this setting - @rtype: string""" - - raise NotImplementedError - - def get_ebuild_path(self): - """Returns the complete path to the .ebuild file. - - @rtype: string""" - - raise NotImplementedError - - def get_files (self): - """ - Returns an iterator over the installed files of a package. - If the package is not installed, the iterator should be "empty". - - @returns: the installed files - @rtype: string - """ - - raise NotImplementedError - - def get_package_settings(self, var, installed = True): - """Returns a package specific setting, such as DESCRIPTION, SRC_URI, IUSE ... - - @param var: the setting to get - @type var: string - @param installed: take the vartree or the porttree - @type installed: boolean - - @returns: the value of the setting - @rtype: string""" - - raise NotImplementedError - - def get_installed_use_flags(self): - """Returns _all_ (not only the package-specific) useflags which were set at the installation time of the package. - - @returns: list of use flags - @rtype: string[]""" - - raise NotImplementedError - - def compare_version(self, other): - """Compares this package's version to another's CPV; returns -1, 0, 1. - - @param other: the other package - @type other: Package - @returns: -1, 0 or 1 - @rtype: int""" - - raise NotImplementedError - - def matches (self, criterion): - """This checks, whether this package matches a specific versioning criterion - e.g.: "<=net-im/foobar-1.2". - - @param criterion: the criterion to match against - @type criterion: string - @returns: True if matches; False if not - @rtype: boolean""" - - raise NotImplementedError + """This is a class abstracting a normal package which can be installed.""" + + def __init__ (self, cpv): + """Constructor. + + @param cpv: The cpv which describes the package to create. + @type cpv: string (cat/pkg-ver)""" + + self._cpv = cpv + + # + # implemented + # + + def set_testing(self, enable = True): + """Sets the actual testing status of the package. + + @param enable: if True it is masked as stable; if False it is marked as testing + @type enable: boolean""" + + flags.set_testing(self, enable) + + def remove_new_testing(self): + """Removes possible changed testing status.""" + + flags.remove_new_testing(self.get_cpv()) + + def set_masked (self, masking = False): + """Sets the masking status of the package. + + @param masking: if True: mask it; if False: unmask it + @type masking: boolean""" + + flags.set_masked(self, masked = masking) + + def remove_new_masked (self): + """Removes possible changed masking status.""" + + flags.remove_new_masked(self.get_cpv()) + + def is_locally_masked (self): + """Checks whether the package is masked by the user. + + @returns: True if masked by the user; False if not + @rtype: bool""" + + return flags.is_locally_masked(self) + + 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: string[]""" + + return flags.get_new_use_flags(self) + + def get_actual_use_flags (self): + """This returns all currently set use-flags including the new ones. + + @return: list of flags + @rtype: string[]""" + + i_flags = self.get_global_settings("USE", installed = False).split() + m_flags = system.get_global_settings("USE").split() + for f in self.get_new_use_flags(): + removed = False + + if f[0] == "~": + f = f[1:] + removed = True + + invf = flags.invert_use_flag(f) + + if f[0] == '-': + if invf in i_flags and not (removed and invf in m_flags): + i_flags.remove(invf) + + elif f not in i_flags: + if not (removed and invf in m_flags): + i_flags.append(f) + + return i_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 use_expanded (self, flag, suggest = None): + """Tests whether a useflag is an expanded one. If it is, this method returns the USE_EXPAND-value. + + @param flag: the flag to check + @type flag: string + @param suggest: try this suggestion first + @type suggest: string + @returns: USE_EXPAND-value on success + @rtype: string or None""" + + if suggest is not None: + if flag.startswith(suggest.lower()): + return suggest + + for exp in self.get_global_settings("USE_EXPAND").split(): + lexp = exp.lower() + if flag.startswith(lexp): + return exp + + return None + + def get_cpv(self): + """Returns full Category/Package-Version string. + + @returns: the cpv + @rtype: string""" + + return self._cpv + + def get_cp (self): + """Returns the cp-string. + + @returns: category/package. + @rtype: string""" + + return self.get_category()+"/"+self.get_name() + + def get_slot_cp (self): + """Returns the current cp followed by a colon and the slot-number. + + @returns: cp:slot + @rtype: string""" + + return ("%s:%s" % (self.get_cp(), self.get_package_settings("SLOT"))) + + def get_package_path(self): + """Returns the path to where the ChangeLog, Manifest, .ebuild files reside. + + @returns: path to the package files + @rtype: string""" + + p = self.get_ebuild_path() + sp = p.split("/") + if sp: + return "/".join(sp[:-1]) + + def get_dependencies (self): + """ + Returns the tree of dependencies that this package needs. + + @rtype: L{DependencyTree} + """ + deps = " ".join(map(self.get_package_settings, ("RDEPEND", "PDEPEND", "DEPEND"))) + deps = paren_reduce(deps) + + tree = DependencyTree() + + def add (tree, deps): + it = iter(deps) + for dep in it: + if hasattr(dep, "__iter__"): + debug("Following dep is an unsupposed list: %s", dep) + assert(len(dep) == 1) + dep = dep[0] + if dep.endswith("?"): + ntree = tree.add_flag(dep[:-1]) + n = it.next() + if not hasattr(n, "__iter__"): + n = (n,) + add(ntree, n) + + elif dep == "||": + n = it.next() # skip + if not hasattr(n, "__iter__"): + n = [n] + else: + n = list(n) + + tree.add_or(n) + + else: + tree.add(dep) + + add(tree, deps) + return tree + + # + # Not implemented + # + + def get_name(self): + """Returns base name of package, no category nor version. + + @returns: base-name + @rtype: string""" + + raise NotImplementedError + + def get_version(self): + """Returns version of package, with (optional) revision number. + + @returns: version-rev + @rtype: string""" + + raise NotImplementedError + + def get_category(self): + """Returns category of package. + + @returns: category + @rtype: string""" + + raise NotImplementedError + + def is_installed(self): + """Returns true if this package is installed (merged). + @rtype: boolean""" + + raise NotImplementedError + + def is_in_overlay(self): + """Returns true if the package is in an overlay. + @rtype: boolean""" + + raise NotImplementedError + + def get_overlay_path(self): + """Returns the path to the current overlay. + @rtype: string""" + + raise NotImplementedError + + def is_in_system (self): + """Returns False if the package could not be found in the portage system. + + @return: True if in portage system; else False + @rtype: boolean""" + + raise NotImplementedError + + def is_missing_keyword(self): + """Returns True if the package is missing the needed keyword. + + @return: True if keyword is missing; else False + @rtype: boolean""" + + raise NotImplementedError + + def is_testing(self, use_keywords = True): + """Checks whether a package is marked as testing. + + @param use_keywords: Controls whether possible keywords are taken into account or not. + @type use_keywords: boolean + @returns: True if the package is marked as testing; else False. + @rtype: boolean""" + + raise NotImplementedError + + def is_masked (self, use_changed = True): + """Returns True if either masked by package.mask or by profile. + + @param use_changed: Controls, whether changes applied to masking keywords are taken into account. + @type use_changed: boolean + @returns: True if masked / False otherwise + @rtype: boolean""" + + raise NotImplementedError + + def get_masking_reason (self): + """Returns the reason for masking the package. If this is not possible for the system, return None. + + @returns: the reason for masking the package + @rtype: string""" + + def get_iuse_flags (self, installed = False, removeForced = True): + """Returns a list of _all_ useflags for this package, i.e. all useflags you can set for this package. + + @param installed: do not take the ones stated in the ebuild, but the ones it has been installed with + @type installed: boolean + @param removeForced: remove forced flags (i.e. usemask / useforce) from the iuse flags as they cannot be set from the user + @type removeForced: boolean + + @returns: list of use-flags + @rtype: string[]""" + + raise NotImplementedError + + def get_matched_dep_packages (self, depvar): + """This function looks for all dependencies which are resolved. In normal case it makes only sense for installed packages, but should work for uninstalled ones too. + + @param depvar: the dependency variables (RDEPEND, PDEPEND, DEPEND) to use + @type depvar: string[] + + @returns: unique list of dependencies resolved (with elements like "<=net-im/foobar-1.2.3") + @rtype: string[] + + @raises portato.DependencyCalcError: when an error occured during executing portage.dep_check()""" + + raise NotImplementedError + + def get_dep_packages (self, depvar = ["RDEPEND", "PDEPEND", "DEPEND"], with_criterions = False): + """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. + + @param depvar: the dependency variables (RDEPEND, PDEPEND, DEPEND) to use + @type depvar: string[] + @param with_criterions: return also the criterions + @type with_criterions: boolean + + @returns: list of cpvs on which the package depend (and if wanted also the criterions) + @rtype: string[] or (string, string)[] + + @raises portato.BlockedException: when a package in the dependency-list is blocked by an installed one + @raises portato.PackageNotFoundException: when a package in the dependency list could not be found in the system + @raises portato.DependencyCalcError: when an error occured during executing portage.dep_check()""" + + raise NotImplementedError + + def get_global_settings(self, key, installed = True): + """Returns the value of a global setting, i.e. ARCH, USE, ROOT, DISTDIR etc. + + @param key: the setting to return + @type key: string + @param installed: get the installed settings or the ebuild settings + @type installed: boolean + @returns: the value of this setting + @rtype: string""" + + raise NotImplementedError + + def get_ebuild_path(self): + """Returns the complete path to the .ebuild file. + + @rtype: string""" + + raise NotImplementedError + + def get_files (self): + """ + Returns an iterator over the installed files of a package. + If the package is not installed, the iterator should be "empty". + + @returns: the installed files + @rtype: string + """ + + raise NotImplementedError + + def get_package_settings(self, var, installed = True): + """Returns a package specific setting, such as DESCRIPTION, SRC_URI, IUSE ... + + @param var: the setting to get + @type var: string + @param installed: take the vartree or the porttree + @type installed: boolean + + @returns: the value of the setting + @rtype: string""" + + raise NotImplementedError + + def get_installed_use_flags(self): + """Returns _all_ (not only the package-specific) useflags which were set at the installation time of the package. + + @returns: list of use flags + @rtype: string[]""" + + raise NotImplementedError + + def compare_version(self, other): + """Compares this package's version to another's CPV; returns -1, 0, 1. + + @param other: the other package + @type other: Package + @returns: -1, 0 or 1 + @rtype: int""" + + raise NotImplementedError + + def matches (self, criterion): + """This checks, whether this package matches a specific versioning criterion - e.g.: "<=net-im/foobar-1.2". + + @param criterion: the criterion to match against + @type criterion: string + @returns: True if matches; False if not + @rtype: boolean""" + + raise NotImplementedError diff --git a/portato/backend/portage/__init__.py b/portato/backend/portage/__init__.py index be6cce6..02a4a82 100644 --- a/portato/backend/portage/__init__.py +++ b/portato/backend/portage/__init__.py @@ -17,8 +17,8 @@ from portage import VERSION as PV VERSION = tuple(map(int, (x.split("_")[0] for x in PV.split(".")))) if VERSION >= (2, 2): - from .system_22 import PortageSystem_22 as PortageSystem - from .package_22 import PortagePackage_22 as PortagePackage + from .system_22 import PortageSystem_22 as PortageSystem + from .package_22 import PortagePackage_22 as PortagePackage else: - from .system import PortageSystem - from .package import PortagePackage + from .system import PortageSystem + from .package import PortagePackage diff --git a/portato/backend/portage/package.py b/portato/backend/portage/package.py index 351b7e0..0270029 100644 --- a/portato/backend/portage/package.py +++ b/portato/backend/portage/package.py @@ -21,294 +21,294 @@ from ...helper import debug, error, unique_array import portage try: - import portage.dep as portage_dep + import portage.dep as portage_dep except ImportError: - import portage_dep + import portage_dep import os.path class PortagePackage (Package): - """This is a class abstracting a normal package which can be installed for the portage-system.""" - - def __init__ (self, cpv): - """Constructor. - - @param cpv: The cpv which describes the package to create. - @type cpv: string (cat/pkg-ver)""" - - Package.__init__(self, cpv) - self._scpv = system.split_cpv(self._cpv) - - if not self._scpv: - raise ValueError("invalid cpv: %s" % cpv) - - self._settings = system.settings - self._settingslock = system.settings.settingslock - self._settings_installed = None - - self._trees = system.settings.trees - - self.forced_flags = set() - - with self._settingslock: - self._init_settings(True) - self.forced_flags.update(self._settings.settings.usemask) - self.forced_flags.update(self._settings.settings.useforce) - - try: - self._status = portage.getmaskingstatus(self.get_cpv(), settings = self._settings.settings) - except KeyError: # package is not located in the system - self._status = None - - if self._status and len(self._status) == 1 and self._status[0] == "corrupted": - self._status = None - - def _init_settings (self, installed): - inst = (installed and self.is_installed()) or (self.is_installed() and not self.is_in_system()) - - if self._settings_installed is not None and self._settings_installed != inst: - self._settings.settings.reset() - - self._settings_installed = inst - - if inst: - dbapi = self._settings.vartree.dbapi - else: - dbapi = self._settings.porttree.dbapi - - self._settings.settings.setcpv(self.get_cpv(), mydb = dbapi) - - def get_name(self): - return self._scpv[1] - - def get_version(self): - v = self._scpv[2] - if self._scpv[3] != "r0": - v += "-" + self._scpv[3] - return v - - def get_category(self): - return self._scpv[0] - - def is_installed(self): - return self._settings.vartree.dbapi.cpv_exists(self._cpv) - - def is_in_overlay(self): - ovl = self.get_overlay_path() - return ovl != self._settings.settings["PORTDIR"] and str(ovl) != "0" - - def get_overlay_path (self): - dir,ovl = self._settings.porttree.dbapi.findname2(self._cpv) - return ovl - - def is_in_system (self): - return (self._status != None) - - def is_missing_keyword(self): - return self._status and "missing keyword" in self._status - - def is_testing(self, use_keywords = True): - testArch = "~" + self.get_global_settings("ARCH") - if not use_keywords: # keywords are NOT taken into account - return testArch in self.get_package_settings("KEYWORDS").split() - - else: # keywords are taken into account - status = flags.new_testing_status(self.get_cpv()) - if status is None: # we haven't changed it in any way - return self._status and testArch+" keyword" in self._status - else: - return status - - def is_masked (self, use_changed = True): - - if use_changed: - status = flags.new_masking_status(self.get_cpv()) - if status != None: # we have locally changed it - if status == "masked": return True - elif status == "unmasked": return False - else: - error(_("BUG in flags.new_masking_status. It returns \'%s\'"), status) - else: # we have not touched the status - return self._status and ("profile" in self._status or "package.mask" in self._status) - - else: # we want the original portage value XXX: bug if masked by user AND by system - - # get the normal masked ones - if self._status and ("profile" in self._status or "package.mask" in self._status): - return not flags.is_locally_masked(self, changes = False) # assume that if it is locally masked, it is not masked by the system - else: # more difficult: get the ones we unmasked, but are masked by the system - try: - masked = self._settings.settings.pmaskdict[self.get_cp()] - except KeyError: # key error: not masked - return False - - for cpv in masked: - if self.matches(cpv): - return not flags.is_locally_masked(self, changes = False) # assume that if it is locally masked, it is not masked by the system - - return False - - def get_masking_reason(self): - reason = portage.getmaskingreason(self.get_cpv(), settings = self._settings.settings) - - if reason: - return reason.strip() - else: - return reason - - def get_iuse_flags (self, installed = False, removeForced = True): - if not self.is_in_system(): - installed = True - - iuse = flags.filter_defaults(self.get_package_settings("IUSE", installed = installed).split()) - - iuse = set(iuse) - - if removeForced: - return list(iuse.difference(self.forced_flags)) - else: - return list(iuse) - - def get_matched_dep_packages (self, depvar): - # change the useflags, because we have internally changed some, but not made them visible for portage - actual = self.get_actual_use_flags() - - depstring = "" - try: - for d in depvar: - depstring += self.get_package_settings(d, installed = False)+" " - except KeyError: # not found in porttree - use vartree - depstring = "" - for d in depvar: - depstring += self.get_package_settings(d, installed = True)+" " - - deps = portage.dep_check(depstring, None, self._settings.settings, myuse = actual, trees = self._trees) - - if not deps: # FIXME: what is the difference to [1, []] ? - return [] - - if deps[0] == 0: # error - raise DependencyCalcError, deps[1] - - deps = deps[1] - - return [d for d in deps if d[0] != "!"] - - def get_dep_packages (self, depvar = ["RDEPEND", "PDEPEND", "DEPEND"], with_criterions = False, return_blocks = False): - dep_pkgs = [] # the package list - - # change the useflags, because we have internally changed some, but not made them visible for portage - actual = self.get_actual_use_flags() - - depstring = "" - for d in depvar: - depstring += self.get_package_settings(d, installed = False)+" " - - # let portage do the main stuff ;) - # pay attention to any changes here - deps = portage.dep_check (depstring, self._settings.vartree.dbapi, self._settings.settings, myuse = actual, trees = self._trees) - - if not deps: # FIXME: what is the difference to [1, []] ? - return [] - - if deps[0] == 0: # error - raise DependencyCalcError, deps[1] - - deps = deps[1] - - def create_dep_pkgs_data (dep, pkg): - """Returns the data to enter into the dep_pkgs list, which is either the package cpv or a tuple - consisting of the cpv and the criterion.""" - if with_criterions: - return (pkg.get_cpv(), dep) - else: - return pkg.get_cpv() - - for dep in deps: - if dep[0] == '!': # blocking sth - blocked = system.find_packages(dep, system.SET_INSTALLED) - if len(blocked) == 1: # only exact one match allowed to be harmless - if blocked[0].get_slot_cp() == self.get_slot_cp(): # blocks in the same slot are harmless - continue - - if return_blocks: - if with_criterions: - dep_pkgs.append((dep, dep)) - else: - dep_pkgs.append(dep) - else: - raise BlockedException, (self.get_cpv(), blocked[0].get_cpv()) - - continue # finished with the blocking one -> next - - pkg = system.find_best_match(dep) - if not pkg: # try to find masked ones - pkgs = system.find_packages(dep, masked = True) - if not pkgs: - raise PackageNotFoundException, dep - - pkgs = system.sort_package_list(pkgs) - pkgs.reverse() - done = False - for p in pkgs: - if not p.is_masked(): - dep_pkgs.append(create_dep_pkgs_data(dep, p)) - done = True - break - if not done: - dep_pkgs.append(create_dep_pkgs_data(dep, pkgs[0])) - else: - dep_pkgs.append(create_dep_pkgs_data(dep, pkg)) - - return dep_pkgs - - def get_global_settings(self, key, installed = True): - with self._settingslock: - self._init_settings(installed) - v = self._settings.settings[key] - - return v - - def get_ebuild_path(self): - if self.is_in_system(): - return self._settings.porttree.dbapi.findname(self._cpv) - else: - return self._settings.vartree.dbapi.findname(self._cpv) - - def get_files (self): - if self.is_installed(): - path = os.path.join(self.get_global_settings("ROOT"), portage.VDB_PATH, self.get_cpv(), "CONTENTS") - with open(path) as f: - for line in f: - yield line.split()[1].strip() - - def get_package_settings(self, var, installed = True): - if installed and self.is_installed(): - mytree = self._settings.vartree - else: - mytree = self._settings.porttree - - r = mytree.dbapi.aux_get(self._cpv,[var]) - - return r[0] - - def get_installed_use_flags(self): - if self.is_installed(): - return self.get_package_settings("USE", installed = True).split() - else: return [] - - def compare_version(self,other): - v1 = self._scpv - v2 = portage.catpkgsplit(other.get_cpv()) - # if category is different - if v1[0] != v2[0]: - return cmp(v1[0],v2[0]) - # if name is different - elif v1[1] != v2[1]: - return cmp(v1[1],v2[1]) - # Compare versions - else: - return portage.pkgcmp(v1[1:],v2[1:]) - - def matches (self, criterion): - return system.cpv_matches(self.get_cpv(), criterion) + """This is a class abstracting a normal package which can be installed for the portage-system.""" + + def __init__ (self, cpv): + """Constructor. + + @param cpv: The cpv which describes the package to create. + @type cpv: string (cat/pkg-ver)""" + + Package.__init__(self, cpv) + self._scpv = system.split_cpv(self._cpv) + + if not self._scpv: + raise ValueError("invalid cpv: %s" % cpv) + + self._settings = system.settings + self._settingslock = system.settings.settingslock + self._settings_installed = None + + self._trees = system.settings.trees + + self.forced_flags = set() + + with self._settingslock: + self._init_settings(True) + self.forced_flags.update(self._settings.settings.usemask) + self.forced_flags.update(self._settings.settings.useforce) + + try: + self._status = portage.getmaskingstatus(self.get_cpv(), settings = self._settings.settings) + except KeyError: # package is not located in the system + self._status = None + + if self._status and len(self._status) == 1 and self._status[0] == "corrupted": + self._status = None + + def _init_settings (self, installed): + inst = (installed and self.is_installed()) or (self.is_installed() and not self.is_in_system()) + + if self._settings_installed is not None and self._settings_installed != inst: + self._settings.settings.reset() + + self._settings_installed = inst + + if inst: + dbapi = self._settings.vartree.dbapi + else: + dbapi = self._settings.porttree.dbapi + + self._settings.settings.setcpv(self.get_cpv(), mydb = dbapi) + + def get_name(self): + return self._scpv[1] + + def get_version(self): + v = self._scpv[2] + if self._scpv[3] != "r0": + v += "-" + self._scpv[3] + return v + + def get_category(self): + return self._scpv[0] + + def is_installed(self): + return self._settings.vartree.dbapi.cpv_exists(self._cpv) + + def is_in_overlay(self): + ovl = self.get_overlay_path() + return ovl != self._settings.settings["PORTDIR"] and str(ovl) != "0" + + def get_overlay_path (self): + dir,ovl = self._settings.porttree.dbapi.findname2(self._cpv) + return ovl + + def is_in_system (self): + return (self._status != None) + + def is_missing_keyword(self): + return self._status and "missing keyword" in self._status + + def is_testing(self, use_keywords = True): + testArch = "~" + self.get_global_settings("ARCH") + if not use_keywords: # keywords are NOT taken into account + return testArch in self.get_package_settings("KEYWORDS").split() + + else: # keywords are taken into account + status = flags.new_testing_status(self.get_cpv()) + if status is None: # we haven't changed it in any way + return self._status and testArch+" keyword" in self._status + else: + return status + + def is_masked (self, use_changed = True): + + if use_changed: + status = flags.new_masking_status(self.get_cpv()) + if status != None: # we have locally changed it + if status == "masked": return True + elif status == "unmasked": return False + else: + error(_("BUG in flags.new_masking_status. It returns \'%s\'"), status) + else: # we have not touched the status + return self._status and ("profile" in self._status or "package.mask" in self._status) + + else: # we want the original portage value XXX: bug if masked by user AND by system + + # get the normal masked ones + if self._status and ("profile" in self._status or "package.mask" in self._status): + return not flags.is_locally_masked(self, changes = False) # assume that if it is locally masked, it is not masked by the system + else: # more difficult: get the ones we unmasked, but are masked by the system + try: + masked = self._settings.settings.pmaskdict[self.get_cp()] + except KeyError: # key error: not masked + return False + + for cpv in masked: + if self.matches(cpv): + return not flags.is_locally_masked(self, changes = False) # assume that if it is locally masked, it is not masked by the system + + return False + + def get_masking_reason(self): + reason = portage.getmaskingreason(self.get_cpv(), settings = self._settings.settings) + + if reason: + return reason.strip() + else: + return reason + + def get_iuse_flags (self, installed = False, removeForced = True): + if not self.is_in_system(): + installed = True + + iuse = flags.filter_defaults(self.get_package_settings("IUSE", installed = installed).split()) + + iuse = set(iuse) + + if removeForced: + return list(iuse.difference(self.forced_flags)) + else: + return list(iuse) + + def get_matched_dep_packages (self, depvar): + # change the useflags, because we have internally changed some, but not made them visible for portage + actual = self.get_actual_use_flags() + + depstring = "" + try: + for d in depvar: + depstring += self.get_package_settings(d, installed = False)+" " + except KeyError: # not found in porttree - use vartree + depstring = "" + for d in depvar: + depstring += self.get_package_settings(d, installed = True)+" " + + deps = portage.dep_check(depstring, None, self._settings.settings, myuse = actual, trees = self._trees) + + if not deps: # FIXME: what is the difference to [1, []] ? + return [] + + if deps[0] == 0: # error + raise DependencyCalcError, deps[1] + + deps = deps[1] + + return [d for d in deps if d[0] != "!"] + + def get_dep_packages (self, depvar = ["RDEPEND", "PDEPEND", "DEPEND"], with_criterions = False, return_blocks = False): + dep_pkgs = [] # the package list + + # change the useflags, because we have internally changed some, but not made them visible for portage + actual = self.get_actual_use_flags() + + depstring = "" + for d in depvar: + depstring += self.get_package_settings(d, installed = False)+" " + + # let portage do the main stuff ;) + # pay attention to any changes here + deps = portage.dep_check (depstring, self._settings.vartree.dbapi, self._settings.settings, myuse = actual, trees = self._trees) + + if not deps: # FIXME: what is the difference to [1, []] ? + return [] + + if deps[0] == 0: # error + raise DependencyCalcError, deps[1] + + deps = deps[1] + + def create_dep_pkgs_data (dep, pkg): + """Returns the data to enter into the dep_pkgs list, which is either the package cpv or a tuple + consisting of the cpv and the criterion.""" + if with_criterions: + return (pkg.get_cpv(), dep) + else: + return pkg.get_cpv() + + for dep in deps: + if dep[0] == '!': # blocking sth + blocked = system.find_packages(dep, system.SET_INSTALLED) + if len(blocked) == 1: # only exact one match allowed to be harmless + if blocked[0].get_slot_cp() == self.get_slot_cp(): # blocks in the same slot are harmless + continue + + if return_blocks: + if with_criterions: + dep_pkgs.append((dep, dep)) + else: + dep_pkgs.append(dep) + else: + raise BlockedException, (self.get_cpv(), blocked[0].get_cpv()) + + continue # finished with the blocking one -> next + + pkg = system.find_best_match(dep) + if not pkg: # try to find masked ones + pkgs = system.find_packages(dep, masked = True) + if not pkgs: + raise PackageNotFoundException, dep + + pkgs = system.sort_package_list(pkgs) + pkgs.reverse() + done = False + for p in pkgs: + if not p.is_masked(): + dep_pkgs.append(create_dep_pkgs_data(dep, p)) + done = True + break + if not done: + dep_pkgs.append(create_dep_pkgs_data(dep, pkgs[0])) + else: + dep_pkgs.append(create_dep_pkgs_data(dep, pkg)) + + return dep_pkgs + + def get_global_settings(self, key, installed = True): + with self._settingslock: + self._init_settings(installed) + v = self._settings.settings[key] + + return v + + def get_ebuild_path(self): + if self.is_in_system(): + return self._settings.porttree.dbapi.findname(self._cpv) + else: + return self._settings.vartree.dbapi.findname(self._cpv) + + def get_files (self): + if self.is_installed(): + path = os.path.join(self.get_global_settings("ROOT"), portage.VDB_PATH, self.get_cpv(), "CONTENTS") + with open(path) as f: + for line in f: + yield line.split()[1].strip() + + def get_package_settings(self, var, installed = True): + if installed and self.is_installed(): + mytree = self._settings.vartree + else: + mytree = self._settings.porttree + + r = mytree.dbapi.aux_get(self._cpv,[var]) + + return r[0] + + def get_installed_use_flags(self): + if self.is_installed(): + return self.get_package_settings("USE", installed = True).split() + else: return [] + + def compare_version(self,other): + v1 = self._scpv + v2 = portage.catpkgsplit(other.get_cpv()) + # if category is different + if v1[0] != v2[0]: + return cmp(v1[0],v2[0]) + # if name is different + elif v1[1] != v2[1]: + return cmp(v1[1],v2[1]) + # Compare versions + else: + return portage.pkgcmp(v1[1:],v2[1:]) + + def matches (self, criterion): + return system.cpv_matches(self.get_cpv(), criterion) diff --git a/portato/backend/portage/package_22.py b/portato/backend/portage/package_22.py index 4fe03d9..1dae1fe 100644 --- a/portato/backend/portage/package_22.py +++ b/portato/backend/portage/package_22.py @@ -15,8 +15,8 @@ from __future__ import absolute_import, with_statement from .package import PortagePackage class PortagePackage_22 (PortagePackage): - """ - The 2.2 specialization of the portage package. - Currently this is identical to the normal one. - """ - pass + """ + The 2.2 specialization of the portage package. + Currently this is identical to the normal one. + """ + pass diff --git a/portato/backend/portage/sets.py b/portato/backend/portage/sets.py index 24ceaca..8d8ef28 100644 --- a/portato/backend/portage/sets.py +++ b/portato/backend/portage/sets.py @@ -17,130 +17,130 @@ import itertools as itt import portage try: - import portage.dep as portage_dep + import portage.dep as portage_dep except ImportError: - import portage_dep + import portage_dep from .. import system from ...helper import debug class Set(object): - def get_pkgs(self, key, is_regexp, masked, with_version, only_cpv): - raise NotImplementedError + def get_pkgs(self, key, is_regexp, masked, with_version, only_cpv): + raise NotImplementedError - def find (self, key, masked = False, with_version = True, only_cpv = False): - if key is None: key = "" - - is_regexp = key == "" or ("*" in key and key[0] not in ("*","=","<",">","~","!")) + def find (self, key, masked = False, with_version = True, only_cpv = False): + if key is None: key = "" + + is_regexp = key == "" or ("*" in key and key[0] not in ("*","=","<",">","~","!")) - try: - t = self.get_pkgs(key, is_regexp, masked, with_version, only_cpv) - # catch the "ambigous package" Exception - except ValueError, e: - if isinstance(e[0], list): - t = set() - for cp in e[0]: - t.update(self.get_pkgs(cp, is_regexp, masked, with_version, only_cpv)) - else: - raise + try: + t = self.get_pkgs(key, is_regexp, masked, with_version, only_cpv) + # catch the "ambigous package" Exception + except ValueError, e: + if isinstance(e[0], list): + t = set() + for cp in e[0]: + t.update(self.get_pkgs(cp, is_regexp, masked, with_version, only_cpv)) + else: + raise - return t + return t class FilterSet (Set): - def get_list(self): - raise NotImplementedError - - def get_pkgs (self, key, is_regexp, masked, with_version, only_cpv): - t = set() - for pkg in self.get_list(): - if is_regexp: - if not re.match(key, pkg, re.I): continue + def get_list(self): + raise NotImplementedError + + def get_pkgs (self, key, is_regexp, masked, with_version, only_cpv): + t = set() + for pkg in self.get_list(): + if is_regexp: + if not re.match(key, pkg, re.I): continue - if not with_version: - t.add(portage_dep.dep_getkey(pkg)) - - t.add(system.find_best_match(pkg, only_cpv = True)) + if not with_version: + t.add(portage_dep.dep_getkey(pkg)) + + t.add(system.find_best_match(pkg, only_cpv = True)) - return t + return t class PortageSet (FilterSet): - def __init__ (self, name): - FilterSet.__init__(self) - debug("Loading portage set '%s'", name) - self.portageSet = system.settings.setsconfig.getSets()[name] + def __init__ (self, name): + FilterSet.__init__(self) + debug("Loading portage set '%s'", name) + self.portageSet = system.settings.setsconfig.getSets()[name] - def get_list(self): - return itt.imap(str, self.portageSet.getAtoms()) + def get_list(self): + return itt.imap(str, self.portageSet.getAtoms()) class SystemSet (FilterSet): - def get_list(self): - for cp in system.settings.settings.packages: - if cp[0] == "*": yield cp[1:] + def get_list(self): + for cp in system.settings.settings.packages: + if cp[0] == "*": yield cp[1:] class WorldSet (FilterSet): - def get_list(self): - with open(portage.WORLD_FILE) as f: - for cp in f: - cp = cp.strip() - if cp and cp[0] != "#": - yield cp + def get_list(self): + with open(portage.WORLD_FILE) as f: + for cp in f: + cp = cp.strip() + if cp and cp[0] != "#": + yield cp class InstalledSet (Set): - def get_pkgs (self, key, is_regexp, masked, with_version, only_cpv): - if is_regexp: - if with_version: - t = system.settings.vartree.dbapi.cpv_all() - else: - t = system.settings.vartree.dbapi.cp_all() + def get_pkgs (self, key, is_regexp, masked, with_version, only_cpv): + if is_regexp: + if with_version: + t = system.settings.vartree.dbapi.cpv_all() + else: + t = system.settings.vartree.dbapi.cp_all() - if key: - t = filter(lambda x: re.match(key, x, re.I), t) + if key: + t = filter(lambda x: re.match(key, x, re.I), t) - return set(t) - else: - return set(system.settings.vartree.dbapi.match(key)) + return set(t) + else: + return set(system.settings.vartree.dbapi.match(key)) class TreeSet (Set): - def get_pkgs (self, key, is_regexp, masked, with_version, only_cpv): - if is_regexp: - if with_version: - t = system.settings.porttree.dbapi.cpv_all() - else: - t = system.settings.porttree.dbapi.cp_all() + def get_pkgs (self, key, is_regexp, masked, with_version, only_cpv): + if is_regexp: + if with_version: + t = system.settings.porttree.dbapi.cpv_all() + else: + t = system.settings.porttree.dbapi.cp_all() - if key: - t = filter(lambda x: re.match(key, x, re.I), t) + if key: + t = filter(lambda x: re.match(key, x, re.I), t) - elif masked: - t = system.settings.porttree.dbapi.xmatch("match-all", key) - else: - t = system.settings.porttree.dbapi.match(key) + elif masked: + t = system.settings.porttree.dbapi.xmatch("match-all", key) + else: + t = system.settings.porttree.dbapi.match(key) - return set(t) + return set(t) class AllSet (Set): - - def __init__ (self): - Set.__init__(self) - self.tree = TreeSet() - self.installed = InstalledSet() + + def __init__ (self): + Set.__init__(self) + self.tree = TreeSet() + self.installed = InstalledSet() - def find (self, *args, **kwargs): - return self.tree.find(*args, **kwargs) | self.installed.find(*args, **kwargs) + def find (self, *args, **kwargs): + return self.tree.find(*args, **kwargs) | self.installed.find(*args, **kwargs) class UninstalledSet (Set): - def __init__ (self): - Set.__init__(self) - self.all = AllSet() - self.installed = InstalledSet() + def __init__ (self): + Set.__init__(self) + self.all = AllSet() + self.installed = InstalledSet() - def find (self, *args, **kwargs): - return self.all.find(*args, **kwargs) - self.installed.find(*args, **kwargs) + def find (self, *args, **kwargs): + return self.all.find(*args, **kwargs) - self.installed.find(*args, **kwargs) diff --git a/portato/backend/portage/settings.py b/portato/backend/portage/settings.py index 5d466ad..0e7eccb 100644 --- a/portato/backend/portage/settings.py +++ b/portato/backend/portage/settings.py @@ -17,42 +17,42 @@ import portage from threading import Lock class PortageSettings: - """Encapsulation of the portage settings. - - @ivar settings: portage settings - @ivar settingslock: a simple Lock - @ivar trees: a dictionary of the trees - @ivar porttree: shortcut to C{trees[root]["porttree"]} - @ivar vartree: shortcut to C{trees[root]["vartree"]} - @ivar virtuals: shortcut to C{trees[root]["virtuals"]}""" - - def __init__ (self): - """Initializes the instance. Calls L{load()}.""" - self.settingslock = Lock() - self.trees = None - self.load() - - def load(self): - """(Re)loads the portage settings and sets the variables.""" - - kwargs = {} - for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")): - kwargs[k] = os.environ.get(envvar, None) - self.trees = portage.create_trees(trees=self.trees, **kwargs) - - self.settings = self.trees["/"]["vartree"].settings - - for myroot in self.trees: - if myroot != "/": - self.settings = self.trees[myroot]["vartree"].settings - break - - self.settings.unlock() - - root = self.settings["ROOT"] - - self.porttree = self.trees[root]["porttree"] - self.vartree = self.trees[root]["vartree"] - self.virtuals = self.trees[root]["virtuals"] - - portage.settings = None # we use our own one ... + """Encapsulation of the portage settings. + + @ivar settings: portage settings + @ivar settingslock: a simple Lock + @ivar trees: a dictionary of the trees + @ivar porttree: shortcut to C{trees[root]["porttree"]} + @ivar vartree: shortcut to C{trees[root]["vartree"]} + @ivar virtuals: shortcut to C{trees[root]["virtuals"]}""" + + def __init__ (self): + """Initializes the instance. Calls L{load()}.""" + self.settingslock = Lock() + self.trees = None + self.load() + + def load(self): + """(Re)loads the portage settings and sets the variables.""" + + kwargs = {} + for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")): + kwargs[k] = os.environ.get(envvar, None) + self.trees = portage.create_trees(trees=self.trees, **kwargs) + + self.settings = self.trees["/"]["vartree"].settings + + for myroot in self.trees: + if myroot != "/": + self.settings = self.trees[myroot]["vartree"].settings + break + + self.settings.unlock() + + root = self.settings["ROOT"] + + self.porttree = self.trees[root]["porttree"] + self.vartree = self.trees[root]["vartree"] + self.virtuals = self.trees[root]["virtuals"] + + portage.settings = None # we use our own one ... diff --git a/portato/backend/portage/settings_22.py b/portato/backend/portage/settings_22.py index a43d69e..5274b3b 100644 --- a/portato/backend/portage/settings_22.py +++ b/portato/backend/portage/settings_22.py @@ -16,12 +16,12 @@ import portage.sets from .settings import PortageSettings class PortageSettings_22 (PortageSettings): - """Enhances the normal PortageSettings in ways, that it adds the setsconfig.""" + """Enhances the normal PortageSettings in ways, that it adds the setsconfig.""" - def __init__ (self): - PortageSettings.__init__(self) + def __init__ (self): + PortageSettings.__init__(self) - def load (self): - PortageSettings.load(self) + def load (self): + PortageSettings.load(self) - self.setsconfig = portage.sets.load_default_config(self.settings, self.trees[self.settings["ROOT"]]) + self.setsconfig = portage.sets.load_default_config(self.settings, self.trees[self.settings["ROOT"]]) diff --git a/portato/backend/portage/system.py b/portato/backend/portage/system.py index 2394a10..e81951e 100644 --- a/portato/backend/portage/system.py +++ b/portato/backend/portage/system.py @@ -15,9 +15,9 @@ from __future__ import absolute_import, with_statement import re, os, os.path import portage try: - import portage.dep as portage_dep + import portage.dep as portage_dep except ImportError: - import portage_dep + import portage_dep from collections import defaultdict import itertools as itt @@ -30,386 +30,386 @@ from ..system_interface import SystemInterface from ...helper import debug, info, warning, unique_array class PortageSystem (SystemInterface): - """This class provides access to the portage-system.""" - - # pre-compile the RE removing the ".svn" and "CVS" entries - unwantedPkgsRE = re.compile(r".*(\.svn|CVS)$") - withBdepsRE = re.compile(r"--with-bdeps\s*( |=)\s*y") + """This class provides access to the portage-system.""" + + # pre-compile the RE removing the ".svn" and "CVS" entries + unwantedPkgsRE = re.compile(r".*(\.svn|CVS)$") + withBdepsRE = re.compile(r"--with-bdeps\s*( |=)\s*y") - def __init__ (self): - """Constructor.""" - self.settings = PortageSettings() - portage.WORLD_FILE = os.path.join(self.settings.settings["ROOT"],portage.WORLD_FILE) - - self.use_descs = {} - self.local_use_descs = defaultdict(dict) - - self.setmap = { - self.SET_ALL : syssets.AllSet, - self.SET_INSTALLED : syssets.InstalledSet, - self.SET_UNINSTALLED : syssets.UninstalledSet, - self.SET_TREE : syssets.TreeSet, - "world" : syssets.WorldSet, - "system" : syssets.SystemSet - } - - def has_set_support (self): - return False - - def get_sets (self, description = False): - if description: - return (("world", "The world set."), ("system", "The system set.")) - else: - return ("world", "system") - - def get_version (self): - return "Portage %s" % portage.VERSION - - def new_package (self, cpv): - return PortagePackage(cpv) - - def get_config_path (self): - return portage.USER_CONFIG_PATH - - def get_merge_command (self): - return ["/usr/bin/python", "/usr/bin/emerge"] - - def get_sync_command (self): - return self.get_merge_command()+["--sync"] - - def get_oneshot_option (self): - return ["--oneshot"] - - def get_newuse_option (self): - return ["--newuse"] - - def get_deep_option (self): - return ["--deep"] - - def get_update_option (self): - return ["--update"] - - def get_pretend_option (self): - return ["--pretend", "--verbose"] - - def get_unmerge_option (self): - return ["--unmerge"] - - def get_environment (self): - default_opts = self.get_global_settings("EMERGE_DEFAULT_OPTS") - opts = dict(os.environ) - opts.update(TERM = "xterm") # emulate terminal :) - opts.update(PAGER = "less") # force less - - if default_opts: - opt_list = default_opts.split() - changed = False - - for option in ["--ask", "-a", "--pretend", "-p"]: - if option in opt_list: - opt_list.remove(option) - changed = True - - if changed: - opts.update(EMERGE_DEFAULT_OPTS = " ".join(opt_list)) - - return opts - - def cpv_matches (self, cpv, criterion): - if portage.match_from_list(criterion, [cpv]) == []: - return False - else: - return True - - def with_bdeps(self): - """Returns whether the "--with-bdeps" option is set to true. - - @returns: the value of --with-bdeps - @rtype: boolean - """ - - settings = self.get_global_settings("EMERGE_DEFAULT_OPTS").split() - for s in settings: - if self.withBdepsRE.match(s): - return True - - return False - - def find_lambda (self, 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 or RE - @returns: - 1. None if no name is given - 2. a lambda function - @rtype: function - """ - - if name != None: - if isinstance(name, str): - return lambda x: re.match(".*"+name+".*",x, re.I) - else: # assume regular expression - return lambda x: name.match(x) - else: - return lambda x: True - - def geneticize_list (self, list_of_packages, only_cpv = False): - """Convertes a list of cpv's into L{backend.Package}s. - - @param list_of_packages: the list of packages - @type list_of_packages: string[] - @param only_cpv: do nothing - return the passed list - @type only_cpv: boolean - @returns: converted list - @rtype: PortagePackage[] - """ - - if not only_cpv: - return [self.new_package(x) for x in list_of_packages] - elif not isinstance(list_of_packages, list): - return list(list_of_packages) - else: - return list_of_packages - - def get_global_settings (self, key): - self.settings.settings.reset() - return self.settings.settings[key] - - def find_best (self, list, only_cpv = False): - if only_cpv: - return portage.best(list) - else: - return self.new_package(portage.best(list)) - - def find_best_match (self, search_key, masked = False, only_installed = False, only_cpv = False): - t = [] - - if not only_installed: - pkgSet = self.SET_TREE - else: - pkgSet = self.SET_INSTALLED - - t = self.find_packages(search_key, pkgSet = pkgSet, masked = masked, with_version = True, only_cpv = True) - - if VERSION >= (2,1,5): - t += [pkg.get_cpv() for pkg in self.find_packages(search_key, self.SET_INSTALLED) if not (pkg.is_testing(True) or pkg.is_masked())] - elif not only_installed: # no need to run twice - t += self.find_packages(search_key, self.SET_INSTALLED, only_cpv=True) - - if t: - t = unique_array(t) - return self.find_best(t, only_cpv) - - return None - - def _get_set (self, pkgSet): - pkgSet = pkgSet.lower() - if pkgSet == "": pkgSet = self.SET_ALL - - return self.setmap[pkgSet]() - - def find_packages (self, key = "", pkgSet = SystemInterface.SET_ALL, masked = False, with_version = True, only_cpv = False): - return self.geneticize_list(self._get_set(pkgSet).find(key, masked, with_version, only_cpv), only_cpv or not with_version) - - def list_categories (self, name = None): - categories = self.settings.settings.categories - return filter(self.find_lambda(name), categories) - - def split_cpv (self, cpv): - cpv = portage.dep_getcpv(cpv) - return portage.catpkgsplit(cpv) - - def sort_package_list(self, pkglist): - pkglist.sort(PortagePackage.compare_version) # XXX: waaah ... direct package naming... =/ - return pkglist - - def reload_settings (self): - self.settings.load() - - def get_new_packages (self, packages): - """Gets a list of packages and returns the best choice for each in the portage tree. - - @param packages: the list of packages - @type packages: string[] - @returns: the list of packages - @rtype: backend.Package[] - """ - - new_packages = [] - - def append(crit, best, inst): - if not best: - return - - if not best.is_installed() and (best.is_masked() or best.is_testing(True)): # check to not update unnecessairily - for i in inst: - if i.matches(crit): - debug("The installed %s matches %s. Discarding upgrade to masked version.", i.get_cpv(), crit) - return - - new_packages.append(best) - - for p in packages: - inst = self.find_packages(p, self.SET_INSTALLED) - - best_p = self.find_best_match(p) - if best_p is None: - best_p = self.find_best_match(p, masked = True) - if best_p is None: - warning(_("No best match for %s. It seems not to be in the tree anymore.") % p) - continue - else: - debug("Best match for %s is masked" % p) - - if len(inst) > 1: - myslots = set() - for i in inst: # get the slots of the installed packages - myslots.add(i.get_package_settings("SLOT")) - - myslots.add(best_p.get_package_settings("SLOT")) # add the slot of the best package in portage - for slot in myslots: - crit = "%s:%s" % (p, slot) - append(crit, self.find_best_match(crit), inst) - else: - append(p, best_p, inst) - - return new_packages - - def get_updated_packages (self): - packages = self.get_new_packages(self.find_packages(pkgSet = self.SET_INSTALLED, with_version = False)) - packages = [x for x in packages if x is not None and not x.is_installed()] - return packages - - def update_world (self, sets = ("world", "system"), newuse = False, deep = False): - packages = set() - map(packages.add, itt.chain(*[self.find_packages(pkgSet = s, with_version = False) for s in sets])) - - states = [(["RDEPEND", "PDEPEND"], True)] - if self.with_bdeps(): - states.append((["DEPEND"], True)) - - checked = [] - updating = [] - raw_checked = {} - def check (p, add_not_installed = True, prev_appended = False): - """Checks whether a package is updated or not.""" - - if p.get_slot_cp() in checked: - return - else: - if (not p.is_installed()) and (not add_not_installed): - # don't add these packages to checked as we may see them again - # - and then we might have add_not_installed being True - return - else: - checked.append(p.get_slot_cp()) - - appended = False - tempDeep = False - - if not p.is_installed(): - oldList = self.find_packages(p.get_slot_cp(), self.SET_INSTALLED) - if oldList: - old = oldList[0] # we should only have one package here - else it is a bug - else: - oldList = self.sort_package_list(self.find_packages(p.get_cp(), self.SET_INSTALLED)) - if not oldList: - info(_("Found a not installed dependency: %s.") % p.get_cpv()) - oldList = [p] - - old = oldList[-1] - - updating.append((p, old)) - appended = True - p = old - - if newuse and p.is_installed() and p.is_in_system(): # there is no use to check newuse for a package which is not existing in portage anymore :) - - new_iuse = set(p.get_iuse_flags(installed = False)) # IUSE in the ebuild - old_iuse = set(p.get_iuse_flags(installed = True)) # IUSE in the vardb - - # add forced flags, as they might trigger a rebuild - new_iuse_f = set(p.get_iuse_flags(installed = False, removeForced = False)) - old_iuse_f = set(p.get_iuse_flags(installed = True, removeForced = False)) - - if new_iuse.symmetric_difference(old_iuse): # difference between IUSE (w/o forced) - tempDeep = True - if not appended: - updating.append((p,p)) - appended = True - - else: # check for difference between the _set_ useflags (w/ forced) - if new_iuse_f.intersection(p.get_actual_use_flags()).symmetric_difference(old_iuse_f.intersection(p.get_installed_use_flags())): - tempDeep = True - if not appended: - updating.append((p,p)) - appended = True - - if deep or tempDeep: - if (appended or prev_appended) and len(states) < 2: - real_states = states + [("PDEPEND", True), ("DEPEND", False)] - else: - real_states = states - for state in real_states: - for i in p.get_matched_dep_packages(state[0]): - if i not in raw_checked or raw_checked[i] == False: - raw_checked.update({i : state[1]}) - bm = self.get_new_packages([i]) - if not bm: - warning(_("Bug? No best match could be found for '%(package)s'. Needed by: '%(cpv)s'."), {"package" : i, "cpv": p.get_cpv()}) - else: - for pkg in bm: - if not pkg: continue - check(pkg, state[1], appended) # XXX: should be 'or'ed with prev_appended? - - for p in self.get_new_packages(packages): - if not p: continue # if a masked package is installed we have "None" here - check(p, True) - - return updating - - def get_use_desc (self, flag, package = None): - # In the first run the dictionaries 'use_descs' and 'local_use_descs' are filled. - - # fill cache if needed - if not self.use_descs and not self.local_use_descs: - for dir in [self.settings.settings["PORTDIR"]] + self.settings.settings["PORTDIR_OVERLAY"].split(): - - # read use.desc - try: - f = open(os.path.join(dir, "profiles/use.desc")) - for line in f: - line = line.strip() - if line and line[0] != '#': - fields = [x.strip() for x in line.split(" - ",1)] - if len(fields) == 2: - self.use_descs[fields[0]] = fields[1] - except IOError: - pass - finally: - f.close() - - # read use.local.desc - try: - f = open(os.path.join(dir, "profiles/use.local.desc")) - for line in f: - line = line.strip() - if line and line[0] != '#': - fields = [x.strip() for x in line.split(":",1)] - if len(fields) == 2: - subfields = [x.strip() for x in fields[1].split(" - ",1)] - if len(subfields) == 2: - self.local_use_descs[fields[0]].update([subfields]) - except IOError: - pass - finally: - f.close() - - # start - desc = self.use_descs.get(flag, "") - if package is not None: - if package in self.local_use_descs: - desc = self.local_use_descs[package].get(flag, desc) - - return desc + def __init__ (self): + """Constructor.""" + self.settings = PortageSettings() + portage.WORLD_FILE = os.path.join(self.settings.settings["ROOT"],portage.WORLD_FILE) + + self.use_descs = {} + self.local_use_descs = defaultdict(dict) + + self.setmap = { + self.SET_ALL : syssets.AllSet, + self.SET_INSTALLED : syssets.InstalledSet, + self.SET_UNINSTALLED : syssets.UninstalledSet, + self.SET_TREE : syssets.TreeSet, + "world" : syssets.WorldSet, + "system" : syssets.SystemSet + } + + def has_set_support (self): + return False + + def get_sets (self, description = False): + if description: + return (("world", "The world set."), ("system", "The system set.")) + else: + return ("world", "system") + + def get_version (self): + return "Portage %s" % portage.VERSION + + def new_package (self, cpv): + return PortagePackage(cpv) + + def get_config_path (self): + return portage.USER_CONFIG_PATH + + def get_merge_command (self): + return ["/usr/bin/python", "/usr/bin/emerge"] + + def get_sync_command (self): + return self.get_merge_command()+["--sync"] + + def get_oneshot_option (self): + return ["--oneshot"] + + def get_newuse_option (self): + return ["--newuse"] + + def get_deep_option (self): + return ["--deep"] + + def get_update_option (self): + return ["--update"] + + def get_pretend_option (self): + return ["--pretend", "--verbose"] + + def get_unmerge_option (self): + return ["--unmerge"] + + def get_environment (self): + default_opts = self.get_global_settings("EMERGE_DEFAULT_OPTS") + opts = dict(os.environ) + opts.update(TERM = "xterm") # emulate terminal :) + opts.update(PAGER = "less") # force less + + if default_opts: + opt_list = default_opts.split() + changed = False + + for option in ["--ask", "-a", "--pretend", "-p"]: + if option in opt_list: + opt_list.remove(option) + changed = True + + if changed: + opts.update(EMERGE_DEFAULT_OPTS = " ".join(opt_list)) + + return opts + + def cpv_matches (self, cpv, criterion): + if portage.match_from_list(criterion, [cpv]) == []: + return False + else: + return True + + def with_bdeps(self): + """Returns whether the "--with-bdeps" option is set to true. + + @returns: the value of --with-bdeps + @rtype: boolean + """ + + settings = self.get_global_settings("EMERGE_DEFAULT_OPTS").split() + for s in settings: + if self.withBdepsRE.match(s): + return True + + return False + + def find_lambda (self, 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 or RE + @returns: + 1. None if no name is given + 2. a lambda function + @rtype: function + """ + + if name != None: + if isinstance(name, str): + return lambda x: re.match(".*"+name+".*",x, re.I) + else: # assume regular expression + return lambda x: name.match(x) + else: + return lambda x: True + + def geneticize_list (self, list_of_packages, only_cpv = False): + """Convertes a list of cpv's into L{backend.Package}s. + + @param list_of_packages: the list of packages + @type list_of_packages: string[] + @param only_cpv: do nothing - return the passed list + @type only_cpv: boolean + @returns: converted list + @rtype: PortagePackage[] + """ + + if not only_cpv: + return [self.new_package(x) for x in list_of_packages] + elif not isinstance(list_of_packages, list): + return list(list_of_packages) + else: + return list_of_packages + + def get_global_settings (self, key): + self.settings.settings.reset() + return self.settings.settings[key] + + def find_best (self, list, only_cpv = False): + if only_cpv: + return portage.best(list) + else: + return self.new_package(portage.best(list)) + + def find_best_match (self, search_key, masked = False, only_installed = False, only_cpv = False): + t = [] + + if not only_installed: + pkgSet = self.SET_TREE + else: + pkgSet = self.SET_INSTALLED + + t = self.find_packages(search_key, pkgSet = pkgSet, masked = masked, with_version = True, only_cpv = True) + + if VERSION >= (2,1,5): + t += [pkg.get_cpv() for pkg in self.find_packages(search_key, self.SET_INSTALLED) if not (pkg.is_testing(True) or pkg.is_masked())] + elif not only_installed: # no need to run twice + t += self.find_packages(search_key, self.SET_INSTALLED, only_cpv=True) + + if t: + t = unique_array(t) + return self.find_best(t, only_cpv) + + return None + + def _get_set (self, pkgSet): + pkgSet = pkgSet.lower() + if pkgSet == "": pkgSet = self.SET_ALL + + return self.setmap[pkgSet]() + + def find_packages (self, key = "", pkgSet = SystemInterface.SET_ALL, masked = False, with_version = True, only_cpv = False): + return self.geneticize_list(self._get_set(pkgSet).find(key, masked, with_version, only_cpv), only_cpv or not with_version) + + def list_categories (self, name = None): + categories = self.settings.settings.categories + return filter(self.find_lambda(name), categories) + + def split_cpv (self, cpv): + cpv = portage.dep_getcpv(cpv) + return portage.catpkgsplit(cpv) + + def sort_package_list(self, pkglist): + pkglist.sort(PortagePackage.compare_version) # XXX: waaah ... direct package naming... =/ + return pkglist + + def reload_settings (self): + self.settings.load() + + def get_new_packages (self, packages): + """Gets a list of packages and returns the best choice for each in the portage tree. + + @param packages: the list of packages + @type packages: string[] + @returns: the list of packages + @rtype: backend.Package[] + """ + + new_packages = [] + + def append(crit, best, inst): + if not best: + return + + if not best.is_installed() and (best.is_masked() or best.is_testing(True)): # check to not update unnecessairily + for i in inst: + if i.matches(crit): + debug("The installed %s matches %s. Discarding upgrade to masked version.", i.get_cpv(), crit) + return + + new_packages.append(best) + + for p in packages: + inst = self.find_packages(p, self.SET_INSTALLED) + + best_p = self.find_best_match(p) + if best_p is None: + best_p = self.find_best_match(p, masked = True) + if best_p is None: + warning(_("No best match for %s. It seems not to be in the tree anymore.") % p) + continue + else: + debug("Best match for %s is masked" % p) + + if len(inst) > 1: + myslots = set() + for i in inst: # get the slots of the installed packages + myslots.add(i.get_package_settings("SLOT")) + + myslots.add(best_p.get_package_settings("SLOT")) # add the slot of the best package in portage + for slot in myslots: + crit = "%s:%s" % (p, slot) + append(crit, self.find_best_match(crit), inst) + else: + append(p, best_p, inst) + + return new_packages + + def get_updated_packages (self): + packages = self.get_new_packages(self.find_packages(pkgSet = self.SET_INSTALLED, with_version = False)) + packages = [x for x in packages if x is not None and not x.is_installed()] + return packages + + def update_world (self, sets = ("world", "system"), newuse = False, deep = False): + packages = set() + map(packages.add, itt.chain(*[self.find_packages(pkgSet = s, with_version = False) for s in sets])) + + states = [(["RDEPEND", "PDEPEND"], True)] + if self.with_bdeps(): + states.append((["DEPEND"], True)) + + checked = [] + updating = [] + raw_checked = {} + def check (p, add_not_installed = True, prev_appended = False): + """Checks whether a package is updated or not.""" + + if p.get_slot_cp() in checked: + return + else: + if (not p.is_installed()) and (not add_not_installed): + # don't add these packages to checked as we may see them again + # - and then we might have add_not_installed being True + return + else: + checked.append(p.get_slot_cp()) + + appended = False + tempDeep = False + + if not p.is_installed(): + oldList = self.find_packages(p.get_slot_cp(), self.SET_INSTALLED) + if oldList: + old = oldList[0] # we should only have one package here - else it is a bug + else: + oldList = self.sort_package_list(self.find_packages(p.get_cp(), self.SET_INSTALLED)) + if not oldList: + info(_("Found a not installed dependency: %s.") % p.get_cpv()) + oldList = [p] + + old = oldList[-1] + + updating.append((p, old)) + appended = True + p = old + + if newuse and p.is_installed() and p.is_in_system(): # there is no use to check newuse for a package which is not existing in portage anymore :) + + new_iuse = set(p.get_iuse_flags(installed = False)) # IUSE in the ebuild + old_iuse = set(p.get_iuse_flags(installed = True)) # IUSE in the vardb + + # add forced flags, as they might trigger a rebuild + new_iuse_f = set(p.get_iuse_flags(installed = False, removeForced = False)) + old_iuse_f = set(p.get_iuse_flags(installed = True, removeForced = False)) + + if new_iuse.symmetric_difference(old_iuse): # difference between IUSE (w/o forced) + tempDeep = True + if not appended: + updating.append((p,p)) + appended = True + + else: # check for difference between the _set_ useflags (w/ forced) + if new_iuse_f.intersection(p.get_actual_use_flags()).symmetric_difference(old_iuse_f.intersection(p.get_installed_use_flags())): + tempDeep = True + if not appended: + updating.append((p,p)) + appended = True + + if deep or tempDeep: + if (appended or prev_appended) and len(states) < 2: + real_states = states + [("PDEPEND", True), ("DEPEND", False)] + else: + real_states = states + for state in real_states: + for i in p.get_matched_dep_packages(state[0]): + if i not in raw_checked or raw_checked[i] == False: + raw_checked.update({i : state[1]}) + bm = self.get_new_packages([i]) + if not bm: + warning(_("Bug? No best match could be found for '%(package)s'. Needed by: '%(cpv)s'."), {"package" : i, "cpv": p.get_cpv()}) + else: + for pkg in bm: + if not pkg: continue + check(pkg, state[1], appended) # XXX: should be 'or'ed with prev_appended? + + for p in self.get_new_packages(packages): + if not p: continue # if a masked package is installed we have "None" here + check(p, True) + + return updating + + def get_use_desc (self, flag, package = None): + # In the first run the dictionaries 'use_descs' and 'local_use_descs' are filled. + + # fill cache if needed + if not self.use_descs and not self.local_use_descs: + for dir in [self.settings.settings["PORTDIR"]] + self.settings.settings["PORTDIR_OVERLAY"].split(): + + # read use.desc + try: + f = open(os.path.join(dir, "profiles/use.desc")) + for line in f: + line = line.strip() + if line and line[0] != '#': + fields = [x.strip() for x in line.split(" - ",1)] + if len(fields) == 2: + self.use_descs[fields[0]] = fields[1] + except IOError: + pass + finally: + f.close() + + # read use.local.desc + try: + f = open(os.path.join(dir, "profiles/use.local.desc")) + for line in f: + line = line.strip() + if line and line[0] != '#': + fields = [x.strip() for x in line.split(":",1)] + if len(fields) == 2: + subfields = [x.strip() for x in fields[1].split(" - ",1)] + if len(subfields) == 2: + self.local_use_descs[fields[0]].update([subfields]) + except IOError: + pass + finally: + f.close() + + # start + desc = self.use_descs.get(flag, "") + if package is not None: + if package in self.local_use_descs: + desc = self.local_use_descs[package].get(flag, desc) + + return desc diff --git a/portato/backend/portage/system_22.py b/portato/backend/portage/system_22.py index a329ab0..d5b605f 100644 --- a/portato/backend/portage/system_22.py +++ b/portato/backend/portage/system_22.py @@ -24,41 +24,41 @@ from . import sets as syssets class PortageSystem_22 (PortageSystem): - def __init__ (self): - self.settings = PortageSettings_22() - portage.WORLD_FILE = os.path.join(self.settings.settings["ROOT"],portage.WORLD_FILE) + def __init__ (self): + self.settings = PortageSettings_22() + portage.WORLD_FILE = os.path.join(self.settings.settings["ROOT"],portage.WORLD_FILE) - self.use_descs = {} - self.local_use_descs = defaultdict(dict) + self.use_descs = {} + self.local_use_descs = defaultdict(dict) - self.setmap = { - self.SET_ALL : syssets.AllSet, - self.SET_INSTALLED : syssets.InstalledSet, - self.SET_UNINSTALLED : syssets.UninstalledSet, - self.SET_TREE : syssets.TreeSet - } + self.setmap = { + self.SET_ALL : syssets.AllSet, + self.SET_INSTALLED : syssets.InstalledSet, + self.SET_UNINSTALLED : syssets.UninstalledSet, + self.SET_TREE : syssets.TreeSet + } - def get_update_option (self): - return ["--update", "--oneshot"] # --oneshot to not record the used sets in world file + def get_update_option (self): + return ["--update", "--oneshot"] # --oneshot to not record the used sets in world file - def has_set_support (self): - return True + def has_set_support (self): + return True - def get_sets (self, description = False): - if description: - return ((name, set.description) for name, set in self.settings.setsconfig.getSets().iteritems()) - else: - return tuple(self.settings.setsconfig.getSets()) + def get_sets (self, description = False): + if description: + return ((name, set.description) for name, set in self.settings.setsconfig.getSets().iteritems()) + else: + return tuple(self.settings.setsconfig.getSets()) - def _get_set (self, pkgSet): - pkgSet = pkgSet.lower() - if pkgSet == "": pkgSet = self.SET_ALL + def _get_set (self, pkgSet): + pkgSet = pkgSet.lower() + if pkgSet == "": pkgSet = self.SET_ALL - s = self.setmap.get(pkgSet, None) - if s is None: - return syssets.PortageSet(pkgSet) - else: - return s() + s = self.setmap.get(pkgSet, None) + if s is None: + return syssets.PortageSet(pkgSet) + else: + return s() - def new_package (self, cpv): - return PortagePackage_22(cpv) + def new_package (self, cpv): + return PortagePackage_22(cpv) diff --git a/portato/backend/system_interface.py b/portato/backend/system_interface.py index 1cb0ed1..6f13042 100644 --- a/portato/backend/system_interface.py +++ b/portato/backend/system_interface.py @@ -11,282 +11,282 @@ # Written by René 'Necoro' Neumann class SystemInterface (object): - - SET_ALL = "__portato_all__" - SET_TREE = "__portato_tree__" - SET_INSTALLED = "__portato_installed__" - SET_UNINSTALLED = "__portato_uninstalled__" - - def has_set_support (self): - """Signals, whether this backend supports sets. - - @rtype: boolean - """ - raise NotImplementedError - - def get_sets (self): - """Returns all supported sets in tuples consisting of name and description. - If sets aren't supported, at least "world" and "system" have to be returned. - - @rtype: iter(string, string) - """ - raise NotImplementedError - - def get_version (self): - """Returns the version of the used backend. - - @rtype: string - """ - raise NotImplementedError - - def split_cpv (self, cpv): - """Splits a cpv into all its parts. - - @param cpv: the cpv to split - @type cpv: string - @returns: the splitted cpv - @rtype: string[] - """ - - raise NotImplementedError - - def cpv_matches (self, cpv, criterion): - """Checks whether a cpv matches a specific criterion. - - @param cpv: cpv to check - @type cpv: string - @param criterion: criterion to check against - @type criterion: string - @returns: match result - @rtype: boolean - """ - - raise NotImplementedError - - def find_best(self, list, only_cpv = False): - """Returns the best package out of a list of packages. - - @param list: the list of packages to select from - @type list: string[] - @param only_cpv: do not return package but only the cpv - @type only_cpv: boolean - - @returns: the best package - @rtype: backend.Package or string - """ - - raise NotImplementedError - - def find_best_match (self, search_key, masked = False, only_installed = False, only_cpv = False): - """Finds the best match in the portage tree. It does not find masked packages! - - @param search_key: the key to find in the portage tree - @type search_key: string - @param masked: if True, also look for masked packages - @type masked: boolean - @param only_installed: if True, only installed packages are searched - @type only_installed: boolean - @param only_cpv: do not return package but only the cpv - @type only_cpv: boolean - - @returns: the package found or None - @rtype: backend.Package or string - """ - - raise NotImplementedError - - def find_packages (self, key, pkgSet = SET_ALL, masked = False, with_version = True, only_cpv = False): - """This returns a list of packages matching the key. - As key, it is allowed to use basic regexps (".*") and the normal package specs. But not a combination - of them. - - @param key: the key to look for - @type key: string - @param all: the package set to use - @type all: string - @param masked: if True, also look for masked packages - @type masked: boolean - @param with_version: if True, return CPVs - else CP - @type with_version: boolean - @param only_cpv: do not return package but only the cpv. if with_version is False, this is ignored - @type only_cpv: boolean - - @returns: list of found packages - @rtype: backend.Package[] or string[] - """ - - raise NotImplementedError - - def list_categories (self, name = None): - """Finds all categories matching a name or all if no name is specified. - - @param name: the name to look for - it is expanded to .*name.* ; if None, all categories are returned - @type name: string or None - @returns: all categories found - @rtype: string[] - """ - - raise NotImplementedError - - def sort_package_list(self, pkglist): - """Sorts a package list in the same manner portage does. - - @param pkglist: list to sort - @type pkglist: Packages[] - """ - - raise NotImplementedError - - def reload_settings (self): - """Reloads portage.""" - - raise NotImplementedError - - def update_world (self, newuse = False, deep = False): - """Calculates the packages to get updated in an update world. - - @param newuse: Checks if a use-flag has a different state then to install time. - @type newuse: boolean - @param deep: Not only check world packages but also there dependencies. - @type deep: boolean - @returns: a list of the tuple (new_package, old_package) - @rtype: (backend.Package, backend.Package)[] - """ - - raise NotImplementedError - - def get_updated_packages (self): - """Returns the packages for which a newer package is available in the portage tree and installable (thus not masked). - This differs from update_world as it takes all installed packages into account but ignores changed useflags. - - @returns: the list of new packages - @rtype: backend.Package[] - """ - - raise NotImplementedError - - def get_use_desc (self, 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. - - @param flag: flag to get the description for - @type flag: string - @param package: name of a package: if given local use descriptions are searched too - @type package: cp-string - @returns: found description - @rtype: string - """ - - raise NotImplementedError - - def get_global_settings(self, key): - """Returns the value of a global setting, i.e. ARCH, USE, ROOT, DISTDIR etc. - - @param key: the setting to return - @type key: string - @returns: the value of this setting - @rtype: string - """ + + SET_ALL = "__portato_all__" + SET_TREE = "__portato_tree__" + SET_INSTALLED = "__portato_installed__" + SET_UNINSTALLED = "__portato_uninstalled__" + + def has_set_support (self): + """Signals, whether this backend supports sets. + + @rtype: boolean + """ + raise NotImplementedError + + def get_sets (self): + """Returns all supported sets in tuples consisting of name and description. + If sets aren't supported, at least "world" and "system" have to be returned. + + @rtype: iter(string, string) + """ + raise NotImplementedError + + def get_version (self): + """Returns the version of the used backend. + + @rtype: string + """ + raise NotImplementedError + + def split_cpv (self, cpv): + """Splits a cpv into all its parts. + + @param cpv: the cpv to split + @type cpv: string + @returns: the splitted cpv + @rtype: string[] + """ + + raise NotImplementedError + + def cpv_matches (self, cpv, criterion): + """Checks whether a cpv matches a specific criterion. + + @param cpv: cpv to check + @type cpv: string + @param criterion: criterion to check against + @type criterion: string + @returns: match result + @rtype: boolean + """ + + raise NotImplementedError + + def find_best(self, list, only_cpv = False): + """Returns the best package out of a list of packages. + + @param list: the list of packages to select from + @type list: string[] + @param only_cpv: do not return package but only the cpv + @type only_cpv: boolean + + @returns: the best package + @rtype: backend.Package or string + """ + + raise NotImplementedError + + def find_best_match (self, search_key, masked = False, only_installed = False, only_cpv = False): + """Finds the best match in the portage tree. It does not find masked packages! + + @param search_key: the key to find in the portage tree + @type search_key: string + @param masked: if True, also look for masked packages + @type masked: boolean + @param only_installed: if True, only installed packages are searched + @type only_installed: boolean + @param only_cpv: do not return package but only the cpv + @type only_cpv: boolean + + @returns: the package found or None + @rtype: backend.Package or string + """ + + raise NotImplementedError + + def find_packages (self, key, pkgSet = SET_ALL, masked = False, with_version = True, only_cpv = False): + """This returns a list of packages matching the key. + As key, it is allowed to use basic regexps (".*") and the normal package specs. But not a combination + of them. + + @param key: the key to look for + @type key: string + @param all: the package set to use + @type all: string + @param masked: if True, also look for masked packages + @type masked: boolean + @param with_version: if True, return CPVs - else CP + @type with_version: boolean + @param only_cpv: do not return package but only the cpv. if with_version is False, this is ignored + @type only_cpv: boolean + + @returns: list of found packages + @rtype: backend.Package[] or string[] + """ + + raise NotImplementedError + + def list_categories (self, name = None): + """Finds all categories matching a name or all if no name is specified. + + @param name: the name to look for - it is expanded to .*name.* ; if None, all categories are returned + @type name: string or None + @returns: all categories found + @rtype: string[] + """ + + raise NotImplementedError + + def sort_package_list(self, pkglist): + """Sorts a package list in the same manner portage does. + + @param pkglist: list to sort + @type pkglist: Packages[] + """ + + raise NotImplementedError + + def reload_settings (self): + """Reloads portage.""" + + raise NotImplementedError + + def update_world (self, newuse = False, deep = False): + """Calculates the packages to get updated in an update world. + + @param newuse: Checks if a use-flag has a different state then to install time. + @type newuse: boolean + @param deep: Not only check world packages but also there dependencies. + @type deep: boolean + @returns: a list of the tuple (new_package, old_package) + @rtype: (backend.Package, backend.Package)[] + """ + + raise NotImplementedError + + def get_updated_packages (self): + """Returns the packages for which a newer package is available in the portage tree and installable (thus not masked). + This differs from update_world as it takes all installed packages into account but ignores changed useflags. + + @returns: the list of new packages + @rtype: backend.Package[] + """ + + raise NotImplementedError + + def get_use_desc (self, 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. + + @param flag: flag to get the description for + @type flag: string + @param package: name of a package: if given local use descriptions are searched too + @type package: cp-string + @returns: found description + @rtype: string + """ + + raise NotImplementedError + + def get_global_settings(self, key): + """Returns the value of a global setting, i.e. ARCH, USE, ROOT, DISTDIR etc. + + @param key: the setting to return + @type key: string + @returns: the value of this setting + @rtype: string + """ - raise NotImplementedError + raise NotImplementedError - def new_package (self, cpv): - """Returns an instance of the appropriate Package-Subclass. + def new_package (self, cpv): + """Returns an instance of the appropriate Package-Subclass. - @param cpv: the cpv to create the package from - @type cpv: string - @returns: a new Package-object. - @rtype: Package - """ + @param cpv: the cpv to create the package from + @type cpv: string + @returns: a new Package-object. + @rtype: Package + """ - raise NotImplementedError + raise NotImplementedError - def get_config_path (self): - """Returns the actual path to the config files. - - @returns: the path, e.g. /etc/portage - @rtype: string - """ + def get_config_path (self): + """Returns the actual path to the config files. + + @returns: the path, e.g. /etc/portage + @rtype: string + """ - raise NotImplementedError + raise NotImplementedError - def get_sync_command (self): - """Returns the command(s) to run for syncing. This can be overridden by the user. + def get_sync_command (self): + """Returns the command(s) to run for syncing. This can be overridden by the user. - @returns: command to run - @rtype: string[] - """ + @returns: command to run + @rtype: string[] + """ - raise NotImplementedError + raise NotImplementedError - def get_merge_command (self): - """Returns the command(s) to run for the merging. + def get_merge_command (self): + """Returns the command(s) to run for the merging. - @returns: command to run - @rtype: string[] - """ + @returns: command to run + @rtype: string[] + """ - raise NotImplementedError + raise NotImplementedError - def get_oneshot_option (self): - """Returns the options to append for marking a merge as "oneshot". + def get_oneshot_option (self): + """Returns the options to append for marking a merge as "oneshot". - @returns: option(s) to append - @rtype: string[] - """ + @returns: option(s) to append + @rtype: string[] + """ - raise NotImplementedError + raise NotImplementedError - def get_newuse_option (self): - """Returns the options to append for marking a merge as "newuse". + def get_newuse_option (self): + """Returns the options to append for marking a merge as "newuse". - @returns: option(s) to append - @rtype: string[] - """ + @returns: option(s) to append + @rtype: string[] + """ - raise NotImplementedError + raise NotImplementedError - def get_deep_option (self): - """Returns the options to append for marking a merge as "deep". + def get_deep_option (self): + """Returns the options to append for marking a merge as "deep". - @returns: option(s) to append - @rtype: string[] - """ + @returns: option(s) to append + @rtype: string[] + """ - raise NotImplementedError + raise NotImplementedError - def get_update_option (self): - """Returns the options to append for marking a merge as "update". + def get_update_option (self): + """Returns the options to append for marking a merge as "update". - @returns: option(s) to append - @rtype: string[] - """ + @returns: option(s) to append + @rtype: string[] + """ - raise NotImplementedError + raise NotImplementedError - def get_pretend_option (self): - """Returns the options to append for marking a merge as "pretend". + def get_pretend_option (self): + """Returns the options to append for marking a merge as "pretend". - @returns: option(s) to append - @rtype: string[] - """ + @returns: option(s) to append + @rtype: string[] + """ - raise NotImplementedError + raise NotImplementedError - def get_unmerge_option (self): - """Returns the options to append for marking a merge as "unmerge". + def get_unmerge_option (self): + """Returns the options to append for marking a merge as "unmerge". - @returns: option(s) to append - @rtype: string[] - """ + @returns: option(s) to append + @rtype: string[] + """ - raise NotImplementedError + raise NotImplementedError - def get_environment (self): - """Returns a dictionary of environment variables to set prior to do an emerge. + def get_environment (self): + """Returns a dictionary of environment variables to set prior to do an emerge. - @returns: environment variables - @rtype: dict{string : string} - """ + @returns: environment variables + @rtype: dict{string : string} + """ - raise NotImplementedError + raise NotImplementedError -- cgit v1.2.3-70-g09d2