def calculate_conflicts(order, packagedb): B_0 = set(order) C = D = set() pkg_conflicts = {} for x in order: pkg = packagedb.get_package(x) # check if any package has conflicts with the installed packages conflicts = check_conflict(pkg, order) if conflicts: pkg_conflicts[x] = map(lambda c:str(c), conflicts) C = C.union(map(lambda c:c.package, conflicts)) # now check if any package has conflicts with each other B_i = B_0.intersection(set(map(lambda c:c.package, pkg.conflicts))) D_i = set() for p in map(lambda x:packagedb.get_package(x), B_i): conflicted = pisi.conflict.package_conflicts(p, pkg.conflicts) if conflicted: D_i.add(str(conflicted)) if D_i: D = D.union(D_i) D.add(pkg.name) return (C, D, pkg_conflicts)
def plan_upgrade(A, ignore_build = False): # try to construct a pisi graph of packages to # install / reinstall packagedb = ctx.packagedb G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A # TODO: conflicts while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) for dep in pkg.runtimeDependencies(): # add packages that can be upgraded if dependency.repo_satisfies_dep(dep): if ctx.installdb.is_installed(dep.package): if dependency.installed_satisfies_dep(dep): continue if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) else: ctx.ui.error(_('Dependency %s of %s cannot be satisfied') % (dep, x)) raise Error(_("Upgrade is not possible.")) B = Bp # now, search reverse dependencies to see if anything # should be upgraded B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) rev_deps = packagedb.get_rev_deps(x) for (rev_dep, depinfo) in rev_deps: # add only installed but unsatisfied reverse dependencies if ctx.installdb.is_installed(rev_dep) and \ (not dependency.installed_satisfies_dep(depinfo)): if not dependency.repo_satisfies_dep(depinfo): raise Error(_('Reverse dependency %s of %s cannot be satisfied') % (rev_dep, x)) if not rev_dep in G_f.vertices(): Bp.add(rev_dep) G_f.add_plain_dep(rev_dep, x) B = Bp if ctx.config.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() return G_f, order
def configure_pending(): # start with pending packages # configure them in reverse topological order of dependency A = ctx.installdb.list_pending() #print A G_f = pgraph.PGraph(packagedb) # construct G_f for x in A: G_f.add_package(x) B = A #state = {} while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) #print pkg for dep in pkg.runtimeDeps: if dep.package in G_f.vertices(): G_f.add_dep(x, dep) B = Bp G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() #print order for x in order: comariface.run_postinstall(x)
def install_pkg_names(A): """This is the real thing. It installs packages from the repository, trying to perform a minimum number of installs""" # A was a list, remove duplicates and expand components A_0 = A = expand_components(set(A)) ctx.ui.debug("A = %s" % str(A)) if len(A) == 0: ctx.ui.info(_("No packages to install.")) return if ctx.config.get_option("ignore_dependency"): # simple code path then for x in A: atomicoperations.install_single_name(x) return # short circuit # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) for dep in pkg.runtimeDependencies(): ctx.ui.debug("checking %s" % str(dep)) # we don't deal with already *satisfied* dependencies if not dependency.installed_satisfies_dep(dep): if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) B = Bp if ctx.config.get_option("debug"): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() check_conflicts(order) ctx.ui.info( _( """The following minimal list of packages will be installed in the respective order to satisfy dependencies: """ ) + util.strlist(order) ) if len(order) > len(A_0): if not ctx.ui.confirm(_("Do you want to continue?")): return False for x in order: atomicoperations.install_single_name(x)
def package_graph(A): """Construct a package relations graph, containing all dependencies of packages A""" ctx.ui.debug('A = %s' % str(A)) # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A #state = {} while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) print pkg for dep in pkg.runtimeDeps: # we don't deal with already *satisfied* dependencies if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) # if not dependency.installed_satisfies_dep(dep): # if not dep.package in G_f.vertices(): # Bp.add(str(dep.package)) # G_f.add_dep(x, dep) B = Bp return G_f
def package_graph(A, ignore_installed = False): """Construct a package relations graph, containing all dependencies of packages A, if ignore_installed option is True, then only uninstalled deps will be added.""" ctx.ui.debug('A = %s' % str(A)) # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A #state = {} while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) #print pkg for dep in pkg.runtimeDependencies(): if ignore_installed: if dependency.installed_satisfies_dep(dep): continue if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) B = Bp return G_f
def configure_pending(): # start with pending packages # configure them in reverse topological order of dependency A = ctx.installdb.list_pending() G_f = pgraph.PGraph(packagedb) # construct G_f for x in A: G_f.add_package(x) B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) for dep in pkg.runtimeDependencies: if dep.package in G_f.vertices(): G_f.add_dep(x, dep) B = Bp if ctx.get_option("debug"): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() try: import pisi.comariface as comariface for x in order: comariface.run_postinstall(x) ctx.installdb.clear_pending(x) except ImportError: raise Error(_("COMAR: comard not fully installed"))
def run(self): """Remove a single package""" inst_packagedb = packagedb.inst_packagedb self.package = packagedb.get_package(self.package_name) self.files = ctx.installdb.files(self.package_name) ctx.ui.status(_('Removing package %s') % self.package_name) if not ctx.installdb.is_installed(self.package_name): raise Exception(_('Trying to remove nonexistent package ') + self.package_name) self.check_dependencies() self.run_preremove() for fileinfo in self.files.list: self.remove_file(fileinfo) txn = ctx.dbenv.txn_begin() try: self.remove_db(txn) txn.commit() except db.DBError, e: txn.abort() raise e
def plan_remove(A): # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the (install closure) graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) rev_deps = packagedb.get_rev_deps(x) for (rev_dep, depinfo) in rev_deps: # we don't deal with uninstalled rev deps # and unsatisfied dependencies (this is important, too) if packagedb.inst_packagedb.has_package(rev_dep) and \ dependency.installed_satisfies_dep(depinfo): if not rev_dep in G_f.vertices(): Bp.add(rev_dep) G_f.add_plain_dep(rev_dep, x) B = Bp if ctx.config.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() return G_f, order
def plan_install_pkg_names(A): # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) for dep in pkg.runtimeDependencies(): ctx.ui.debug('checking %s' % str(dep)) # we don't deal with already *satisfied* dependencies if not dependency.installed_satisfies_dep(dep): if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) B = Bp if ctx.config.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() check_conflicts(order) return G_f, order
def repo_satisfies_dep(depinfo): """determine if a package in *repository* satisfies given dependency spec""" pkg_name = depinfo.package if not packagedb.has_package(pkg_name): return False else: pkg = packagedb.get_package(pkg_name) (version, release) = (pkg.version, pkg.release) return depinfo.satisfies(pkg_name, version, release)
def remove(A): """remove set A of packages from system (A is a list of package names)""" # filter packages that are not installed A_0 = A = set(A) Ap = [] for x in A: if ctx.installdb.is_installed(x): Ap.append(x) else: ctx.ui.info(_('Package %s does not exist. Cannot remove.') % x) A = set(Ap) if len(A)==0: ctx.ui.info(_('No packages to remove.')) return # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the (install closure) graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) rev_deps = packagedb.get_rev_deps(x) for (rev_dep, depinfo) in rev_deps: # we don't deal with unsatisfied dependencies if packagedb.has_package(rev_dep) and \ dependency.installed_satisfies_dep(depinfo): if not rev_dep in G_f.vertices(): Bp.add(rev_dep) G_f.add_plain_dep(rev_dep, x) B = Bp if ctx.config.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() ctx.ui.info(_("""The following minimal list of packages will be removed in the respective order to satisfy dependencies: """) + util.strlist(order)) if len(order) > len(A_0): if not ctx.ui.confirm('Do you want to continue?'): ctx.ui.warning(_('Package removal declined')) return False for x in order: if ctx.installdb.is_installed(x): atomicoperations.remove_single(x) else: ctx.ui.info(_('Package %s is not installed. Cannot remove.') % x)
def __init__(self, package_name, ignore_dep = None): super(Remove, self).__init__(ignore_dep) self.package_name = package_name self.package = packagedb.get_package(self.package_name) try: self.files = ctx.installdb.files(self.package_name) except pisi.Error, e: # for some reason file was deleted, we still allow removes! ctx.ui.error(unicode(e)) ctx.ui.warning(_('File list could not be read for package %s, continuing removal.') % package_name) self.files = Files()
def install_pkg_names(A, reinstall = False): """This is the real thing. It installs packages from the repository, trying to perform a minimum number of installs""" # A was a list, remove duplicates and expand components A_0 = A = expand_components(set(A)) ctx.ui.debug('A = %s' % str(A)) # filter packages that are already installed if not reinstall: Ap = set(filter(lambda x: not ctx.installdb.is_installed(x), A)) d = A - Ap if len(d) > 0: ctx.ui.warning(_('Not re-installing the following packages: ') + util.strlist(d)) A = Ap if len(A)==0: ctx.ui.info(_('No packages to install.')) return if not ctx.config.get_option('ignore_dependency'): G_f, order = plan_install_pkg_names(A) else: G_f = None order = A ctx.ui.info(_("""The following minimal list of packages will be installed in the respective order to satisfy dependencies: """) + util.strlist(order)) #this silly try/except block will be removed soon.. try: total_size = sum([packagedb.get_package(p).packageSize for p in order]) except: total_size = 0 if total_size: total_size, symbol = util.human_readable_size(total_size) ctx.ui.warning(_('Total size of packages: %.2f %s') % (total_size, symbol)) if ctx.get_option('dry_run'): return if len(order) > len(A_0): if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')): return False ctx.ui.notify(ui.packagestogo, order = order) for x in order: atomicoperations.install_single_name(x)
def upgradable(dep): # pre dep.package is installed (v, r, b) = ctx.installdb.get_version(dep.package) rep_pkg = packagedb.get_package(dep.package) (vp, rp, bp) = (rep_pkg.version, rep_pkg.release, rep_pkg.build) if ignore_build or (not b) or (not bp): # if we can't look at build if r >= rp: # installed already new return False elif b and bp and b >= bp: return False return True
def remove(A): """remove set A of packages from system (A is a list of package names)""" # filter packages that are not installed Ap = [] for x in A: if ctx.installdb.is_installed(x): Ap.append(x) else: ctx.ui.info(_('Package %s does not exist. Cannot remove.') % x) A = Ap if len(A)==0: ctx.ui.info(_('No packages to remove.')) return True # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the (install closure) graph of G_f by package # set A using packagedb #print A for x in A: G_f.add_package(x) B = A #state = {} while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) #print 'processing', pkg.name rev_deps = packagedb.get_rev_deps(x) for (rev_dep, depinfo) in rev_deps: #print 'checking ', rev_dep # we don't deal with unsatisfied dependencies if dependency.installed_satisfies_dep(depinfo): if not rev_dep in G_f.vertices(): Bp.add(rev_dep) G_f.add_plain_dep(rev_dep, x) B = Bp #G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() #FIXME: do something more informative here #print order for x in order: if ctx.installdb.is_installed(x): operations.remove_single(x) else: ctx.ui.info(_('Package %s is not installed. Cannot remove.') % x) return True # everything went OK :)
def configure_pending(): # start with pending packages # configure them in reverse topological order of dependency A = ctx.installdb.list_pending() G_f = pgraph.PGraph(packagedb) # construct G_f for x in A.keys(): G_f.add_package(x) B = A while len(B) > 0: Bp = set() for x in B.keys(): pkg = packagedb.get_package(x) for dep in pkg.runtimeDependencies(): if dep.package in G_f.vertices(): G_f.add_dep(x, dep) B = Bp if ctx.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() try: import pisi.comariface as comariface for x in order: if ctx.installdb.is_installed(x): pkginfo = A[x] pkgname = util.package_name(x, pkginfo.version, pkginfo.release, False, False) pkg_path = util.join_path(ctx.config.lib_dir(), 'package', pkgname) m = MetaData() metadata_path = util.join_path(pkg_path, ctx.const.metadata_xml) m.read(metadata_path) for pcomar in m.package.providesComar: scriptPath = util.join_path(pkg_path, ctx.const.comar_dir, pcomar.script) comariface.register(pcomar, x, scriptPath) # FIXME: we need a full package info here! # Eray, please fix this # your wish is a command, darling -- eray pkginfo.name = x ctx.ui.notify(pisi.ui.configuring, package = pkginfo, files = None) comariface.run_postinstall(x) ctx.ui.notify(pisi.ui.configured, package = pkginfo, files = None) ctx.installdb.clear_pending(x) except ImportError: raise Error(_("COMAR: comard not fully installed"))
def install_pkg_names(A): """This is the real thing. It installs packages from the repository, trying to perform a minimum number of installs""" A = set(A) # A was a list, remove duplicates ctx.ui.debug('A = %s' % str(A)) if len(A)==0: ctx.ui.info(_('No packages to install.')) return True # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb #print A for x in A: G_f.add_package(x) B = A #state = {} while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) #print pkg for dep in pkg.runtimeDeps: ctx.ui.debug('checking %s' % str(dep)) # we don't deal with already *satisfied* dependencies if not dependency.installed_satisfies_dep(dep): if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) B = Bp if ctx.config.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() #print order for x in order: operations.install_single_name(x) return True # everything went OK :)
def info_name(package_name): """fetch package information for a package""" if packagedb.has_package(package_name): package = packagedb.get_package(package_name) from pisi.metadata import MetaData metadata = MetaData() metadata.package = package #FIXME: get it from sourcedb metadata.source = None #TODO: fetch the files from server if possible if ctx.installdb.is_installed(package.name): files = ctx.installdb.files(package.name) else: files = None return metadata, files else: raise Error(_('Package %s not found') % package_name)
def list_upgradable(): ignore_build = ctx.get_option('ignore_build_no') A = ctx.installdb.list_installed() # filter packages that are not upgradable Ap = [] for x in A: (version, release, build) = ctx.installdb.get_version(x) pkg = packagedb.get_package(x) if ignore_build or (not build): if release < pkg.release: Ap.append(x) elif build < pkg.build: Ap.append(x) else: pass #ctx.ui.info('Package %s cannot be upgraded. ' % x) return Ap
def run(self): """Remove a single package""" inst_packagedb = packagedb.inst_packagedb self.package = packagedb.get_package(self.package_name) ctx.ui.info(_('Removing package %s') % self.package_name) if not ctx.installdb.is_installed(self.package_name): raise Exception(_('Trying to remove nonexistent package ') + self.package_name) self.check_dependencies() self.run_preremove() for fileinfo in ctx.installdb.files(self.package_name).list: self.remove_file(fileinfo) self.remove_db() self.remove_pisi_files()
def calculate_conflicts(order, packagedb): B_0 = set(order) C = D = set() pkg_conflicts = {} for x in order: pkg = packagedb.get_package(x) B_p = set(check_conflict(pkg)) if B_p: pkg_conflicts[x] = B_p C = C.union(B_p) B_i = B_0.intersection(set(pkg.conflicts)) # check if there are any conflicts within the packages that are # going to be installed if B_i: D = D.union(B_i) D.add(pkg.name) return (C, D, pkg_conflicts)
def from_name(name): # download package and return an installer object # find package in repository repo = packagedb.which_repo(name) if repo: repo = ctx.repodb.get_repo(repo) pkg = packagedb.get_package(name) # FIXME: let pkg.packageURI be stored as URI type rather than string pkg_uri = URI(pkg.packageURI) if pkg_uri.is_absolute_path(): pkg_path = str(pkg.packageURI) else: pkg_path = os.path.join(os.path.dirname(repo.indexuri.get_uri()), str(pkg_uri.path())) ctx.ui.debug(_("Package URI: %s") % pkg_path) return Install(pkg_path) else: raise Error(_("Package %s not found in any active repository.") % name)
def install_single_name(name, upgrade = False): """install a single package from ID""" # find package in repository repo = packagedb.which_repo(name) if repo: repo = ctx.repodb.get_repo(repo) pkg = packagedb.get_package(name) # FIXME: let pkg.packageURI be stored as URI type rather than string pkg_uri = URI(pkg.packageURI) if pkg_uri.is_absolute_path(): pkg_path = str(pkg.packageURI) else: pkg_path = os.path.join(os.path.dirname(repo.indexuri.get_uri()), str(pkg_uri.path())) ctx.ui.debug(_("Package URI: %s") % pkg_path) # Package will handle remote file for us! install_single_file(pkg_path, upgrade) else: raise Error(_("Package %s not found in any active repository.") % name)
def check_conflicts(order): """check if upgrading to the latest versions will cause havoc done in a simple minded way without regard for dependencies of conflicts, etc.""" B_0 = B = set(order) C = set() # calculate conflict closure while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) # get latest version! #TODO: read conflicts from a conflicts db... for conflict in pkg.conflicts: if ctx.installdb.is_installed(self.pkginfo): Bp.add(conflict) C.add(conflict) B = Bp if B_0.intersection(C): raise Error(_("Selected packages %s and %s are in conflict.") % (x, pkg)) if C: if not ctx.ui.confirm(_('Remove the following conflicting packages?')): #raise Error(_("Package %s conflicts installed package %s") % (x, pkg)) raise Error(_("Conflicts remain"))
def install_pkg_files(package_URIs): """install a number of pisi package files""" from package import Package ctx.ui.debug('A = %s' % str(package_URIs)) for x in package_URIs: if not x.endswith(ctx.const.package_suffix): raise Error(_('Mixing file names and package names not supported yet.')) if ctx.config.get_option('ignore_dependency'): # simple code path then for x in package_URIs: atomicoperations.install_single_file(x) return # short circuit # read the package information into memory first # regardless of which distribution they come from d_t = {} dfn = {} for x in package_URIs: package = Package(x) package.read() name = str(package.metadata.package.name) d_t[name] = package.metadata.package dfn[name] = x def satisfiesDep(dep): # is dependency satisfied among available packages # or packages to be installed? return dependency.installed_satisfies_dep(dep) \ or dependency.dict_satisfies_dep(d_t, dep) # for this case, we have to determine the dependencies # that aren't already satisfied and try to install them # from the repository dep_unsatis = [] for name in d_t.keys(): pkg = d_t[name] deps = pkg.runtimeDependencies() for dep in deps: if not satisfiesDep(dep): dep_unsatis.append(dep) # now determine if these unsatisfied dependencies could # be satisfied by installing packages from the repo # if so, then invoke install_pkg_names extra_packages = [x.package for x in dep_unsatis] if extra_packages: ctx.ui.info(_("""The following packages will be installed in the respective order to satisfy extra dependencies: """) + util.strlist(extra_packages)) if not ctx.ui.confirm(_('Do you want to continue?')): raise Error(_('External dependencies not satisfied')) install_pkg_names(extra_packages) class PackageDB: def get_package(self, key, repo = None): return d_t[str(key)] packagedb = PackageDB() A = d_t.keys() if len(A)==0: ctx.ui.info(_('No packages to install.')) return # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) for dep in pkg.runtimeDependencies(): if dependency.dict_satisfies_dep(d_t, dep): if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) B = Bp if ctx.config.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() if not ctx.get_option('ignore_file_conflicts'): check_conflicts(order, packagedb) order.reverse() ctx.ui.info(_('Installation order: ') + util.strlist(order) ) if ctx.get_option('dry_run'): return ctx.ui.notify(ui.packagestogo, order = order) for x in order: atomicoperations.install_single_file(dfn[x]) pisi_installed = ctx.installdb.is_installed('pisi') if 'pisi' in order and pisi_installed: upgrade_pisi()
def plan_upgrade(A, ignore_build=False): # try to construct a pisi graph of packages to # install / reinstall packagedb = ctx.packagedb G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A # TODO: conflicts while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) for dep in pkg.runtimeDependencies(): # add packages that can be upgraded if dependency.repo_satisfies_dep(dep): if ctx.installdb.is_installed(dep.package): if ctx.get_option('eager'): if not is_upgradable(dep.package): continue else: if dependency.installed_satisfies_dep(dep): continue if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) else: ctx.ui.error( _('Dependency %s of %s cannot be satisfied') % (dep, x)) raise Error(_("Upgrade is not possible.")) B = Bp # now, search reverse dependencies to see if anything # should be upgraded B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) rev_deps = packagedb.get_rev_deps(x) for (rev_dep, depinfo) in rev_deps: if ctx.get_option('eager'): # add all upgradable reverse deps if is_upgradable(rev_dep): if not rev_dep in G_f.vertices(): Bp.add(rev_dep) G_f.add_plain_dep(rev_dep, x) else: # add only installed but unsatisfied reverse dependencies if ctx.installdb.is_installed(rev_dep) and \ (not dependency.installed_satisfies_dep(depinfo)): if not dependency.repo_satisfies_dep(depinfo): raise Error( _('Reverse dependency %s of %s cannot be satisfied' ) % (rev_dep, x)) if not rev_dep in G_f.vertices(): Bp.add(rev_dep) G_f.add_plain_dep(rev_dep, x) B = Bp if ctx.config.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() if not ctx.get_option('ignore_file_conflicts'): check_conflicts(order, ctx.packagedb) return G_f, order
def install_pkg_files(package_URIs): """install a number of pisi package files""" from package import Package ctx.ui.debug('A = %s' % str(package_URIs)) for x in package_URIs: if not x.endswith(ctx.const.package_suffix): raise Error( _('Mixing file names and package names not supported yet.')) if ctx.config.get_option('ignore_dependency'): # simple code path then for x in package_URIs: atomicoperations.install_single_file(x) return # short circuit # read the package information into memory first # regardless of which distribution they come from d_t = {} dfn = {} for x in package_URIs: package = Package(x) package.read() name = str(package.metadata.package.name) d_t[name] = package.metadata.package dfn[name] = x def satisfiesDep(dep): # is dependency satisfied among available packages # or packages to be installed? return dependency.installed_satisfies_dep(dep) \ or dependency.dict_satisfies_dep(d_t, dep) # for this case, we have to determine the dependencies # that aren't already satisfied and try to install them # from the repository dep_unsatis = [] for name in d_t.keys(): pkg = d_t[name] deps = pkg.runtimeDependencies() for dep in deps: if not satisfiesDep(dep): dep_unsatis.append(dep) # now determine if these unsatisfied dependencies could # be satisfied by installing packages from the repo # if so, then invoke install_pkg_names extra_packages = [x.package for x in dep_unsatis] if extra_packages: ctx.ui.info( _("""The following packages will be installed in the respective order to satisfy extra dependencies: """) + util.strlist(extra_packages)) if not ctx.ui.confirm(_('Do you want to continue?')): raise Error(_('External dependencies not satisfied')) install_pkg_names(extra_packages) class PackageDB: def get_package(self, key, repo=None): return d_t[str(key)] packagedb = PackageDB() A = d_t.keys() if len(A) == 0: ctx.ui.info(_('No packages to install.')) return # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) for dep in pkg.runtimeDependencies(): if dependency.dict_satisfies_dep(d_t, dep): if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) B = Bp if ctx.config.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() if not ctx.get_option('ignore_file_conflicts'): check_conflicts(order, packagedb) order.reverse() ctx.ui.info(_('Installation order: ') + util.strlist(order)) if ctx.get_option('dry_run'): return ctx.ui.notify(ui.packagestogo, order=order) for x in order: atomicoperations.install_single_file(dfn[x])
def install_pkg_files(package_URIs): """install a number of pisi package files""" from package import Package ctx.ui.debug('A = %s' % str(package_URIs)) for x in package_URIs: if not x.endswith(ctx.const.package_prefix): ctx.ui.error('Mixing file names and package names not supported YET.\n') return False # read the package information into memory first # regardless of which distribution they come from d_t = {} dfn = {} for x in package_URIs: package = Package(x) package.read() name = str(package.metadata.package.name) d_t[name] = package.metadata.package dfn[name] = x def satisfiesDep(dep): return dependency.installed_satisfies_dep(dep) \ or dependency.dict_satisfies_dep(d_t, dep) # for this case, we have to determine the dependencies # that aren't already satisfied and try to install them # from the repository dep_unsatis = [] for name in d_t.keys(): pkg = d_t[name] deps = pkg.runtimeDeps for dep in deps: if not satisfiesDep(dep): dep_unsatis.append(dep) # now determine if these unsatisfied dependencies could # be satisfied by installing packages from the repo # if so, then invoke install_pkg_names extra_packages = [x.package for x in dep_unsatis] if (extra_packages and install_pkg_names(extra_packages)) or \ (not extra_packages): class PackageDB: def __init__(self): self.d = d_t def get_package(self, key): return d_t[str(key)] packagedb = PackageDB() A = d_t.keys() if len(A)==0: ctx.ui.info('No packages to install.') return True # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb print A for x in A: G_f.add_package(x) B = A #state = {} while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) print pkg for dep in pkg.runtimeDeps: print 'checking ', dep if dependency.dict_satisfies_dep(d_t, dep): if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) B = Bp G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() print order for x in order: operations.install_single_file(dfn[x]) else: raise Error('External dependencies not satisfied') return True # everything went OK.
def upgrade_pkg_names(A): """Re-installs packages from the repository, trying to perform a maximum number of upgrades.""" ignore_build = ctx.config.options and ctx.config.options.ignore_build_no # filter packages that are not upgradable Ap = [] for x in A: if not ctx.installdb.is_installed(x): ctx.ui.info('Package %s is not installed.' % x) continue (version, release, build) = ctx.installdb.get_version(x) pkg = packagedb.get_package(x) if ignore_build or (not build): if release < pkg.release: Ap.append(x) elif build < pkg.build: Ap.append(x) else: #ctx.ui.info('Package %s cannot be upgraded. ' % x) ctx.ui.info('Package %s is already at its latest version %s,\ release %s, build %s.' % (x, pkg.version, pkg.release, pkg.build)) A = Ap if len(A)==0: ctx.ui.info('No packages to upgrade.') return True ctx.ui.debug('A = %s' % str(A)) # try to construct a pisi graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A #state = {} while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) print pkg for dep in pkg.runtimeDeps: print 'checking ', dep # add packages that can be upgraded if dependency.repo_satisfies_dep(dep): if ctx.installdb.is_installed(dep.package): (v,r,b) = ctx.installdb.get_version(dep.package) rep_pkg = packagedb.get_package(dep.package) (vp,rp,bp) = (rep_pkg.version, rep_pkg.release, rep_pkg.build) if ignore_build or (not b) or (not bp): # if we can't look at build if r >= rp: # installed already new continue elif b and bp and b >= bp: continue if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) B = Bp G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() print order for x in order: operations.install_single_name(x, True) return True # everything went OK :)
def plan_upgrade(A): # try to construct a pisi graph of packages to # install / reinstall packagedb = ctx.packagedb G_f = pgraph.PGraph(packagedb) # construct G_f # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.add_package(x) B = A def upgradable(dep): #pre dep.package is installed (v,r,b) = ctx.installdb.get_version(dep.package) rep_pkg = packagedb.get_package(dep.package) (vp,rp,bp) = (rep_pkg.version, rep_pkg.release, rep_pkg.build) if ignore_build or (not b) or (not bp): # if we can't look at build if r >= rp: # installed already new return False elif b and bp and b >= bp: return False return True # TODO: conflicts while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) for dep in pkg.runtimeDependencies(): # add packages that can be upgraded if dependency.repo_satisfies_dep(dep): #TODO: distinguish must upgrade and upgradable if ctx.installdb.is_installed(dep.package): if not ctx.get_option('eager'): if dependency.installed_satisfies_dep(dep): continue else: if not upgradable(dep): continue if not dep.package in G_f.vertices(): Bp.add(str(dep.package)) G_f.add_dep(x, dep) else: raise Error(_("Reverse dependency %s cannot be satisfied") % rev_dep) B = Bp # now, search reverse dependencies to see if anything # should be upgraded B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) rev_deps = packagedb.get_rev_deps(x) for (rev_dep, depinfo) in rev_deps: if not ctx.get_option('eager'): # add unsatisfied reverse dependencies if packagedb.has_package(rev_dep) and \ (not dependency.installed_satisfies_dep(depinfo)): if not dependency.repo_satisfies_dep(depinfo): raise Error(_("Reverse dependency %s cannot be satisfied") % rev_dep) if not rev_dep in G_f.vertices(): Bp.add(rev_dep) G_f.add_plain_dep(rev_dep, x) else: if not rev_dep in G_f.vertices(): Bp.add(rev_dep) G_f.add_plain_dep(rev_dep, x) B = Bp if ctx.config.get_option('debug'): G_f.write_graphviz(sys.stdout) order = G_f.topological_sort() order.reverse() check_conflicts(order, ctx.packagedb) return G_f, order
def upgrade_pkg_names(A = []): """Re-installs packages from the repository, trying to perform a maximum number of upgrades.""" ignore_build = ctx.get_option('ignore_build_no') if not A: # if A is empty, then upgrade all packages A = ctx.installdb.list_installed() # filter packages that are not upgradable A_0 = A = expand_components(set(A)) Ap = [] for x in A: if x.endswith(ctx.const.package_suffix): ctx.ui.debug(_("Warning: package *name* ends with '.pisi'")) if not ctx.installdb.is_installed(x): ctx.ui.info(_('Package %s is not installed.') % x) continue (version, release, build) = ctx.installdb.get_version(x) pkg = packagedb.get_package(x) if ignore_build or (not build) or (not pkg.build): if release < pkg.release: Ap.append(x) else: ctx.ui.info(_('Package %s is already at the latest release %s.') % (pkg.name, pkg.release)) else: if build < pkg.build: Ap.append(x) else: ctx.ui.info(_('Package %s is already at the latest build %s.') % (pkg.name, pkg.build)) A = set(Ap) if len(A)==0: ctx.ui.info(_('No packages to upgrade.')) return True ctx.ui.debug('A = %s' % str(A)) if not ctx.config.get_option('ignore_dependency'): G_f, order = plan_upgrade(A) else: G_f = None order = A ctx.ui.info(_("""The following packages will be upgraded:\n""") + util.strlist(order)) if ctx.get_option('dry_run'): return if len(order) > len(A_0): if not ctx.ui.confirm(_('There are extra packages due to dependencies. Do you want to continue?')): return False install_ops = [atomicoperations.Install.from_name(x) for x in order] for install in install_ops: install.install(True)