* refactor in preparation of fixing several bugs and making many
not-so minor improvements!
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE Project SYSTEM "Project-3.8.dtd">
|
<!DOCTYPE Project SYSTEM "Project-3.8.dtd">
|
||||||
<!-- Project file for project pisi -->
|
<!-- Project file for project pisi -->
|
||||||
<!-- Saved: 2005-10-18, 01:54:10 -->
|
<!-- Saved: 2005-10-19, 20:42:26 -->
|
||||||
<!-- Copyright (C) 2005 PiSi Development Team, -->
|
<!-- Copyright (C) 2005 PiSi Development Team, -->
|
||||||
<Project version="3.8">
|
<Project version="3.8">
|
||||||
<ProgLanguage mixed="0">Python</ProgLanguage>
|
<ProgLanguage mixed="0">Python</ProgLanguage>
|
||||||
@@ -402,9 +402,9 @@
|
|||||||
</Vcs>
|
</Vcs>
|
||||||
<FiletypeAssociations>
|
<FiletypeAssociations>
|
||||||
<FiletypeAssociation pattern="*.ui.h" type="FORMS" />
|
<FiletypeAssociation pattern="*.ui.h" type="FORMS" />
|
||||||
<FiletypeAssociation pattern="*.ui" type="FORMS" />
|
|
||||||
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
|
|
||||||
<FiletypeAssociation pattern="*.py" type="SOURCES" />
|
|
||||||
<FiletypeAssociation pattern="*.ptl" type="SOURCES" />
|
<FiletypeAssociation pattern="*.ptl" type="SOURCES" />
|
||||||
|
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
|
||||||
|
<FiletypeAssociation pattern="*.ui" type="FORMS" />
|
||||||
|
<FiletypeAssociation pattern="*.py" type="SOURCES" />
|
||||||
</FiletypeAssociations>
|
</FiletypeAssociations>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+20
-351
@@ -37,11 +37,11 @@ import pisi.repodb
|
|||||||
import pisi.installdb
|
import pisi.installdb
|
||||||
from pisi.index import Index
|
from pisi.index import Index
|
||||||
import pisi.cli
|
import pisi.cli
|
||||||
|
from pisi.operations import install, remove, upgrade
|
||||||
|
|
||||||
class Error(pisi.Error):
|
class Error(pisi.Error):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def init(database = True, options = None, ui = None, comar = True):
|
def init(database = True, options = None, ui = None, comar = True):
|
||||||
"""Initialize PiSi subsystem"""
|
"""Initialize PiSi subsystem"""
|
||||||
|
|
||||||
@@ -71,179 +71,27 @@ def init(database = True, options = None, ui = None, comar = True):
|
|||||||
# import pisi.sourcedb
|
# import pisi.sourcedb
|
||||||
# pisi.sourcedb.init()
|
# pisi.sourcedb.init()
|
||||||
|
|
||||||
def install(packages):
|
def list_upgradable():
|
||||||
"""install a list of packages (either files/urls, or names)"""
|
ignore_build = ctx.config.options and ctx.config.options.ignore_build_no
|
||||||
|
|
||||||
# FIXME: this function name "install" makes impossible to import
|
A = ctx.installdb.list_installed()
|
||||||
# and use install module directly.
|
# filter packages that are not upgradable
|
||||||
from install import Error as InstallError
|
Ap = []
|
||||||
|
|
||||||
try:
|
|
||||||
# determine if this is a list of files/urls or names
|
|
||||||
if packages[0].endswith('.pisi'): # they all have to!
|
|
||||||
return install_pkg_files(packages)
|
|
||||||
else:
|
|
||||||
return install_pkg_names(packages)
|
|
||||||
|
|
||||||
except packagedb.Error, e:
|
|
||||||
ctx.ui.error(_("Package is not installable."))
|
|
||||||
raise e
|
|
||||||
|
|
||||||
|
|
||||||
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.'))
|
|
||||||
return False
|
|
||||||
|
|
||||||
if ctx.config.get_option('ignore_dependency'):
|
|
||||||
# simple code path then
|
|
||||||
for x in package_URIs:
|
|
||||||
operations.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 = 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
|
|
||||||
if ctx.config.get_option('debug'):
|
|
||||||
G_f.write_graphviz(sys.stdout)
|
|
||||||
order = G_f.topological_sort()
|
|
||||||
order.reverse()
|
|
||||||
ctx.ui.info(_('Installation order: ') + util.strlist(order) )
|
|
||||||
for x in order:
|
|
||||||
operations.install_single_file(dfn[x])
|
|
||||||
else:
|
|
||||||
raise Error(_('External dependencies not satisfied'))
|
|
||||||
|
|
||||||
return True # everything went OK.
|
|
||||||
|
|
||||||
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_0 = 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:
|
for x in A:
|
||||||
G_f.add_package(x)
|
if not ctx.installdb.is_installed(x):
|
||||||
B = A
|
continue
|
||||||
#state = {}
|
(version, release, build) = ctx.installdb.get_version(x)
|
||||||
while len(B) > 0:
|
pkg = packagedb.get_package(x)
|
||||||
Bp = set()
|
if ignore_build or (not build):
|
||||||
for x in B:
|
if release < pkg.release:
|
||||||
pkg = packagedb.get_package(x)
|
Ap.append(x)
|
||||||
#print pkg
|
elif build < pkg.build:
|
||||||
for dep in pkg.runtimeDeps:
|
Ap.append(x)
|
||||||
ctx.ui.debug('checking %s' % str(dep))
|
else:
|
||||||
# we don't deal with already *satisfied* dependencies
|
pass
|
||||||
if not dependency.installed_satisfies_dep(dep):
|
#ctx.ui.info('Package %s cannot be upgraded. ' % x)
|
||||||
if not dep.package in G_f.vertices():
|
return Ap
|
||||||
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()
|
|
||||||
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:
|
|
||||||
operations.install_single_name(x)
|
|
||||||
|
|
||||||
return True # everything went OK :)
|
|
||||||
|
|
||||||
def package_graph(A, ignore_installed = False):
|
def package_graph(A, ignore_installed = False):
|
||||||
"""Construct a package relations graph, containing
|
"""Construct a package relations graph, containing
|
||||||
@@ -279,185 +127,6 @@ def package_graph(A, ignore_installed = False):
|
|||||||
B = Bp
|
B = Bp
|
||||||
return G_f
|
return G_f
|
||||||
|
|
||||||
def upgrade(A):
|
|
||||||
upgrade_pkg_names(A)
|
|
||||||
|
|
||||||
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 = set(A)
|
|
||||||
Ap = []
|
|
||||||
for x in A:
|
|
||||||
if x.endswith('.pisi'):
|
|
||||||
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))
|
|
||||||
|
|
||||||
# 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
|
|
||||||
if ctx.config.get_option('debug'):
|
|
||||||
G_f.write_graphviz(sys.stdout)
|
|
||||||
order = G_f.topological_sort()
|
|
||||||
order.reverse()
|
|
||||||
ctx.ui.info(_("""The following packages will be upgraded:\n""") +
|
|
||||||
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:
|
|
||||||
operations.install_single_name(x, True)
|
|
||||||
|
|
||||||
return True # everything went OK :)
|
|
||||||
|
|
||||||
def list_upgradable():
|
|
||||||
ignore_build = ctx.config.options and ctx.config.options.ignore_build_no
|
|
||||||
|
|
||||||
A = ctx.installdb.list_installed()
|
|
||||||
# filter packages that are not upgradable
|
|
||||||
Ap = []
|
|
||||||
for x in A:
|
|
||||||
if not ctx.installdb.is_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:
|
|
||||||
pass
|
|
||||||
#ctx.ui.info('Package %s cannot be upgraded. ' % x)
|
|
||||||
return Ap
|
|
||||||
|
|
||||||
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 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 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?'):
|
|
||||||
return False
|
|
||||||
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():
|
def configure_pending():
|
||||||
# start with pending packages
|
# start with pending packages
|
||||||
|
|||||||
@@ -32,18 +32,31 @@ import pisi
|
|||||||
import pisi.context as ctx
|
import pisi.context as ctx
|
||||||
import pisi.packagedb as packagedb
|
import pisi.packagedb as packagedb
|
||||||
import pisi.dependency as dependency
|
import pisi.dependency as dependency
|
||||||
import pisi.operations as operations
|
|
||||||
import pisi.util as util
|
import pisi.util as util
|
||||||
from pisi.specfile import *
|
from pisi.specfile import *
|
||||||
from pisi.package import Package
|
from pisi.package import Package
|
||||||
from pisi.metadata import MetaData
|
from pisi.metadata import MetaData
|
||||||
|
from pisi.uri import URI
|
||||||
#import conflicts
|
#import conflicts
|
||||||
|
|
||||||
class Error(pisi.Error):
|
class Error(pisi.Error):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Installer:
|
class AtomicOperation(object):
|
||||||
"Installer class, provides install routines for pisi packages"
|
|
||||||
|
def __init__(self, package, ignore_dep = None):
|
||||||
|
self.package = package
|
||||||
|
if not ignore_dep:
|
||||||
|
self.ignore_dep = ctx.config.get_option('ignore_dependency')
|
||||||
|
else:
|
||||||
|
self.ignore_dep = ignore_dep
|
||||||
|
|
||||||
|
def run(self, package):
|
||||||
|
"perform an atomic package operation"
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Install(AtomicOperation):
|
||||||
|
"Install class, provides install routines for pisi packages"
|
||||||
|
|
||||||
def __init__(self, package_fname):
|
def __init__(self, package_fname):
|
||||||
"initialize from a file name"
|
"initialize from a file name"
|
||||||
@@ -72,10 +85,8 @@ class Installer:
|
|||||||
ctx.ui.info("Regenerating /etc/ld.so.cache...")
|
ctx.ui.info("Regenerating /etc/ld.so.cache...")
|
||||||
util.env_update()
|
util.env_update()
|
||||||
|
|
||||||
|
|
||||||
def check_requirements(self):
|
def check_requirements(self):
|
||||||
"""check system requirements"""
|
"""check system requirements"""
|
||||||
|
|
||||||
#TODO: IS THERE ENOUGH SPACE?
|
#TODO: IS THERE ENOUGH SPACE?
|
||||||
# what to do if / is split into /usr, /var, etc.
|
# what to do if / is split into /usr, /var, etc.
|
||||||
pass
|
pass
|
||||||
@@ -215,3 +226,99 @@ class Installer:
|
|||||||
|
|
||||||
# installed packages
|
# installed packages
|
||||||
packagedb.inst_packagedb.add_package(self.pkginfo)
|
packagedb.inst_packagedb.add_package(self.pkginfo)
|
||||||
|
|
||||||
|
# single package operations
|
||||||
|
|
||||||
|
# remove stuff
|
||||||
|
|
||||||
|
def Remove(AtomicOperation):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def remove_file(fileinfo):
|
||||||
|
fpath = pisi.util.join_path(ctx.config.dest_dir(), fileinfo.path)
|
||||||
|
# TODO: We have to store configuration files for futher
|
||||||
|
# usage. Currently we'are doing it like rpm does, saving
|
||||||
|
# with a prefix and leaving the user to edit it. In the future
|
||||||
|
# we'll have a plan for these configuration files.
|
||||||
|
if fileinfo.type == ctx.const.conf:
|
||||||
|
if os.path.isfile(fpath):
|
||||||
|
os.rename(fpath, fpath + ".pisi")
|
||||||
|
else:
|
||||||
|
# check if file is removed manually.
|
||||||
|
# And we don't remove directories!
|
||||||
|
# TODO: remove directory if there is nothing under it?
|
||||||
|
if os.path.isfile(fpath) or os.path.islink(fpath):
|
||||||
|
os.unlink(fpath)
|
||||||
|
else:
|
||||||
|
ctx.ui.warning(_('Not removing non-file, non-link %s') % fpath)
|
||||||
|
|
||||||
|
def run_preremove(package_name):
|
||||||
|
if ctx.comar:
|
||||||
|
import pisi.comariface as comariface
|
||||||
|
comariface.run_preremove(package_name)
|
||||||
|
else:
|
||||||
|
# TODO: store this somewhere
|
||||||
|
pass
|
||||||
|
|
||||||
|
def remove_db(package_name):
|
||||||
|
ctx.installdb.remove(package_name)
|
||||||
|
packagedb.remove_package(package_name) #FIXME: this looks like a mistake!
|
||||||
|
|
||||||
|
def remove_single(package_name):
|
||||||
|
"""Remove a single package"""
|
||||||
|
inst_packagedb = packagedb.inst_packagedb
|
||||||
|
|
||||||
|
#TODO: check dependencies
|
||||||
|
|
||||||
|
ctx.ui.info(_('Removing package %s') % package_name)
|
||||||
|
if not ctx.installdb.is_installed(package_name):
|
||||||
|
raise Exception(_('Trying to remove nonexistent package ')
|
||||||
|
+ package_name)
|
||||||
|
|
||||||
|
run_preremove(package_name)
|
||||||
|
|
||||||
|
for fileinfo in ctx.installdb.files(package_name).list:
|
||||||
|
remove_file(fileinfo)
|
||||||
|
|
||||||
|
remove_db(package_name)
|
||||||
|
|
||||||
|
def install_single(pkg, upgrade = False):
|
||||||
|
"""install a single package from URI or ID"""
|
||||||
|
url = URI(pkg)
|
||||||
|
# Check if we are dealing with a remote file or a real path of
|
||||||
|
# package filename. Otherwise we'll try installing a package from
|
||||||
|
# the package repository.
|
||||||
|
if url.is_remote_file() or os.path.exists(url.uri):
|
||||||
|
install_single_file(pkg, upgrade)
|
||||||
|
else:
|
||||||
|
install_single_name(pkg, upgrade)
|
||||||
|
|
||||||
|
# FIXME: Here and elsewhere pkg_location must be a URI
|
||||||
|
def install_single_file(pkg_location, upgrade = False):
|
||||||
|
"""install a package file"""
|
||||||
|
from pisi.atomicoperations import Install
|
||||||
|
Install(pkg_location).install(not upgrade)
|
||||||
|
|
||||||
|
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:
|
||||||
|
ctx.ui.error(_("Package %s not found in any active repository.") % pkg)
|
||||||
|
|
||||||
+345
-102
@@ -9,11 +9,15 @@
|
|||||||
#
|
#
|
||||||
# Please read the COPYING file.
|
# Please read the COPYING file.
|
||||||
#
|
#
|
||||||
#
|
# Author: Eray Ozkural <eray@uludag.org.tr>
|
||||||
|
|
||||||
"Package Operations: install/remove/upgrade"
|
"Package Operations: install/remove/upgrade"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
ver = sys.version_info
|
||||||
|
if ver[0] <= 2 and ver[1] < 4:
|
||||||
|
from sets import Set as set
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
__trans = gettext.translation('pisi', fallback=True)
|
__trans = gettext.translation('pisi', fallback=True)
|
||||||
@@ -21,112 +25,351 @@ _ = __trans.ugettext
|
|||||||
|
|
||||||
import pisi
|
import pisi
|
||||||
import pisi.context as ctx
|
import pisi.context as ctx
|
||||||
import pisi.util as util
|
|
||||||
import pisi.packagedb as packagedb
|
|
||||||
from pisi.uri import URI
|
from pisi.uri import URI
|
||||||
|
import pisi.util as util
|
||||||
|
import pisi.dependency as dependency
|
||||||
|
import pisi.pgraph as pgraph
|
||||||
|
import pisi.packagedb as packagedb
|
||||||
|
import pisi.repodb
|
||||||
|
import pisi.installdb
|
||||||
|
from pisi.index import Index
|
||||||
|
import pisi.cli
|
||||||
|
import pisi.atomicoperations as atomicoperations
|
||||||
|
|
||||||
# single package operations
|
class Error(pisi.Error):
|
||||||
|
pass
|
||||||
# remove stuff
|
|
||||||
|
|
||||||
def remove_file(fileinfo):
|
|
||||||
fpath = pisi.util.join_path(ctx.config.dest_dir(), fileinfo.path)
|
|
||||||
# TODO: We have to store configuration files for futher
|
|
||||||
# usage. Currently we'are doing it like rpm does, saving
|
|
||||||
# with a prefix and leaving the user to edit it. In the future
|
|
||||||
# we'll have a plan for these configuration files.
|
|
||||||
if fileinfo.type == ctx.const.conf:
|
|
||||||
if os.path.isfile(fpath):
|
|
||||||
os.rename(fpath, fpath + ".pisi")
|
|
||||||
else:
|
|
||||||
# check if file is removed manually.
|
|
||||||
# And we don't remove directories!
|
|
||||||
# TODO: remove directory if there is nothing under it?
|
|
||||||
if os.path.isfile(fpath) or os.path.islink(fpath):
|
|
||||||
os.unlink(fpath)
|
|
||||||
else:
|
|
||||||
ctx.ui.warning(_('Not removing non-file, non-link %s') % fpath)
|
|
||||||
|
|
||||||
def run_preremove(package_name):
|
|
||||||
if ctx.comar:
|
|
||||||
import pisi.comariface as comariface
|
|
||||||
comariface.run_preremove(package_name)
|
|
||||||
else:
|
|
||||||
# TODO: store this somewhere
|
|
||||||
pass
|
|
||||||
|
|
||||||
def remove_db(package_name):
|
|
||||||
ctx.installdb.remove(package_name)
|
|
||||||
packagedb.remove_package(package_name) #FIXME: this looks like a mistake!
|
|
||||||
|
|
||||||
def remove_single(package_name):
|
|
||||||
"""Remove a single package"""
|
|
||||||
inst_packagedb = packagedb.inst_packagedb
|
|
||||||
|
|
||||||
#TODO: check dependencies
|
|
||||||
|
|
||||||
ctx.ui.info(_('Removing package %s') % package_name)
|
|
||||||
if not ctx.installdb.is_installed(package_name):
|
|
||||||
raise Exception(_('Trying to remove nonexistent package ')
|
|
||||||
+ package_name)
|
|
||||||
|
|
||||||
run_preremove(package_name)
|
|
||||||
|
|
||||||
for fileinfo in ctx.installdb.files(package_name).list:
|
|
||||||
remove_file(fileinfo)
|
|
||||||
|
|
||||||
remove_db(package_name)
|
|
||||||
|
|
||||||
def install_single(pkg, upgrade = False):
|
|
||||||
"""install a single package from URI or ID"""
|
|
||||||
url = URI(pkg)
|
|
||||||
# Check if we are dealing with a remote file or a real path of
|
|
||||||
# package filename. Otherwise we'll try installing a package from
|
|
||||||
# the package repository.
|
|
||||||
if url.is_remote_file() or os.path.exists(url.uri):
|
|
||||||
install_single_file(pkg, upgrade)
|
|
||||||
else:
|
|
||||||
install_single_name(pkg, upgrade)
|
|
||||||
|
|
||||||
# FIXME: Here and elsewhere pkg_location must be a URI
|
|
||||||
def install_single_file(pkg_location, upgrade = False):
|
|
||||||
"""install a package file"""
|
|
||||||
from install import Installer
|
|
||||||
Installer(pkg_location).install(not upgrade)
|
|
||||||
|
|
||||||
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:
|
|
||||||
ctx.ui.error(_("Package %s not found in any active repository.") % pkg)
|
|
||||||
|
|
||||||
# high level operations
|
# high level operations
|
||||||
|
def install(packages):
|
||||||
|
"""install a list of packages (either files/urls, or names)"""
|
||||||
|
|
||||||
|
# FIXME: this function name "install" makes impossible to import
|
||||||
|
# and use install module directly.
|
||||||
|
from pisi.atomicoperations import Error as InstallError
|
||||||
|
|
||||||
|
try:
|
||||||
|
# determine if this is a list of files/urls or names
|
||||||
|
if packages[0].endswith('.pisi'): # they all have to!
|
||||||
|
return install_pkg_files(packages)
|
||||||
|
else:
|
||||||
|
return install_pkg_names(packages)
|
||||||
|
|
||||||
|
except packagedb.Error, e:
|
||||||
|
ctx.ui.error(_("Package is not installable."))
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
def install_pkg_files(package_URIs):
|
||||||
|
"""install a number of pisi package files"""
|
||||||
|
from package import Package
|
||||||
|
|
||||||
# deneme, don't remove ulan
|
ctx.ui.debug('A = %s' % str(package_URIs))
|
||||||
class AtomicOperation(object):
|
|
||||||
def __init__(self, package, ignore_dep = False):
|
|
||||||
self.package = package
|
|
||||||
self.ignore_dep = ignore_dep
|
|
||||||
|
|
||||||
def run(self, package):
|
for x in package_URIs:
|
||||||
"perform an atomic package operation"
|
if not x.endswith(ctx.const.package_prefix):
|
||||||
pass
|
ctx.ui.error(_('Mixing file names and package names not supported YET.'))
|
||||||
|
return False
|
||||||
|
|
||||||
|
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 = 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
|
||||||
|
if ctx.config.get_option('debug'):
|
||||||
|
G_f.write_graphviz(sys.stdout)
|
||||||
|
order = G_f.topological_sort()
|
||||||
|
order.reverse()
|
||||||
|
ctx.ui.info(_('Installation order: ') + util.strlist(order) )
|
||||||
|
for x in order:
|
||||||
|
atomicoperations.install_single_file(dfn[x])
|
||||||
|
else:
|
||||||
|
raise Error(_('External dependencies not satisfied'))
|
||||||
|
|
||||||
|
return True # everything went OK.
|
||||||
|
|
||||||
|
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_0 = 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()
|
||||||
|
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)
|
||||||
|
|
||||||
|
return True # everything went OK :)
|
||||||
|
|
||||||
|
def upgrade(A):
|
||||||
|
upgrade_pkg_names(A)
|
||||||
|
|
||||||
|
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 = set(A)
|
||||||
|
Ap = []
|
||||||
|
for x in A:
|
||||||
|
if x.endswith('.pisi'):
|
||||||
|
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))
|
||||||
|
|
||||||
|
# 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
|
||||||
|
if ctx.config.get_option('debug'):
|
||||||
|
G_f.write_graphviz(sys.stdout)
|
||||||
|
order = G_f.topological_sort()
|
||||||
|
order.reverse()
|
||||||
|
ctx.ui.info(_("""The following packages will be upgraded:\n""") +
|
||||||
|
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, True)
|
||||||
|
|
||||||
|
return True # everything went OK :)
|
||||||
|
|
||||||
|
|
||||||
|
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 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 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?'):
|
||||||
|
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)
|
||||||
|
|
||||||
|
return True # everything went OK :)
|
||||||
|
|||||||
Reference in New Issue
Block a user