* refactor in preparation of fixing several bugs and making many

not-so minor improvements!
This commit is contained in:
Eray Özkural
2005-10-20 03:08:27 +00:00
parent 46322f177a
commit c3bb82858f
4 changed files with 481 additions and 462 deletions
+4 -4
View File
@@ -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
View File
@@ -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
+112 -5
View File
@@ -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
View File
@@ -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 :)