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) = inary.analyzer.conflict.calculate_conflicts(order, packagedb) if D: raise Exception( _("Selected packages \"[{}]\" are in conflict with each other.").format( util.strlist( list(D)))) if pkg_conflicts: conflicts = "" for pkg in list(pkg_conflicts.keys()): conflicts += _(" - [\"{0}\" conflicts with: \"{1}\"]\n").format( pkg, util.strlist(pkg_conflicts[pkg])) ctx.ui.info( _("The following packages have conflicts:\n{}").format(conflicts)) if not ctx.ui.confirm(_('Remove the following conflicting packages?')): raise Exception( _("Conflicting packages should be removed to continue.")) return list(C)
def emerge(A): """ Builds and installs the given packages from source @param A: list of package names -> list_of_strings """ inary.db.historydb.HistoryDB().create_history("emerge") # A was a list, remove duplicates and expand components A = [str(x) for x in A] A_0 = A = inary.operations.helper.expand_src_components(set(A)) ctx.ui.debug('A = {}'.format(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) else: G_f = None order_inst = [] order_build = A if order_inst: ctx.ui.info(_("""The following list of packages will be installed from repository in the respective order to satisfy dependencies: """) + util.strlist(order_inst)) ctx.ui.info(_("""The following 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. Would you like 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 = operations.build.build(x).new_packages inary.operations.install.install_pkg_files(package_names, reinstall=True) # handle inter-package deps here # reset counts between builds ctx.ui.errors = ctx.ui.warnings = 0 # 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)
def takeback(operation): """ Takes back the system to a previous state. Uses inary history to find out which packages were installed at the time _after_ the given operation that the system is requested to be taken back. @param operation: number of the operation that the system will be taken back -> integer """ historydb = inary.db.historydb.HistoryDB() historydb.create_history("takeback") beinstalled, beremoved, configs = plan_takeback(operation) if not beinstalled and not beremoved: ctx.ui.info( _("There is no packages to taking back (installing or removing).")) return if beinstalled: ctx.ui.info( _("Following packages will be installed:\n") + util.strlist(beinstalled)) if beremoved: ctx.ui.info( _("Following packages will be removed:\n") + util.strlist(beremoved)) if (beremoved or beinstalled) and not ctx.ui.confirm( _('Would you like to continue?')): return errors = [] paths = [] for pkg in beinstalled: lndig = math.floor(math.log(len(beinstalled), 10)) + 1 ctx.ui.info(_("Downloading") + str(" [ {:>" + str(lndig) + "} / {} ] => [{}]").format(beinstalled.index(pkg) + 1, len(beinstalled), pkg), color="yellow") pkg += ctx.const.package_suffix if fetch_remote_file(pkg, errors): paths.append(os.path.join(ctx.config.cached_packages_dir(), pkg)) if errors: ctx.ui.info(_("\nFollowing packages could not be found in repositories and are not cached:\n") + util.strlist(errors)) if not ctx.ui.confirm(_('Would you like to continue?')): return if beremoved: operations.remove.remove(beremoved, True, True) if paths: operations.install.install_pkg_files(paths, True) for pkg, operation in configs: historydb.load_config(operation, pkg)
def print_specdata(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(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))))
def remove(A, ignore_dep=False, ignore_safety=False): """ Removes the given packages from the system @param A: list of package names -> list_of_strings @param ignore_dep: removes packages without looking into theirs reverse deps if True @param ignore_safety: system.base packages can also be removed if True """ inary.db.historydb.HistoryDB().create_history("remove") componentdb = inary.db.componentdb.ComponentDB() installdb = inary.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 inary.errors.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 \"{}\" does not exist. Cannot remove.').format(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:"""), color='green') ctx.ui.info(util.strlist(order)) if len(order) > len(A_0): if not ctx.ui.confirm(_('Would you like to continue?')): ctx.ui.warning(_('Package removal declined.')) return False removal_size = 0 for pkg in [installdb.get_package(name) for name in order]: removal_size += pkg.installedSize removal_size, symbol = util.human_readable_size(removal_size) ctx.ui.info(_('{:.2f} {} space will be freed.').format( removal_size, symbol), color='cyan') del removal_size, symbol if not ctx.ui.confirm(_("Would you like 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 \"{}\" is not installed. Cannot remove.').format(x))
def install_pkg_files(package_URIs, reinstall=False): """install a number of inary package files""" installdb = inary.db.installdb.InstallDB() ctx.ui.debug('A = {}'.format(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: pkg_name = util.parse_package_name_get_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 = inary.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 list(d_t.keys()): pkg = d_t[x] if pkg.distributionRelease > ctx.config.values.general.distribution_release: raise Exception( _('Package \"{0}\" is not compatible with your distribution release \'{1}\' \'{2}\'.' ).format(x, ctx.config.values.general.distribution, ctx.config.values.general.distribution_release)) if pkg.architecture != ctx.config.values.general.architecture: raise Exception( _('Package \"{0}\" (\'{1}\') is not compatible with your \'{2}\' architecture.' ).format(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 list(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() and not ctx.config.get_option( 'ignore_satisfy'): raise Exception( _('External dependencies not satisfied: \"{}\", \"{}\"'). format(dep, name)) # 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(_('Would you like to continue?')): raise Exception(_('External dependencies not satisfied.')) install_pkg_names(extra_packages, reinstall=False, extra=False) class PackageDB: @staticmethod def get_package(key, repo=None): return d_t[str(key)] packagedb = PackageDB() installdb = inary.db.installdb.InstallDB() A = list(d_t.keys()) if len(A) == 0: ctx.ui.info(_('No packages to install.')) return # try to construct a inary graph of packages to # install / reinstall G_f = pgraph.PGraph(packagedb, installdb) # construct G_f G_f.reinstall = reinstall # find the "install closure" graph of G_f by package # set A using packagedb for x in A: G_f.packages.append(x) B = A while len(B) > 0: Bp = set() for x in B: pkg = packagedb.get_package(x) G_f.add_package(x) # for dep in pkg.runtimeDependencies(): # G_f.add_package(dep) B = Bp 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