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 = [str(x) for x in A] #FIXME: why do we still get unicode input here? :/ -- exa # 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 A |= upgrade_base(A) 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( _("""Following packages will be installed in the respective order to satisfy dependencies: """) + util.strlist(order)) total_size = sum([ctx.packagedb.get_package(p).packageSize for p in order]) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_('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) pisi_installed = ctx.installdb.is_installed('pisi') for x in order: atomicoperations.install_single_name(x, True) # allow reinstalls here if 'pisi' in order and pisi_installed: upgrade_pisi()
def emerge(A, rebuild_all=False): # A was a list, remove duplicates and expand components A = [str(x) for x in A] A_0 = A = expand_src_components(set(A)) ctx.ui.debug('A = %s' % str(A)) if len(A) == 0: ctx.ui.info(_('No packages to emerge.')) return #A |= upgrade_base(A) # FIXME: Errr... order_build changes type conditionally and this # is not good. - baris if not ctx.config.get_option('ignore_dependency'): G_f, order_inst, order_build = plan_emerge(A, rebuild_all) else: G_f = None order_inst = [] order_build = A if order_inst: ctx.ui.info( _("""The following minimal list of packages will be installed from repository in the respective order to satisfy dependencies: """) + util.strlist(order_inst)) ctx.ui.info( _("""The following minimal list of packages will be built and installed in the respective order to satisfy dependencies: """) + util.strlist(order_build)) if ctx.get_option('dry_run'): return if len(order_inst) + len(order_build) > 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_inst) pisi_installed = ctx.installdb.is_installed('pisi') for x in order_inst: atomicoperations.install_single_name(x) #ctx.ui.notify(ui.packagestogo, order = order_build) for x in order_build: package_names = atomicoperations.build(x)[0] install_pkg_files(package_names) # handle inter-package deps here # FIXME: take a look at the fixme above :(, we have to be sure # that order_build is a known type... U = set(order_build) U.update(order_inst) if 'pisi' in order_build or (('pisi' in U) and pisi_installed): upgrade_pisi()
def check_conflicts(order, packagedb): """check if upgrading to the latest versions will cause havoc done in a simple minded way without regard for dependencies of conflicts, etc.""" (C, D, pkg_conflicts) = calculate_conflicts(order, packagedb) if D: raise Error( _("Selected packages [%s] are in conflict with each other.") % util.strlist(list(D))) if pkg_conflicts: conflicts = "" for pkg in pkg_conflicts.keys(): conflicts += _("[%s conflicts with: %s]") % ( pkg, util.strlist(pkg_conflicts[pkg])) ctx.ui.info(_("The following packages have conflicts: %s") % conflicts) if not ctx.ui.confirm(_('Remove the following conflicting packages?')): raise Error(_("Conflicts remain")) if remove(list(C), True) == False: raise Error(_("Conflicts remain"))
def print_pkginfo(self, metadata, files, repo = None): import os.path if not ctx.get_option('long'): pkg = metadata.package ctx.ui.info('%15s - %s' % (pkg.name, unicode(pkg.summary))) else: ctx.ui.info(unicode(metadata.package)) if repo: deps = [x.package for x in ctx.packagedb.get_deps(metadata.package.name, repo)] print _('Dependencies:'), util.strlist(deps) revdeps = [x[0] for x in ctx.packagedb.get_rev_deps(metadata.package.name, repo)] print _('Reverse Dependencies:'), util.strlist(revdeps) if self.options.files or self.options.files_path: if files: print _('\nFiles:') for fileinfo in files.list: if self.options.files: print fileinfo else: print fileinfo.path else: ctx.ui.warning(_('File information not available')) if ctx.get_option('long'): print
def check_conflicts(order, packagedb): """check if upgrading to the latest versions will cause havoc done in a simple minded way without regard for dependencies of conflicts, etc.""" (C, D, pkg_conflicts) = pisi.conflict.calculate_conflicts(order, packagedb) if D: raise Exception( _("Selected packages [%s] are in conflict with each other.") % util.strlist(list(D))) if pkg_conflicts: conflicts = "" for pkg in pkg_conflicts.keys(): conflicts += _("[%s conflicts with: %s]\n") % ( pkg, util.strlist(pkg_conflicts[pkg])) ctx.ui.info( _("The following packages have conflicts:\n%s") % conflicts) if not ctx.ui.confirm(_('Remove the following conflicting packages?')): raise Exception( _("Conflicting packages should be removed to continue")) return list(C)
def upgrade_base(A=set(), ignore_package_conflicts=False): ignore_build = ctx.get_option("ignore_build_no") if not ctx.get_option("ignore_safety"): if ctx.componentdb.has_component("system.base"): systembase = set(ctx.componentdb.get_union_comp("system.base").packages) extra_installs = filter(lambda x: not ctx.installdb.is_installed(x), systembase - set(A)) if extra_installs: ctx.ui.warning( _("Safety switch: Following packages in system.base will be installed: ") + util.strlist(extra_installs) ) G_f, install_order = plan_install_pkg_names(extra_installs, ignore_package_conflicts) extra_upgrades = filter(lambda x: is_upgradable(x, ignore_build), systembase - set(install_order)) upgrade_order = [] if extra_upgrades: ctx.ui.warning( _("Safety switch: Following packages in system.base will be upgraded: ") + util.strlist(extra_upgrades) ) G_f, upgrade_order = plan_upgrade(extra_upgrades, ignore_build) # return packages that must be added to any installation return set(install_order + upgrade_order) else: ctx.ui.warning(_("Safety switch: the component system.base cannot be found")) return set()
def upgrade_base(A=set(), ignore_package_conflicts=False): installdb = pisi.db.installdb.InstallDB() componentdb = pisi.db.componentdb.ComponentDB() ignore_build = ctx.get_option('ignore_build_no') if not ctx.get_option('ignore_safety'): if componentdb.has_component('system.base'): systembase = set( componentdb.get_union_component('system.base').packages) extra_installs = filter(lambda x: not installdb.has_package(x), systembase - set(A)) if extra_installs: ctx.ui.warning( _('Safety switch: Following packages in system.base will be installed: ' ) + util.strlist(extra_installs)) G_f, install_order = operations.install.plan_install_pkg_names( extra_installs, ignore_package_conflicts) extra_upgrades = filter(lambda x: is_upgradable(x, ignore_build), systembase - set(install_order)) upgrade_order = [] if extra_upgrades: ctx.ui.warning( _('Safety switch: Following packages in system.base will be upgraded: ' ) + util.strlist(extra_upgrades)) G_f, upgrade_order = plan_upgrade(extra_upgrades) # return packages that must be added to any installation return set(install_order + upgrade_order) else: ctx.ui.warning( _('Safety switch: the component system.base cannot be found')) return set()
def upgrade_base(A=set()): ignore_build = ctx.get_option('ignore_build_no') if not ctx.get_option('bypass_safety'): if ctx.componentdb.has_component('system.base'): systembase = set( ctx.componentdb.get_union_comp('system.base').packages) extra_installs = filter( lambda x: not ctx.installdb.is_installed(x), systembase - A) if extra_installs: ctx.ui.warning( _('Safety switch: Following packages in system.base will be installed: ' ) + util.strlist(extra_installs)) G_f, install_order = install.plan_install_pkg_names(extra_installs) extra_upgrades = filter(lambda x: is_upgradable(x, ignore_build), systembase - set(install_order)) upgrade_order = [] if extra_upgrades: ctx.ui.warning( _('Safety switch: Following packages in system.base will be upgraded: ' ) + util.strlist(extra_upgrades)) G_f, upgrade_order = plan_upgrade(extra_upgrades, ignore_build) # return packages that must be added to any installation return set(install_order + upgrade_order) else: ctx.ui.warning( _('Safety switch: the component system.base cannot be found')) return set()
def upgrade_base(A=set()): installdb = pisi.db.installdb.InstallDB() componentdb = pisi.db.componentdb.ComponentDB() ignore_build = ctx.get_option("ignore_build_no") if not ctx.config.values.general.ignore_safety and not ctx.get_option("ignore_safety"): if componentdb.has_component("system.base"): systembase = set(componentdb.get_union_component("system.base").packages) extra_installs = filter(lambda x: not installdb.has_package(x), systembase - set(A)) if extra_installs: ctx.ui.warning( _("Safety switch: Following packages in system.base will be installed: ") + util.strlist(extra_installs) ) G_f, install_order = operations.install.plan_install_pkg_names(extra_installs) extra_upgrades = filter(lambda x: is_upgradable(x, ignore_build), systembase - set(install_order)) upgrade_order = [] if extra_upgrades: ctx.ui.warning( _("Safety switch: Following packages in system.base will be upgraded: ") + util.strlist(extra_upgrades) ) G_f, upgrade_order = plan_upgrade(extra_upgrades) # return packages that must be added to any installation return set(install_order + upgrade_order) else: ctx.ui.warning(_("Safety switch: the component system.base cannot be found")) return set()
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""" installdb = pisi.db.installdb.InstallDB() A = [str(x) for x in A] #FIXME: why do we still get unicode input here? :/ -- exa # A was a list, remove duplicates A_0 = A = set(A) # filter packages that are already installed if not reinstall: Ap = set(filter(lambda x: not installdb.has_package(x), A)) d = A - Ap if len(d) > 0: ctx.ui.warning(_("The following package(s) are already installed and are not going to be installed again:\n") + util.strlist(d)) A = Ap if len(A)==0: ctx.ui.info(_('No packages to install.')) return True A |= operations.upgrade.upgrade_base(A) if not ctx.config.get_option('ignore_dependency'): G_f, order = plan_install_pkg_names(A) else: G_f = None order = list(A) componentdb = pisi.db.componentdb.ComponentDB() # Bug 4211 if componentdb.has_component('system.base'): order = operations.helper.reorder_base_packages(order) if len(order) > 1: ctx.ui.info(_("Following packages will be installed in the respective " "order to satisfy dependencies:\n") + util.strlist(order)) total_size, cached_size = operations.helper.calculate_download_sizes(order) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_('Total size of package(s): %.2f %s') % (total_size, symbol)) if ctx.get_option('dry_run'): return True if set(order) - 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, True) # allow reinstalls here return True
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 = [str(x) for x in A] # FIXME: why do we still get unicode input here? :/ -- exa # 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( _("The following package(s) are already installed and are not going to be installed again:\n") + util.strlist(d) ) A = Ap if len(A) == 0: ctx.ui.info(_("No packages to install.")) return A |= upgrade_base(A) if not ctx.config.get_option("ignore_dependency"): G_f, order = plan_install_pkg_names(A) else: G_f = None order = list(A) if len(order) > 1: ctx.ui.info( _("Following packages will be installed in the respective " "order to satisfy dependencies:\n") + util.strlist(order) ) total_size = sum([ctx.packagedb.get_package(p).packageSize for p in order]) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_("Total size of package(s): %.2f %s") % (total_size, symbol)) if ctx.get_option("dry_run"): return if set(order) - 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) pisi_installed = ctx.installdb.is_installed("pisi") for x in order: atomicoperations.install_single_name(x, True) # allow reinstalls here if "pisi" in order and pisi_installed: upgrade_pisi()
def remove(A, ignore_dep=None): """remove set A of packages from system (A is a list of package names)""" A = [str(x) for x in A] # filter packages that are not installed A_0 = A = expand_components(set(A)) if not ctx.get_option('bypass_safety'): if ctx.componentdb.has_component('system.base'): systembase = set( ctx.componentdb.get_union_comp('system.base').packages) refused = A.intersection(systembase) if refused: ctx.ui.warning( _('Safety switch: cannot remove the following packages in system.base: ' ) + util.strlist(refused)) A = A - systembase else: ctx.ui.warning( _('Safety switch: the component system.base cannot be found')) 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 False if not ctx.config.get_option('ignore_dependency') and not ignore_dep: G_f, order = plan_remove(A) else: G_f = None order = A 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 if ctx.get_option('dry_run'): return ctx.ui.notify(ui.packagestogo, order=order) 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 remove(A, ignore_dep = False, ignore_safety = False): """remove set A of packages from system (A is a list of package names)""" componentdb = pisi.db.componentdb.ComponentDB() installdb = pisi.db.installdb.InstallDB() A = [str(x) for x in A] # filter packages that are not installed A_0 = A = set(A) if not ctx.get_option('ignore_safety') and not ctx.config.values.general.ignore_safety and not ignore_safety: if componentdb.has_component('system.base'): systembase = set(componentdb.get_union_component('system.base').packages) refused = A.intersection(systembase) if refused: raise pisi.Error(_('Safety switch: cannot remove the following packages in system.base: ') + util.strlist(refused)) A = A - systembase else: ctx.ui.warning(_('Safety switch: the component system.base cannot be found')) Ap = [] for x in A: if installdb.has_package(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 False if not ctx.config.get_option('ignore_dependency') and not ignore_dep: G_f, order = plan_remove(A) else: G_f = None order = A 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 if ctx.get_option('dry_run'): return ctx.ui.notify(ui.packagestogo, order = order) for x in order: if installdb.has_package(x): atomicoperations.remove_single(x) else: ctx.ui.info(_('Package %s is not installed. Cannot remove.') % x)
def install_pkg_names(A, reinstall = False, bypass_safety = False): """This is the real thing. It installs packages from the repository, trying to perform a minimum number of installs""" A = [str(x) for x in A] #FIXME: why do we still get unicode input here? :/ -- exa # A was a list, remove duplicates and expand components A_0 = A = expand_components(set(A)) ctx.ui.debug('A = %s' % str(A)) if not bypass_safety: upgrade_base(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(_("""Following packages will be installed in the respective order to satisfy dependencies: """) + util.strlist(order)) total_size = sum([ctx.packagedb.get_package(p).packageSize for p in order]) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_('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) pisi_installed = ctx.installdb.is_installed('pisi') for x in order: atomicoperations.install_single_name(x) if not bypass_safety and 'pisi' in order and pisi_installed: upgrade_pisi()
def emerge(A, rebuild_all = False): # A was a list, remove duplicates and expand components A = [str(x) for x in A] A_0 = A = expand_src_components(set(A)) ctx.ui.debug('A = %s' % str(A)) if len(A)==0: ctx.ui.info(_('No packages to emerge.')) return #A |= upgrade_base(A) # FIXME: Errr... order_build changes type conditionally and this # is not good. - baris if not ctx.config.get_option('ignore_dependency'): G_f, order_inst, order_build = plan_emerge(A, rebuild_all) else: G_f = None order_inst = [] order_build = A if order_inst: ctx.ui.info(_("""The following minimal list of packages will be installed from repository in the respective order to satisfy dependencies: """) + util.strlist(order_inst)) ctx.ui.info(_("""The following minimal list of packages will be built and installed in the respective order to satisfy dependencies: """) + util.strlist(order_build)) if ctx.get_option('dry_run'): return if len(order_inst) + len(order_build) > 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_inst) pisi_installed = ctx.installdb.is_installed('pisi') for x in order_inst: atomicoperations.install_single_name(x) #ctx.ui.notify(ui.packagestogo, order = order_build) for x in order_build: package_names = atomicoperations.build(x)[0] install_pkg_files(package_names) # handle inter-package deps here # FIXME: take a look at the fixme above :(, we have to be sure # that order_build is a known type... U = set(order_build) U.update(order_inst) if 'pisi' in order_build or (('pisi' in U) and pisi_installed): upgrade_pisi()
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 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 = expand_components(set(A)) if not ctx.get_option('bypass_safety'): if ctx.componentdb.has_component('system.base'): refused = A.intersection(set(ctx.componentdb.get_component('system.base').packages)) if refused: ctx.ui.warning(_('Safety switch: cannot remove the following packages in system.base: ') + util.strlist(refused)) A = A - set(ctx.componentdb.get_component('system.base').packages) else: ctx.ui.warning(_('Safety switch: the component system.base cannot be found')) 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 False if not ctx.config.get_option('ignore_dependency'): G_f, order = plan_remove(A) else: G_f = None order = A 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 if ctx.get_option('dry_run'): return ctx.ui.notify(ui.packagestogo, order = order) 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 emerge(A, rebuild_all=False): # A was a list, remove duplicates and expand components A_0 = A = expand_src_components(set(A)) ctx.ui.debug("A = %s" % str(A)) if len(A) == 0: ctx.ui.info(_("No packages to emerge.")) return if not ctx.config.get_option("ignore_dependency"): G_f, order_inst, order_build = plan_emerge(A, rebuild_all) else: G_f = None order_inst = [] order_build = A if order_inst: ctx.ui.info( _( """The following minimal list of packages will be installed from repository in the respective order to satisfy dependencies: """ ) + util.strlist(order_inst) ) ctx.ui.info( _( """The following minimal list of packages will be built and installed in the respective order to satisfy dependencies: """ ) + util.strlist(order_build) ) if ctx.get_option("dry_run"): return if len(order_inst) + len(order_build) > 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_inst) for x in order_inst: atomicoperations.install_single_name(x) # ctx.ui.notify(ui.packagestogo, order = order_build) for x in order_build: package_names, blah = atomicoperations.build(x) install_pkg_files(package_names) # handle inter-package deps here
def check_build_dependencies(self): """check and try to install build dependencies, otherwise fail.""" build_deps = self.spec.source.buildDependencies for package in self.spec.packages: build_deps.extend(package.buildDependencies) if not ctx.config.values.general.ignore_safety and \ not ctx.get_option('ignore_safety'): if self.componentdb.has_component('system.devel'): build_deps_names = set([x.package for x in build_deps]) devel_deps_names = set(self.componentdb.get_component('system.devel').packages) extra_names = devel_deps_names - build_deps_names extra_names = filter(lambda x: not self.installdb.has_package(x), extra_names) if extra_names: ctx.ui.warning(_('Safety switch: following extra packages in system.devel will be installed: ') + util.strlist(extra_names)) extra_deps = [dependency.Dependency(package=x) for x in extra_names] build_deps.extend(extra_deps) else: ctx.ui.info(_('Safety switch: system.devel is already installed')) else: ctx.ui.warning(_('Safety switch: the component system.devel cannot be found')) # find out the build dependencies that are not satisfied... dep_unsatis = [] for dep in build_deps: if not dep.satisfied_by_installed(): dep_unsatis.append(dep) if dep_unsatis: ctx.ui.info(_("Unsatisfied Build Dependencies:") + ' ' + util.strlist([str(x) for x in dep_unsatis])) def fail(): raise Error(_('Cannot build package due to unsatisfied build dependencies')) if not ctx.config.get_option('ignore_dependency'): for dep in dep_unsatis: if not dep.satisfied_by_repo(): raise Error(_('Build dependency %s cannot be satisfied') % str(dep)) if ctx.ui.confirm( _('Do you want to install the unsatisfied build dependencies')): ctx.ui.info(_('Installing build dependencies.')) if not pisi.api.install([dep.package for dep in dep_unsatis], reinstall=True): fail() else: fail() else: ctx.ui.warning(_('Ignoring build dependencies.'))
def emerge(A, rebuild_all = False, bypass_safety = False): # A was a list, remove duplicates and expand components A = [str(x) for x in A] A_0 = A = expand_src_components(set(A)) ctx.ui.debug('A = %s' % str(A)) if len(A)==0: ctx.ui.info(_('No packages to emerge.')) return #if not bypass_safety: # A |= upgrade_base(A) if not ctx.config.get_option('ignore_dependency'): G_f, order_inst, order_build = plan_emerge(A, rebuild_all) else: G_f = None order_inst = [] order_build = A if order_inst: ctx.ui.info(_("""The following minimal list of packages will be installed from repository in the respective order to satisfy dependencies: """) + util.strlist(order_inst)) ctx.ui.info(_("""The following minimal list of packages will be built and installed in the respective order to satisfy dependencies: """) + util.strlist(order_build)) if ctx.get_option('dry_run'): return if len(order_inst) + len(order_build) > 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_inst) pisi_installed = ctx.installdb.is_installed('pisi') for x in order_inst: atomicoperations.install_single_name(x) #ctx.ui.notify(ui.packagestogo, order = order_build) for x in order_build: package_names, blah = atomicoperations.build(x) install_pkg_files(package_names) # handle inter-package deps here if 'pisi' in order_build or ( ('pisi' in order_inst + order_build) and pisi_installed): upgrade_pisi()
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 print_pkginfo(self, metadata, files, repo=None): if ctx.get_option('short'): pkg = metadata.package ctx.ui.info('%15s - %s' % (pkg.name, unicode(pkg.summary))) else: ctx.ui.info(unicode(metadata.package)) if repo: revdeps = [ x[0] for x in ctx.packagedb.get_rev_deps( metadata.package.name, repo) ] print _('Reverse Dependencies:'), util.strlist(revdeps) if self.options.files or self.options.files_path: if files: print _('\nFiles:') files.list.sort(key=lambda x: x.path) for fileinfo in files.list: if self.options.files: print fileinfo else: print fileinfo.path else: ctx.ui.warning(_('File information not available')) if not self.options.short: print
def upgrade_base(A = set()): ignore_build = ctx.get_option('ignore_build_no') if not ctx.get_option('bypass_safety'): if ctx.componentdb.has_component('system.base'): systembase = set(ctx.componentdb.get_union_comp('system.base').packages) extra_installs = filter(lambda x: not ctx.installdb.is_installed(x), systembase - A) if extra_installs: ctx.ui.warning(_('Safety switch: Following packages in system.base will be installed: ') + util.strlist(extra_installs)) install_pkg_names(extra_installs, bypass_safety=True) extra_upgrades = filter(lambda x: is_upgradable(x, ignore_build), systembase) if extra_upgrades: ctx.ui.warning(_('Safety switch: Following packages in system.base will be upgraded: ') + util.strlist(extra_upgrades)) upgrade_pkg_names(extra_upgrades, bypass_safety=True) else: ctx.ui.warning(_('Safety switch: the component system.base cannot be found'))
def check_build_dependencies(self): """fail if dependencies not satisfied""" build_deps = self.spec.source.buildDependencies if not ctx.get_option("bypass_safety"): if ctx.componentdb.has_component("system.devel"): build_deps_names = set([x.package for x in build_deps]) devel_deps_names = set(ctx.componentdb.get_component("system.devel").packages) extra_names = devel_deps_names - build_deps_names extra_names = filter(lambda x: not ctx.installdb.is_installed(x), extra_names) if extra_names: ctx.ui.warning( _("Safety switch: following extra packages in system.devel will be installed: ") + util.strlist(extra_names) ) extra_deps = [dependency.Dependency(package=x) for x in extra_names] build_deps.extend(extra_deps) else: ctx.ui.warning(_("Safety switch: system.devel is already installed")) else: ctx.ui.warning(_("Safety switch: the component system.devel cannot be found")) # find out the build dependencies that are not satisfied... dep_unsatis = [] for dep in build_deps: if not dependency.installed_satisfies_dep(dep): dep_unsatis.append(dep) if dep_unsatis: ctx.ui.info(_("Unsatisfied Build Dependencies:") + " " + util.strlist([str(x) for x in dep_unsatis])) for dep in dep_unsatis: if not dependency.repo_satisfies_dep(dep): raise Error(_("Build dependency %s cannot be satisfied") % str(dep)) ctx.ui.warning(str(dep)) if not ctx.config.get_option("ignore_dependency"): if ctx.ui.confirm(_("Do you want to install the unsatisfied build dependencies")): ctx.ui.info(_("Installing build dependencies.")) operations.install([dep.package for dep in dep_unsatis]) else: raise Error(_("Cannot build package due to unsatisfied build dependencies")) else: ctx.ui.warning(_("Ignoring build dependencies."))
def print_specdata(self, spec, sourcedb=None): src = spec.source if ctx.get_option('short'): ctx.ui.info('%15s - %s' % (src.name, unicode(src.summary))) else: ctx.ui.info(unicode(spec)) if sourcedb: revdeps = [name for name, dep in sourcedb.get_rev_deps(spec.source.name)] print _('Reverse Build Dependencies:'), util.strlist(revdeps) print
def print_metadata(self, metadata, packagedb=None): if ctx.get_option('short'): pkg = metadata.package ctx.ui.formatted_output(" - ".join((pkg.name, unicode(pkg.summary)))) else: ctx.ui.formatted_output(unicode(metadata.package)) if packagedb: revdeps = [name for name, dep in packagedb.get_rev_deps(metadata.package.name)] ctx.ui.formatted_output(" ".join((_("Reverse Dependencies:"), util.strlist(revdeps)))) print
def print_metadata(self, metadata, packagedb=None): if ctx.get_option('short'): pkg = metadata.package ctx.ui.info('%15s - %s' % (pkg.name, unicode(pkg.summary))) else: ctx.ui.info(unicode(metadata.package)) if packagedb: revdeps = [name for name, dep in packagedb.get_rev_deps(metadata.package.name)] print _('Reverse Dependencies:'), util.strlist(revdeps) print
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 check_conflicts(order, packagedb): """check if upgrading to the latest versions will cause havoc done in a simple minded way without regard for dependencies of conflicts, etc.""" (C, D, pkg_conflicts) = calculate_conflicts(order, packagedb) if D: raise Error(_("Selected packages [%s] are in conflict with each other.") % util.strlist(list(D))) if pkg_conflicts: conflicts = "" for pkg in pkg_conflicts.keys(): conflicts += _("[%s conflicts with: %s]\n") % (pkg, util.strlist(pkg_conflicts[pkg])) ctx.ui.info(_("The following packages have conflicts:\n%s") % conflicts) if not ctx.ui.confirm(_("Remove the following conflicting packages?")): raise Error(_("Conflicts remain")) return list(C)
def upgrade_base(A=set()): ignore_build = ctx.get_option("ignore_build_no") if not ctx.get_option("bypass_safety"): if ctx.componentdb.has_component("system.base"): extra_packages = set(ctx.componentdb.get_component("system.base").packages) - A extra_installs = filter(lambda x: not ctx.installdb.is_installed(x), extra_packages) if extra_installs: ctx.ui.warning( _("Safety switch: Following packages in system.base will be installed: ") + util.strlist(extra_installs) ) install_pkg_names(extra_installs, bypass_safety=True) # A |= extra_installs extra_upgrades = filter(lambda x: is_upgradable(x, ignore_build), extra_packages) if extra_upgrades: ctx.ui.warning( _("Safety switch: Following packages in system.base will be upgraded: ") + util.strlist(extra_upgrades) ) upgrade_pkg_names(extra_upgrades, bypass_safety=True) else: ctx.ui.warning(_("Safety switch: the component system.base cannot be found"))
def print_specdata(self, spec, sourcedb=None): src = spec.source if ctx.get_option('short'): ctx.ui.formatted_output(" - ".join((src.name, str(src.summary)))) else: ctx.ui.formatted_output(str(spec)) if sourcedb: revdeps = [ name for name, dep in sourcedb.get_rev_deps(spec.source.name) ] print(_('Reverse Build Dependencies:'), util.strlist(revdeps)) print()
def print_metadata(self, metadata, packagedb=None): if ctx.get_option('short'): pkg = metadata.package ctx.ui.formatted_output(" - ".join((pkg.name, str(pkg.summary)))) else: ctx.ui.formatted_output(str(metadata.package)) if packagedb: revdeps = [ name for name, dep in packagedb.get_rev_deps( metadata.package.name) ] ctx.ui.formatted_output(" ".join( (_("Reverse Dependencies:"), util.strlist(revdeps)))) print()
def print_pkginfo(self, metadata, files): import os.path ctx.ui.info(unicode(metadata.package)) revdeps = [x[0] for x in packagedb.get_rev_deps(metadata.package.name)] print _('Reverse Dependencies:'), util.strlist(revdeps) if self.options.files or self.options.files_path: if files: print _('\nFiles:') for fileinfo in files.list: if self.options.files: print fileinfo else: print fileinfo.path else: ctx.ui.warning(_('File information not available')) print
def check_build_dependencies(self): """fail if dependencies not satisfied""" build_deps = set(self.spec.source.buildDependencies) if not ctx.get_option('bypass_safety'): if ctx.componentdb.has_component('system.devel'): build_deps_names = set([x.package for x in build_deps]) devel_deps_names = set(ctx.componentdb.get_component('system.devel').packages) extra_names = devel_deps_names - build_deps_names ctx.ui.warning(_('Safety switch: following extra packages in system.devel will be installed: ') + util.strlist(extra_names)) extra_deps = [dependency.Dependency(package = x) for x in extra_names] build_deps = build_deps.union(extra_deps) else: ctx.ui.warning(_('Safety switch: the component system.devel cannot be found')) # find out the build dependencies that are not satisfied... dep_unsatis = [] for dep in build_deps: if not dependency.installed_satisfies_dep(dep): dep_unsatis.append(dep) if dep_unsatis: ctx.ui.info(_("Unsatisfied Build Dependencies:")) for dep in dep_unsatis: ctx.ui.warning(dep.package) if not ctx.config.get_option('ignore_dependency'): if ctx.ui.confirm( _('Do you want to install the unsatisfied build dependencies')): ctx.ui.info(_('Installing build dependencies.')) operations.install([dep.package for dep in dep_unsatis]) else: raise Error(_('Cannot build package due to unsatisfied build dependencies')) else: ctx.ui.warning(_('Ignoring build dependencies.'))
def pisi_installed(*args): packages = util.strlist(args).rstrip() os.system("pisi -D%s install %s" % (consts.pisi_db, packages))
def pisi_removed(*args): packages = util.strlist(args).rstrip() os.system("pisi -D%s remove %s" % (consts.pisi_db, packages))
def pisi_upgraded(*args): packages = util.strlist(args).rstrip() os.system("pisi -D%s upgrade %s" % (consts.pisi_db, packages))
def install_pkg_files(package_URIs, reinstall = False): """install a number of pisi package files""" installdb = pisi.db.installdb.InstallDB() ctx.ui.debug('A = %s' % str(package_URIs)) for x in package_URIs: if not x.endswith(ctx.const.package_suffix): raise Exception(_('Mixing file names and package names not supported yet.')) # filter packages that are already installed tobe_installed, already_installed = [], set() if not reinstall: for x in package_URIs: if not x.endswith(ctx.const.delta_package_suffix) and x.endswith(ctx.const.package_suffix): pkg_name, pkg_version = pisi.util.parse_package_name(os.path.basename(x)) if installdb.has_package(pkg_name): already_installed.add(pkg_name) else: tobe_installed.append(x) if already_installed: ctx.ui.warning(_("The following package(s) are already installed " "and are not going to be installed again:")) ctx.ui.info(util.format_by_columns(sorted(already_installed))) package_URIs = tobe_installed if ctx.config.get_option('ignore_dependency'): # simple code path then for x in package_URIs: atomicoperations.install_single_file(x, reinstall) return True # read the package information into memory first # regardless of which distribution they come from d_t = {} dfn = {} for x in package_URIs: try: package = pisi.package.Package(x) package.read() except zipfile.BadZipfile: # YALI needed to get which file is broken raise zipfile.BadZipfile(x) name = str(package.metadata.package.name) d_t[name] = package.metadata.package dfn[name] = x # check packages' DistributionReleases and Architecture if not ctx.get_option('ignore_check'): for x in d_t.keys(): pkg = d_t[x] if pkg.distributionRelease != ctx.config.values.general.distribution_release: raise Exception(_('Package %s is not compatible with your distribution release %s %s.') \ % (x, ctx.config.values.general.distribution, \ ctx.config.values.general.distribution_release)) if pkg.architecture != ctx.config.values.general.architecture: raise Exception(_('Package %s (%s) is not compatible with your %s architecture.') \ % (x, pkg.architecture, ctx.config.values.general.architecture)) def satisfiesDep(dep): # is dependency satisfied among available packages # or packages to be installed? return dep.satisfied_by_installed() or dep.satisfied_by_dict_repo(d_t) # 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) and dep.package not in [x.package for x in dep_unsatis]: dep_unsatis.append(dep) # now determine if these unsatisfied dependencies could # be satisfied by installing packages from the repo for dep in dep_unsatis: if not dep.satisfied_by_repo(): raise Exception(_('External dependencies not satisfied: %s') % dep) # if so, then invoke install_pkg_names extra_packages = [x.package for x in dep_unsatis] if extra_packages: ctx.ui.warning(_("The following packages will be installed " "in order to satisfy dependencies:")) ctx.ui.info(util.format_by_columns(sorted(extra_packages))) if not ctx.ui.confirm(_('Do you want to continue?')): raise Exception(_('External dependencies not satisfied')) install_pkg_names(extra_packages, reinstall=True, extra=True) 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 dep.satisfied_by_dict_repo(d_t): 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_package_conflicts'): conflicts = operations.helper.check_conflicts(order, packagedb) if conflicts: operations.remove.remove_conflicting_packages(conflicts) order.reverse() ctx.ui.info(_('Installation order: ') + util.strlist(order) ) if ctx.get_option('dry_run'): return True ctx.ui.notify(ui.packagestogo, order = order) for x in order: atomicoperations.install_single_file(dfn[x], reinstall) return True
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""" installdb = pisi.db.installdb.InstallDB() packagedb = pisi.db.packagedb.PackageDB() A = [str(x) for x in A] #FIXME: why do we still get unicode input here? :/ -- exa # A was a list, remove duplicates A_0 = A = set(A) # filter packages that are already installed if not reinstall: Ap = set(filter(lambda x: not installdb.has_package(x), A)) d = A - Ap if len(d) > 0: ctx.ui.warning( _("The following package(s) are already installed and are not going to be installed again:\n" ) + util.strlist(d)) A = Ap if len(A) == 0: ctx.ui.info(_('No packages to install.')) return True A |= operations.upgrade.upgrade_base(A) if not ctx.config.get_option('ignore_dependency'): G_f, order = plan_install_pkg_names(A) else: G_f = None order = list(A) componentdb = pisi.db.componentdb.ComponentDB() # Bug 4211 if componentdb.has_component('system.base'): order = operations.helper.reorder_base_packages(order) if len(order) > 1: ctx.ui.info( _("Following packages will be installed in the respective " "order to satisfy dependencies:\n") + util.strlist(order)) total_size, cached_size = operations.helper.calculate_download_sizes(order) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_('Total size of package(s): %.2f %s') % (total_size, symbol)) if ctx.get_option('dry_run'): return True if set(order) - 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) ignore_dep = ctx.config.get_option('ignore_dependency') conflicts = [] if not ctx.get_option('ignore_package_conflicts'): conflicts = operations.helper.check_conflicts(order, packagedb) paths = [] for x in order: ctx.ui.info( util.colorize( _("Downloading %d / %d") % (order.index(x) + 1, len(order)), "yellow")) install_op = atomicoperations.Install.from_name(x) paths.append(install_op.package_fname) # fetch to be installed packages but do not install them. if ctx.get_option('fetch_only'): return if conflicts: operations.remove.remove_conflicting_packages(conflicts) for path in paths: ctx.ui.info( util.colorize( _("Installing %d / %d") % (paths.index(path) + 1, len(paths)), "yellow")) install_op = atomicoperations.Install(path) install_op.install(False) return True
def install_pkg_files(package_URIs): """install a number of pisi package files""" ctx.ui.debug('A = %s' % str(package_URIs)) for x in package_URIs: if not x.endswith(ctx.const.package_suffix): raise Exception( _('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 True # read the package information into memory first # regardless of which distribution they come from d_t = {} dfn = {} for x in package_URIs: package = pisi.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) and dep not in dep_unsatis: dep_unsatis.append(dep) # now determine if these unsatisfied dependencies could # be satisfied by installing packages from the repo for dep in dep_unsatis: if not dependency.repo_satisfies_dep(dep): raise Exception(_('External dependencies not satisfied: %s') % dep) # 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 Exception(_('External dependencies not satisfied')) install_pkg_names(extra_packages, reinstall=True) 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_package_conflicts'): conflicts = operations.helper.check_conflicts(order, packagedb) if conflicts: operations.remove.remove_conflicting_packages(conflicts) order.reverse() ctx.ui.info(_('Installation order: ') + util.strlist(order)) if ctx.get_option('dry_run'): return True ctx.ui.notify(ui.packagestogo, order=order) for x in order: atomicoperations.install_single_file(dfn[x]) return True
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 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) # First check version. If they are same, check release. Again # if releases are same and checking buildno is premitted, # check build number. if version < pkg.version: Ap.append(x) elif version == pkg.version: if release < pkg.release: Ap.append(x) if release == pkg.release and build and not ignore_build: if 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 = 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 for x in order: atomicoperations.install_single_name(x, True)
def check_build_dependencies(self): """check and try to install build dependencies, otherwise fail.""" build_deps = self.spec.source.buildDependencies if not ctx.get_option('bypass_safety'): if ctx.componentdb.has_component('system.devel'): build_deps_names = set([x.package for x in build_deps]) devel_deps_names = set( ctx.componentdb.get_component('system.devel').packages) extra_names = devel_deps_names - build_deps_names extra_names = filter( lambda x: not ctx.installdb.is_installed(x), extra_names) if extra_names: ctx.ui.warning( _('Safety switch: following extra packages in system.devel will be installed: ' ) + util.strlist(extra_names)) extra_deps = [ dependency.Dependency(package=x) for x in extra_names ] build_deps.extend(extra_deps) else: ctx.ui.warning( _('Safety switch: system.devel is already installed')) else: ctx.ui.warning( _('Safety switch: the component system.devel cannot be found' )) # find out the build dependencies that are not satisfied... dep_unsatis = [] for dep in build_deps: if not dependency.installed_satisfies_dep(dep): dep_unsatis.append(dep) if dep_unsatis: ctx.ui.info( _("Unsatisfied Build Dependencies:") + ' ' + util.strlist([str(x) for x in dep_unsatis])) def fail(): raise Error( _('Cannot build package due to unsatisfied build dependencies' )) if ctx.config.get_option('no_install'): fail() if not ctx.config.get_option('ignore_dependency'): for dep in dep_unsatis: if not dependency.repo_satisfies_dep(dep): raise Error( _('Build dependency %s cannot be satisfied') % str(dep)) if ctx.ui.confirm( _('Do you want to install the unsatisfied build dependencies' )): ctx.ui.info(_('Installing build dependencies.')) operations.install([dep.package for dep in dep_unsatis]) else: fail() else: ctx.ui.warning(_('Ignoring build dependencies.'))
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 = ctx.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), True) 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), True) 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 ctx.ui.notify(ui.packagestogo, order = order) install_ops = [atomicoperations.Install.from_name(x) for x in order] for install in install_ops: install.install(True)
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""" installdb = pisi.db.installdb.InstallDB() packagedb = pisi.db.packagedb.PackageDB() A = [str(x) for x in A] # FIXME: why do we still get unicode input here? :/ -- exa # A was a list, remove duplicates A_0 = A = set(A) # filter packages that are already installed if not reinstall: Ap = set(filter(lambda x: not installdb.has_package(x), A)) d = A - Ap if len(d) > 0: ctx.ui.warning( _("The following package(s) are already installed and are not going to be installed again:\n") + util.strlist(d) ) A = Ap if len(A) == 0: ctx.ui.info(_("No packages to install.")) return True A |= operations.upgrade.upgrade_base(A) if not ctx.config.get_option("ignore_dependency"): G_f, order = plan_install_pkg_names(A) else: G_f = None order = list(A) componentdb = pisi.db.componentdb.ComponentDB() # Bug 4211 if componentdb.has_component("system.base"): order = operations.helper.reorder_base_packages(order) if len(order) > 1: ctx.ui.info( _("Following packages will be installed in the respective " "order to satisfy dependencies:\n") + util.strlist(order) ) total_size, cached_size = operations.helper.calculate_download_sizes(order) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_("Total size of package(s): %.2f %s") % (total_size, symbol)) if ctx.get_option("dry_run"): return True if set(order) - 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) ignore_dep = ctx.config.get_option("ignore_dependency") conflicts = [] if not ctx.get_option("ignore_package_conflicts"): conflicts = operations.helper.check_conflicts(order, packagedb) paths = [] for x in order: ctx.ui.info(util.colorize(_("Downloading %d / %d") % (order.index(x) + 1, len(order)), "yellow")) install_op = atomicoperations.Install.from_name(x) paths.append(install_op.package_fname) # fetch to be installed packages but do not install them. if ctx.get_option("fetch_only"): return if conflicts: operations.remove.remove_conflicting_packages(conflicts) for path in paths: ctx.ui.info(util.colorize(_("Installing %d / %d") % (paths.index(path) + 1, len(paths)), "yellow")) install_op = atomicoperations.Install(path) install_op.install(False) return True
def upgrade_pkg_names(A=[]): """Re-installs packages from the repository, trying to perform a minimum or maximum number of upgrades according to options.""" ignore_build = ctx.get_option('ignore_build_no') security_only = ctx.get_option('security_only') packagedb = pisi.db.packagedb.PackageDB() replaces = packagedb.get_replaces() installdb = pisi.db.installdb.InstallDB() if not A: # if A is empty, then upgrade all packages A = installdb.list_installed() A_0 = A = set(A) Ap = [] for x in A: if x.endswith(ctx.const.package_suffix): ctx.ui.debug(_("Warning: package *name* ends with '.pisi'")) # Handling of replacement packages if x in replaces.values(): Ap.append(x) continue if x in replaces.keys(): Ap.append(replaces[x]) continue if not installdb.has_package(x): ctx.ui.info(_('Package %s is not installed.') % x, True) continue (version, release, build) = installdb.get_version(x) if packagedb.has_package(x): pkg = packagedb.get_package(x) else: ctx.ui.info( _('Package %s is not available in repositories.') % x, True) continue if security_only: updates = [ i for i in pkg.history if pisi.version.Version(i.release) > pisi.version.Version(release) ] if not pisi.util.any(lambda i: i.type == 'security', updates): continue if ignore_build or (not build) or (not pkg.build): if pisi.version.Version(release) < pisi.version.Version( pkg.release): Ap.append(x) else: ctx.ui.info( _('Package %s is already at the latest release %s.') % (pkg.name, pkg.release), True) 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), True) A = set(Ap) if len(A) == 0: ctx.ui.info(_('No packages to upgrade.')) return True A |= upgrade_base(A) 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 = list(A) componentdb = pisi.db.componentdb.ComponentDB() # Bug 4211 if componentdb.has_component('system.base'): order = operations.helper.reorder_base_packages(order) if not ctx.get_option('ignore_package_conflicts'): conflicts = operations.helper.check_conflicts(order, packagedb) ctx.ui.info( _('The following packages will be upgraded: ') + util.strlist(order)) total_size, cached_size = operations.helper.calculate_download_sizes(order) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_('Total size of package(s): %.2f %s') % (total_size, symbol)) if ctx.get_option('dry_run'): return if set(order) - A_0 - set(replaces.values()): 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) paths = [] for x in order: ctx.ui.info( util.colorize( _("Downloading %d / %d") % (order.index(x) + 1, len(order)), "yellow")) install_op = atomicoperations.Install.from_name(x) paths.append(install_op.package_fname) # fetch to be upgraded packages but do not install them. if ctx.get_option('fetch_only'): return if not ctx.get_option('ignore_package_conflicts'): if conflicts: operations.remove.remove_conflicting_packages(conflicts) if replaces: operations.remove.remove_replaced_packages(order, replaces) operations.remove.remove_obsoleted_packages() for path in paths: ctx.ui.info( util.colorize( _("Installing %d / %d") % (paths.index(path) + 1, len(paths)), "yellow")) install_op = atomicoperations.Install(path, ignore_file_conflicts=True) install_op.install(True)
def upgrade_pkg_names(A = []): """Re-installs packages from the repository, trying to perform a minimum or maximum number of upgrades according to options.""" ignore_build = ctx.get_option('ignore_build_no') security = ctx.get_option('security') if not A: # if A is empty, then upgrade all packages A = ctx.installdb.list_installed() 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, True) continue (version, release, build) = ctx.installdb.get_version(x) if ctx.packagedb.has_package(x): pkg = ctx.packagedb.get_package(x) else: ctx.ui.info(_('Package %s is not available in repositories.') % x, True) continue if security: # below is a readable functional code, don't overflow lines! updates = [i for i in pkg.history if Version(i.release) > Version(release)] if not pisi.util.any(lambda i:i.type == 'security', updates): continue if ignore_build or (not build) or (not pkg.build): if Version(release) < Version(pkg.release): Ap.append(x) else: ctx.ui.info(_('Package %s is already at the latest release %s.') % (pkg.name, pkg.release), True) 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), True) A = set(Ap) if len(A)==0: ctx.ui.info(_('No packages to upgrade.')) return True A |= upgrade_base(A) ctx.ui.debug('A = %s' % str(A)) if not ctx.config.get_option('ignore_dependency'): G_f, order = plan_upgrade(A, ignore_build) else: G_f = None order = A ctx.ui.info(_('The following packages will be upgraded: ') + util.strlist(order)) total_size = sum([ctx.packagedb.get_package(p).packageSize for p in order]) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_('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) paths = [] for x in order: install_op = atomicoperations.Install.from_name(x) paths.append(install_op.package_fname) # fetch to be upgraded packages but do not install them. if ctx.get_option('fetch_only'): return for path in paths: install_op = atomicoperations.Install(path, ignore_file_conflicts = True) install_op.install(True) if 'pisi' in order: upgrade_pisi()
def upgrade_pkg_names(A=[]): """Re-installs packages from the repository, trying to perform a minimum or maximum number of upgrades according to options.""" ignore_build = ctx.get_option('ignore_build_no') security = ctx.get_option('security') if not A: # if A is empty, then upgrade all packages A = ctx.installdb.list_installed() A_0 = A = component.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, True) continue (version, release, build) = ctx.installdb.get_version(x) if ctx.packagedb.has_package(x): pkg = ctx.packagedb.get_package(x) else: ctx.ui.info( _('Package %s is not available in repositories.') % x, True) continue if security: # below is a readable functional code, don't overflow lines! updates = [ x for x in pkg.history if Version(x.release) > Version(release) ] if not pisi.util.any(lambda x: x.type == 'security', updates): continue if ignore_build or (not build) or (not pkg.build): if Version(release) < Version(pkg.release): Ap.append(x) else: ctx.ui.info( _('Package %s is already at the latest release %s.') % (pkg.name, pkg.release), True) 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), True) A = set(Ap) if len(A) == 0: ctx.ui.info(_('No packages to upgrade.')) return True A |= upgrade_base(A) ctx.ui.debug('A = %s' % str(A)) if not ctx.config.get_option('ignore_dependency'): G_f, order = plan_upgrade(A, ignore_build) else: G_f = None order = A ctx.ui.info( _('The following packages will be upgraded: ') + util.strlist(order)) total_size = sum([ctx.packagedb.get_package(p).packageSize for p in order]) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_('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) paths = [] for x in order: install_op = install.Install.from_name(x) paths.append(install_op.package_fname) for path in paths: install_op = install.Install(path, ignore_file_conflicts=True) install_op.install(True) if 'pisi' in order: upgradepisi.upgrade_pisi()
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 upgrade_pkg_names(A=[], bypass_safety=False): """Re-installs packages from the repository, trying to perform a minimum or maximum number of upgrades according to options.""" 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)) if not bypass_safety: upgrade_base(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, True) continue (version, release, build) = ctx.installdb.get_version(x) if ctx.packagedb.has_package(x): pkg = ctx.packagedb.get_package(x) else: ctx.ui.info(_("Package %s is not available in repositories.") % x, True) continue if ignore_build or (not build) or (not pkg.build): if Version(release) < Version(pkg.release): Ap.append(x) else: ctx.ui.info(_("Package %s is already at the latest release %s.") % (pkg.name, pkg.release), True) 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), True) 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, ignore_build) else: G_f = None order = A ctx.ui.info(_("The following packages will be upgraded: ") + util.strlist(order)) total_size = sum([ctx.packagedb.get_package(p).packageSize for p in order]) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_("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) paths = [] for x in order: install_op = atomicoperations.Install.from_name(x) paths.append(install_op.package_fname) for path in paths: install_op = atomicoperations.Install(path) install_op.install(True)
def upgrade(A=[], repo=None): """Re-installs packages from the repository, trying to perform a minimum or maximum number of upgrades according to options.""" packagedb = pisi.db.packagedb.PackageDB() installdb = pisi.db.installdb.InstallDB() replaces = packagedb.get_replaces() if not A: # if A is empty, then upgrade all packages A = installdb.list_installed() if repo: repo_packages = set(packagedb.list_packages(repo)) A = set(A).intersection(repo_packages) A_0 = A = set(A) Ap = find_upgrades(A, replaces) A = set(Ap) if len(A) == 0: ctx.ui.info(_('No packages to upgrade.')) return True # Force upgrading of installed but replaced packages or else they will be removed (they are obsoleted also). # This is not wanted for a replaced driver package (eg. nvidia-X). A |= set(replaces.values()) A |= upgrade_base(A) 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 = list(A) componentdb = pisi.db.componentdb.ComponentDB() # Bug 4211 if componentdb.has_component('system.base'): order = operations.helper.reorder_base_packages(order) ctx.ui.info( _('The following packages will be upgraded: ') + util.strlist(order)) total_size, cached_size = operations.helper.calculate_download_sizes(order) total_size, symbol = util.human_readable_size(total_size) ctx.ui.info(_('Total size of package(s): %.2f %s') % (total_size, symbol)) if ctx.get_option('dry_run'): return if set(order) - A_0 - set(replaces.values()): 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) conflicts = [] if not ctx.get_option('ignore_package_conflicts'): conflicts = operations.helper.check_conflicts(order, packagedb) paths = [] for x in order: ctx.ui.info( util.colorize( _("Downloading %d / %d") % (order.index(x) + 1, len(order)), "yellow")) install_op = atomicoperations.Install.from_name(x) paths.append(install_op.package_fname) # fetch to be upgraded packages but do not install them. if ctx.get_option('fetch_only'): return if conflicts: operations.remove.remove_conflicting_packages(conflicts) operations.remove.remove_replaced_packages(replaces.keys()) operations.remove.remove_obsoleted_packages() for path in paths: ctx.ui.info( util.colorize( _("Installing %d / %d") % (paths.index(path) + 1, len(paths)), "yellow")) install_op = atomicoperations.Install(path, ignore_file_conflicts=True) install_op.install(True)
def remove(A, ignore_dep=False, ignore_safety=False): """remove set A of packages from system (A is a list of package names)""" componentdb = pisi.db.componentdb.ComponentDB() installdb = pisi.db.installdb.InstallDB() A = [str(x) for x in A] # filter packages that are not installed A_0 = A = set(A) if not ctx.get_option( 'ignore_safety' ) and not ctx.config.values.general.ignore_safety and not ignore_safety: if componentdb.has_component('system.base'): systembase = set( componentdb.get_union_component('system.base').packages) refused = A.intersection(systembase) if refused: raise pisi.Error( _("Safety switch prevents the removal of " "following packages:\n") + util.format_by_columns(sorted(refused))) A = A - systembase else: ctx.ui.warning( _("Safety switch: The component system.base cannot be found.")) Ap = [] for x in A: if installdb.has_package(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 False if not ctx.config.get_option('ignore_dependency') and not ignore_dep: G_f, order = plan_remove(A) else: G_f = None order = A ctx.ui.info( _("""The following 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 if ctx.get_option('dry_run'): return ctx.ui.notify(ui.packagestogo, order=order) for x in order: if installdb.has_package(x): atomicoperations.remove_single(x) if x in installdb.installed_extra: installdb.installed_extra.remove(x) with open( os.path.join(ctx.config.info_dir(), ctx.const.installed_extra), "w") as ie_file: ie_file.write("\n".join(installdb.installed_extra) + ("\n" if installdb.installed_extra else "")) else: ctx.ui.info(_('Package %s is not installed. Cannot remove.') % x)