diff options
-rw-r--r-- | geneticone/gui/main.py | 151 | ||||
-rw-r--r-- | geneticone/helper.py | 3 | ||||
-rw-r--r-- | geneticone/package.py | 287 |
3 files changed, 271 insertions, 170 deletions
diff --git a/geneticone/gui/main.py b/geneticone/gui/main.py index e0dceef..b533e11 100644 --- a/geneticone/gui/main.py +++ b/geneticone/gui/main.py @@ -41,11 +41,11 @@ class EmergeQueue: def __init__ (self, tree = None, console = None, packages = None): """Constructor. - @param tree: Tree to append all the items to. + @param tree: Tree to append all the items to. Default: None. @type tree: gtk.TreeStore - @param console: Output is shown here. + @param console: Output is shown here. Default: None @type console: vte.Terminal - @param packages: The list of packages sorted by categories. We will delete the appropriate category if we updated sth. + @param packages: The list of packages sorted by categories. We will delete the appropriate category if we updated sth. Default: None @type packages: dictionary: {category: list_of_packages}.""" self.mergequeue = [] @@ -56,111 +56,165 @@ class EmergeQueue: self.console = console self.packages = packages - if self.tree: + if self.tree: self.emergeIt = self.tree.append(None, ["Emerge"]) self.unmergeIt = self.tree.append(None, ["Unmerge"]) else: self.emergeIt = self.unmergeIt = None def update_tree (self, it, cpv): - try: + """This updates the tree recursivly. + + @param it: iterator where to append + @type it: gtk.TreeIter + @param cpv: The package to append. + @type cpv: string (cat/pkg-ver) + + @raise geneticone.BlockedException: When occured during dependency-calculation.""" + + # get depencies + if cpv in self.deps: deps = self.deps[cpv] - except KeyError: + else: deps = geneticone.find_packages("="+cpv)[0].get_dep_packages() self.deps.update({cpv : deps}) subIt = self.tree.append(it, [cpv]) + # recursive call for d in deps: try: self.update_tree(subIt, d) except geneticone.BlockedException, e: + # remove the project while self.tree.iter_parent(subIt): subIt = self.tree.iter_parent(subIt) self.remove_children(subIt) raise e + # add iter self.iters.update({cpv: subIt}) - def append (self, sth, unmerge = False, update = False): + def append (self, cpv, unmerge = False, update = False): """Appends a cpv either to the merge queue or to the unmerge-queue. - Also update the tree-view.""" + Also updates the tree-view. + + @param cpv: Package to add + @type cpv: string (cat/pkg-ver) + @param unmerge: Set to True if you want to unmerge this package - else False. Default: False + @type unmerge: boolean + @param update: Set to True if a package is going to be updated (e.g. if the use-flags changed). Default: False + @type update: boolean""" + if not unmerge: try: # insert dependencies - pkg = geneticone.find_packages("="+sth)[0] + pkg = geneticone.find_packages("="+cpv)[0] deps = pkg.get_dep_packages() if update: - if deps == self.deps[sth]: - return + if deps == self.deps[cpv]: + return # nothing changed - return else: - parentIt = self.tree.iter_parent(self.iters[sth]) - self.remove(self.iters[sth]) - self.deps.update({sth: deps}) - self.update_tree(parentIt, sth) - else: - self.mergequeue.append(sth) - self.deps.update({sth : deps}) - - # update tree - if self.emergeIt: - self.update_tree(self.emergeIt, sth) + parentIt = self.tree.iter_parent(self.iters[cpv]) + self.remove(self.iters[cpv]) + self.deps.update({cpv: deps}) + self.update_tree(parentIt, cpv) + else: # not update + self.mergequeue.append(cpv) + self.deps.update({cpv : deps}) + if self.emergeIt: self.update_tree(self.emergeIt, cpv) - except geneticone.BlockedException, e : + except geneticone.BlockedException, e : # there is sth blocked --> call blocked_dialog blocks = e[0] - blocked_dialog(sth, blocks) + blocked_dialog(cpv, blocks) return - else: - self.unmergequeue.append(sth) + else: # unmerge + self.unmergequeue.append(cpv) if self.unmergeIt: # update tree - self.tree.append(self.unmergeIt, [sth]) + self.tree.append(self.unmergeIt, [cpv]) - def update_packages(self, process, packages): - """This updates the packages-list. It simply removes all affected categories so they have to be rebuilt.""" - process.wait() + def _update_packages(self, packages, process = None): + """This updates the packages-list. It simply removes all affected categories so they have to be rebuilt. + + @param packages: The packages which we emerged. + @type packages: list of cpvs + @param process: The process we have to wait for before we can do our work. Default: None. + @type process: subprocess.Popen""" + + if process: process.wait() for p in packages: try: - cat = geneticone.split_package_name(p)[0] + cat = geneticone.split_package_name(p)[0] # get category while cat[0] in ["=",">","<","!"]: cat = cat[1:] - print cat, + print "Category: "+cat , del self.packages[cat] - print "deleted" - except KeyError: + print "marked for refreshing" + except KeyError: # not in self.packages - ignore pass def _emerge (self, options, packages, it): - """Calls emerge and updates the terminal.""" + """Calls emerge and updates the terminal. + + @param options: options to send to emerge + @type options: list + @param packages: packages to emerge + @type packages: list + @param it: Iterator which points to an entry whose children will be removed after completion. + @type it: gtk.TreeIter""" + + # open tty (master, slave) = pty.openpty() self.console.set_pty(master) + + # start emerge process = Popen(["/usr/bin/python","/usr/bin/emerge"]+options+packages, stdout = slave, stderr = STDOUT, shell = False) - Thread(target=self.update_packages, args=(process, packages)).start() + Thread(target=self._update_packages, args=(packages, process)).start() + + # remove self.remove_children(it) def emerge (self, force = False): - """Emerges everything in the merge-queue. If force is 'False' (default) only 'emerge -pv' is called.""" - if len(self.mergequeue) == 0: return + """Emerges everything in the merge-queue. + + @param force: If False, '-pv' is send to emerge. Default: False. + @type force: boolean""" + if len(self.mergequeue) == 0: return # nothing in queue + + # prepare package-list list = [] for k in self.mergequeue: list += ["="+k] s = [] if not force: s = ["-pv"] + self._emerge(s, list, self.emergeIt) def unmerge (self, force = False): - """Unmerges everything in the umerge-queue. If force is 'False' (default) only "emerge -pv -C" is called.""" - if len(self.unmergequeue) == 0: return + """Unmerges everything in the umerge-queue. - list = self.unmergequeue[:] + @param force: If False, '-pv' is send to emerge. Default: False. + @type force: boolean""" + + if len(self.unmergequeue) == 0: return # nothing in queue + + list = self.unmergequeue[:] # copy the unmerge-queue + + # set options s = ["-C"] if not force: s = ["-Cpv"] + self._emerge(s,list, self.unmergeIt) def remove_children (self, parentIt): - """Removes all children of a given parent TreeIter.""" + """Removes all children of a given parent TreeIter. + + @param parentIt: The iter from which to remove all children. + @type parentIt: gtk.TreeIter""" + childIt = self.tree.iter_children(parentIt) while childIt: @@ -169,18 +223,23 @@ class EmergeQueue: self.remove(temp) def remove (self, it): - """Removes a specific item in the tree.""" + """Removes a specific item in the tree. This does not remove the top-entries. + + @param it: Iterator which points to the entry we are going to remove. + @type it: gtk.TreeIter""" + if self.tree.iter_parent(it): # NEVER remove our top stuff cpv = self.tree.get_value(it,0) - if self.tree.get_string_from_iter(it).split(":")[0] == self.tree.get_string_from_iter(self.emergeIt): + if self.tree.get_string_from_iter(it).split(":")[0] == self.tree.get_string_from_iter(self.emergeIt): # in Emerge try: self.mergequeue.remove(cpv) del self.iters[cpv] del self.deps[cpv] - except ValueError: + except ValueError: # this is a dependency - ignore pass flags.remove_new_use_flags(cpv) - else: + + else: # in Unmerge self.unmergequeue.remove(cpv) self.tree.remove(it) diff --git a/geneticone/helper.py b/geneticone/helper.py index e59ca98..e97568b 100644 --- a/geneticone/helper.py +++ b/geneticone/helper.py @@ -27,6 +27,9 @@ class BlockedException (Exception): class PackageNotFoundException (Exception): pass +class DependencyCalcError (Exception): + pass + def find_lambda (name): """Returns the function needed by all the find_all_*-functions. Returns None if no name is given.""" if name != None: diff --git a/geneticone/package.py b/geneticone/package.py index 9df92c7..085d4c2 100644 --- a/geneticone/package.py +++ b/geneticone/package.py @@ -20,22 +20,26 @@ import portage from portage_util import unique_array class Package (gentoolkit.Package): - """This is just a subclass of the Package-class of gentoolkit.""" + """This is a subclass of the gentoolkit.Package-class which a lot of additional functionality we need in Genetic/One.""" def __init__ (self, cpv): + """Constructor. + + @param cpv: The cpv or gentoolkit.Package which describes the package to create. + @type cpv: string (cat/pkg-ver) or gentoolkit.Package-object.""" + if isinstance(cpv, gentoolkit.Package): cpv = cpv.get_cpv() gentoolkit.Package.__init__(self, cpv) def get_mask_status(self): - '''gets the numeric mask status of a package - can be translated as string: - maskmodes = [ " ", " ~", " -", "M ", "M~", "M-" ] - (0=unmasked 1=~arch 2=-arch etc.) - + """Gets the numeric mask status of a package. The return value can be translated as a string when taking the following list of modes: [ " ", " ~", " -", "M ", "M~", "M-" ] + This method adapted from equery 0.1.4 Original author: Karl Trygve Kalleberg <karltk@gentoo.org> - ''' + + @returns: mask status + @rtype: int""" pkgmask = 0 if self.is_masked(): @@ -47,15 +51,19 @@ class Package (gentoolkit.Package): pkgmask = pkgmask + 2 return pkgmask - def get_size (self): - return self.size() - def get_all_use_flags (self): - """Returns a list of _all_ useflags for this package.""" + """Returns a list of _all_ useflags for this package, i.e. all useflags you can set for this package. + + @returns: list of use-flags + @rtype: list""" + return unique_array(self.get_env_var("IUSE").split()) def get_installed_use_flags (self): - """Returns a list of the useflags enabled at installation time. If package is not installed, it returns an empty list.""" + """Returns a list of the useflags enabled at installation time. If package is not installed, it returns an empty list. + + @returns: list of useflags enabled at installation time or an empty list + @rtype: list""" if self.is_installed(): uses = self.get_use_flags().split() iuses = self.get_all_use_flags() @@ -68,9 +76,18 @@ class Package (gentoolkit.Package): return [] def get_new_use_flags (self): + """Returns a list of the new useflags, i.e. these flags which are not written to the portage-system yet. + + @returns: list of flags or [] + @rtype: list""" return flags.get_new_use_flags(self) def get_actual_use_flags (self): + """This returns the result of installed_use_flags + new_use_flags. If the package is not installed, it returns only the new flags. + + @return: list of flags + @rtype: list""" + if self.is_installed(): i_flags = self.get_installed_use_flags() for f in self.get_new_use_flags(): @@ -83,19 +100,25 @@ class Package (gentoolkit.Package): return self.get_new_flags() def set_use_flag (self, flag): + """Set a use-flag. + + @param flag: the flag to set + @type flag: string""" flags.set_use_flag(self, flag) def remove_new_use_flags (self): + """Remove all the new use-flags.""" flags.remove_new_use_flags(self) - def get_all_deps (self): - """Returns a linearised list of all first-level dependencies for this package, on - the form [(comparator, [use flags], cpv), ...]""" - return unique_array(self.get_compiletime_deps()+self.get_runtime_deps()+self.get_postmerge_deps()) - def get_dep_packages (self): - """Returns a cpv-list of packages on which this package depends and which have not been installed yet. - raises: BlockedException, PackageNotFoundException.""" + """Returns a cpv-list of packages on which this package depends and which have not been installed yet. This does not check the dependencies in a recursive manner. + + @returns: list of cpvs on which the package depend + @rtype: list + @raises geneticone.BlockedException: when a package in the dependency-list is blocked by an installed one + @raises geneticone.PackageNotFoundException: when a package in the dependency list could not be found in the system + @raises geneticone.DependencyCalcError: when an error occured during executing portage.dep_check()""" + dep_pkgs = [] # the package list # check whether we got use-flags which are not visible for portage yet @@ -116,10 +139,13 @@ class Package (gentoolkit.Package): if not deps: # what is the difference to [1, []] ? return [] + if deps[0] == 0: # error + raise DependencyCalcError, deps[1] + deps = deps[1] for dep in deps: - if dep[0] == '!': + if dep[0] == '!': # blocking sth blocked = find_installed_packages(dep[1:]) if blocked != []: raise BlockedException, blocked[0].get_cpv() @@ -134,67 +160,16 @@ class Package (gentoolkit.Package): return dep_pkgs - def own_get_dep_packages (self, old_cpv_dict = {}): - # XXX: after having finished this, i realized, that there is already a portage function -.- ; - # will keep this in case portage changes anything - """Returns a list of all packages (i.e. package-cpvs) which this package depends on and which not have been installed yet. - Param old_cpv_dict is a {cp: version}-dictionary holding already found deps. - Raises a BlockedException if the package is being blocked by another installed package.""" - # XXX: This won't find blocking dependencies - # XXX: Has some problems with modular X (this has a very strange ebuild) ... we should enhance _parse_deps - print "Actual: "+self._cpv # debug output - - uses = [] # list of actual useflags / useflags the package has been installed with - dep_packages = [] # list of packages returned - dep_cpv_dict = {} # all dependencies are inserted here - - # get useflags - if self.is_installed(): - uses = self.get_installed_use_flags() - else: - uses = self.get_settings("USE") - - # cycle through dependencies - for (comp, flags, dep_cpv) in self.get_all_deps(): - - # find blocking packages - if comp and comp[0] == '!': - blocked = find_installed_packages(comp[1:]+dep_cpv) - if blocked != []: - raise BlockedException, blocked[0].get_cpv() - else: # next flag - continue - - # look whether this package is really required - needDep = True - for flag in flags: - if (flag[0] == '!' and flag[1:] in uses) or (flag[0] != '!' and flag not in uses): - needDep = False - break - - if needDep: # it is ... - if find_installed_packages(comp+dep_cpv) == []: # ... and not installed yet - d = find_best_match(comp+dep_cpv) - if not d: # no package found - raise PackageNotFoundException, dep_cpv - if d.get_cp() not in old_cpv_dict: # ... and not found already by an other package - dep_cpv_dict[d.get_cp()] = d.get_version() - print "Dep: "+d.get_cpv() # debug - dep_packages.append(d.get_cpv()) - - for dep in dep_packages: # find dependencies for each package - old_cpv_dict.update(dep_cpv_dict) - old_cpv_dict.update({self.get_cp() : self.get_version()}) - dep_packages += find_packages("="+dep)[0].own_get_dep_packages(old_cpv_dict) - - return unique_array(dep_packages) - def get_cp (self): - """Returns category/package.""" + """Returns the cp-string. + @returns: category/package. + @rtype: string""" return self.get_category()+"/"+self.get_name() def is_masked (self): - """Returns True if either masked by package.mask or by profile.""" + """Returns True if either masked by package.mask or by profile. + @returns: mask-status + @rtype: boolean""" # XXX: Better solution than string comparison? status = portage.getmaskingstatus(self._cpv) if "profile" in status or "package.mask" in status: @@ -202,55 +177,119 @@ class Package (gentoolkit.Package): return False def matches (self, criterion): - """This checks, whether this package matches a specific verisioning criterion - e.g.: "<=net-im/foobar-1.2".""" + """This checks, whether this package matches a specific verisioning criterion - e.g.: "<=net-im/foobar-1.2". + @param criterion: the criterion to match against + @type criterion: string""" if portage.match_from_list(criterion, [self.get_cpv()]) == []: return False else: return True +# +# OBSOLETE DEPENDENCY-CALCULATION-METHODS - kept in the case the above ones do not work +# + + #def own_get_dep_packages (self, old_cpv_dict = {}): + # # XXX: after having finished this, i realized, that there is already a portage function -.- ; + # """Returns a list of all packages (i.e. package-cpvs) which this package depends on and which not have been installed yet. + # Param old_cpv_dict is a {cp: version}-dictionary holding already found deps. + # Raises a BlockedException if the package is being blocked by another installed package.""" + # # XXX: This won't find blocking dependencies + # # XXX: Has some problems with modular X (this has a very strange ebuild) ... we should enhance _parse_deps + # print "Actual: "+self._cpv # debug output + # + # uses = [] # list of actual useflags / useflags the package has been installed with + # dep_packages = [] # list of packages returned + # dep_cpv_dict = {} # all dependencies are inserted here + # + # # get useflags + # if self.is_installed(): + # uses = self.get_installed_use_flags() + # else: + # uses = self.get_settings("USE") + # + # # cycle through dependencies + # for (comp, flags, dep_cpv) in self.get_all_deps(): + + # # find blocking packages + # if comp and comp[0] == '!': + # blocked = find_installed_packages(comp[1:]+dep_cpv) + # if blocked != []: + # raise BlockedException, blocked[0].get_cpv() + # else: # next flag + # continue + # + # # look whether this package is really required + # needDep = True + # for flag in flags: + # if (flag[0] == '!' and flag[1:] in uses) or (flag[0] != '!' and flag not in uses): + # needDep = False + # break + + # if needDep: # it is ... + # if find_installed_packages(comp+dep_cpv) == []: # ... and not installed yet + # d = find_best_match(comp+dep_cpv) + # if not d: # no package found + # raise PackageNotFoundException, dep_cpv + # if d.get_cp() not in old_cpv_dict: # ... and not found already by an other package + # dep_cpv_dict[d.get_cp()] = d.get_version() + # print "Dep: "+d.get_cpv() # debug + # dep_packages.append(d.get_cpv()) + # + # for dep in dep_packages: # find dependencies for each package + # old_cpv_dict.update(dep_cpv_dict) + # old_cpv_dict.update({self.get_cp() : self.get_version()}) + # dep_packages += find_packages("="+dep)[0].own_get_dep_packages(old_cpv_dict) + + # return unique_array(dep_packages) + + #def get_all_deps (self): + # """Returns a linearised list of all first-level dependencies for this package, on + # the form [(comparator, [use flags], cpv), ...]""" + # return unique_array(self.get_compiletime_deps()+self.get_runtime_deps()+self.get_postmerge_deps()) - def _parse_deps(self,deps,curuse=[],level=0): - """Modified method "_parse_deps" of gentoolkit.Package. - Do NOT ignore blocks.""" - # store (comparator, [use predicates], cpv) - r = [] - comparators = ["~","<",">","=","<=",">="] - end = len(deps) - i = 0 - while i < end: - blocked = False - tok = deps[i] - if tok == ')': - return r,i - if tok[-1] == "?": - tok = tok.replace("?","") - sr,l = self._parse_deps(deps[i+2:],curuse=curuse+[tok],level=level+1) - r += sr - i += l + 3 - continue - if tok == "||": - sr,l = self._parse_deps(deps[i+2:],curuse,level=level+1) - r += sr - i += l + 3 - continue - # conjonction, like in "|| ( ( foo bar ) baz )" => recurse - if tok == "(": - sr,l = self._parse_deps(deps[i+1:],curuse,level=level+1) - r += sr - i += l + 2 - continue - # pkg block "!foo/bar" => ignore it - if tok[0] == "!": - #i += 1 - #continue - blocked = True # added - tok = tok[1:] # added - # pick out comparator, if any - cmp = "" - for c in comparators: - if tok.find(c) == 0: - cmp = c - if blocked: cmp = "!"+cmp # added - tok = tok[len(cmp):] - r.append((cmp,curuse,tok)) - i += 1 - return r,i + #def _parse_deps(self,deps,curuse=[],level=0): + # """Modified method "_parse_deps" of gentoolkit.Package. + # Do NOT ignore blocks.""" + # # store (comparator, [use predicates], cpv) + # r = [] + # comparators = ["~","<",">","=","<=",">="] + # end = len(deps) + # i = 0 + # while i < end: + # blocked = False + # tok = deps[i] + # if tok == ')': + # return r,i + # if tok[-1] == "?": + # tok = tok.replace("?","") + # sr,l = self._parse_deps(deps[i+2:],curuse=curuse+[tok],level=level+1) + # r += sr + # i += l + 3 + # continue + # if tok == "||": + # sr,l = self._parse_deps(deps[i+2:],curuse,level=level+1) + # r += sr + # i += l + 3 + # continue + # # conjonction, like in "|| ( ( foo bar ) baz )" => recurse + # if tok == "(": + # sr,l = self._parse_deps(deps[i+1:],curuse,level=level+1) + # r += sr + # i += l + 2 + # continue + # # pkg block "!foo/bar" => ignore it + # if tok[0] == "!": + # #i += 1 + # #continue + # blocked = True # added + # tok = tok[1:] # added + # # pick out comparator, if any + # cmp = "" + # for c in comparators: + # if tok.find(c) == 0: + # cmp = c + # if blocked: cmp = "!"+cmp # added + # tok = tok[len(cmp):] + # r.append((cmp,curuse,tok)) + # i += 1 + # return r,i |