|
Server : Apache/2.2.2 (Fedora) System : Linux App1.pathumtani.go.th 2.6.20-1.2320.fc5smp #1 SMP Tue Jun 12 19:40:16 EDT 2007 i686 User : apache ( 48) PHP Version : 5.2.9 Disable Function : NONE Directory : /proc/self/root/proc/self/root/usr/lib/python2.4/site-packages/yum/ |
Upload File : |
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Copyright 2005 Duke University
# Written by Seth Vidal
# TODOS: make all the package relationships deal with package objects
# search by package object for TransactionData, etc.
# provide a real TransactionData.remove(txmbr) method, It should
# remove the given txmbr and iterate to remove all those in depedent relationships
# with the given txmbr.
from constants import *
class TransactionData:
"""Data Structure designed to hold information on a yum Transaction Set"""
def __init__(self):
self.flags = []
self.vsflags = []
self.probFilterFlags = []
self.root = '/'
self.pkgdict = {} # key = pkgtup, val = list of TransactionMember obj
self.debug = 0
self.changed = False
def __len__(self):
return len(self.pkgdict.values())
def __iter__(self):
if hasattr(self.getMembers(), '__iter__'):
return self.getMembers().__iter__()
else:
return iter(self.getMembers())
def debugprint(self, msg):
if self.debug:
print msg
def getMembers(self, pkgtup=None):
"""takes an optional package tuple and returns all transaction members
matching, no pkgtup means it returns all transaction members"""
if pkgtup is None:
returnlist = []
for key in self.pkgdict.keys():
returnlist.extend(self.pkgdict[key])
return returnlist
if self.pkgdict.has_key(pkgtup):
return self.pkgdict[pkgtup]
else:
return []
def getMode(self, name=None, arch=None, epoch=None, ver=None, rel=None):
"""returns the mode of the first match from the transaction set,
otherwise, returns None"""
txmbrs = self.matchNaevr(name=name, arch=arch, epoch=epoch, ver=ver, rel=rel)
if len(txmbrs):
return txmbrs[0].ts_state
else:
return None
def matchNaevr(self, name=None, arch=None, epoch=None, ver=None, rel=None):
"""returns the list of packages matching the args above"""
completelist = self.pkgdict.keys()
removedict = {}
returnlist = []
returnmembers = []
for pkgtup in completelist:
(n, a, e, v, r) = pkgtup
if name is not None:
if name != n:
removedict[pkgtup] = 1
continue
if arch is not None:
if arch != a:
removedict[pkgtup] = 1
continue
if epoch is not None:
if epoch != e:
removedict[pkgtup] = 1
continue
if ver is not None:
if ver != v:
removedict[pkgtup] = 1
continue
if rel is not None:
if rel != r:
removedict[pkgtup] = 1
continue
for pkgtup in completelist:
if not removedict.has_key(pkgtup):
returnlist.append(pkgtup)
for matched in returnlist:
returnmembers.extend(self.pkgdict[matched])
return returnmembers
def add(self, txmember):
"""add a package to the transaction"""
if not self.pkgdict.has_key(txmember.pkgtup):
self.pkgdict[txmember.pkgtup] = []
else:
self.debugprint("Package: %s.%s - %s:%s-%s already in ts" % txmember.pkgtup)
for member in self.pkgdict[txmember.pkgtup]:
if member.ts_state == txmember.ts_state:
self.debugprint("Package in same mode, skipping.")
return
self.pkgdict[txmember.pkgtup].append(txmember)
self.changed = True
def remove(self, pkgtup):
"""remove a package from the transaction"""
if not self.pkgdict.has_key(pkgtup):
self.debugprint("Package: %s not in ts" %(pkgtup,))
return
for txmbr in self.pkgdict[pkgtup]:
txmbr.po.state = None
del self.pkgdict[pkgtup]
self.changed = True
def exists(self, pkgtup):
"""tells if the pkg is in the class"""
if self.pkgdict.has_key(pkgtup):
if len(self.pkgdict[pkgtup]) != 0:
return 1
return 0
def isObsoleted(self, pkgtup):
"""true if the pkgtup is marked to be obsoleted"""
if self.exists(pkgtup):
for txmbr in self.getMembers(pkgtup=pkgtup):
if txmbr.output_state == TS_OBSOLETED:
return True
return False
def makelists(self):
"""returns lists of transaction Member objects based on mode:
updated, installed, erased, obsoleted, depupdated, depinstalled
deperased"""
self.instgroups = []
self.removedgroups = []
self.removed = []
self.installed = []
self.updated = []
self.obsoleted = []
self.depremoved = []
self.depinstalled = []
self.depupdated = []
for txmbr in self.getMembers():
if txmbr.output_state == TS_UPDATE:
if txmbr.isDep:
self.depupdated.append(txmbr)
else:
self.updated.append(txmbr)
elif txmbr.output_state == TS_INSTALL or txmbr.output_state == TS_TRUEINSTALL:
if txmbr.groups:
for g in txmbr.groups:
if g not in self.instgroups:
self.instgroups.append(g)
if txmbr.isDep:
self.depinstalled.append(txmbr)
else:
self.installed.append(txmbr)
elif txmbr.output_state == TS_ERASE:
for g in txmbr.groups:
if g not in self.instgroups:
self.removedgroups.append(g)
if txmbr.isDep:
self.depremoved.append(txmbr)
else:
self.removed.append(txmbr)
elif txmbr.output_state == TS_OBSOLETED:
self.obsoleted.append(txmbr)
elif txmbr.output_state == TS_OBSOLETING:
self.installed.append(txmbr)
else:
pass
self.updated.sort()
self.installed.sort()
self.removed.sort()
self.obsoleted.sort()
self.depupdated.sort()
self.depinstalled.sort()
self.depremoved.sort()
self.instgroups.sort()
self.removedgroups.sort()
def addInstall(self, po):
"""adds a package as an install but in mode 'u' to the ts
takes a packages object and returns a TransactionMember Object"""
txmbr = TransactionMember(po)
txmbr.current_state = TS_AVAILABLE
txmbr.output_state = TS_INSTALL
txmbr.po.state = TS_INSTALL
txmbr.ts_state = 'u'
txmbr.reason = 'user'
self.add(txmbr)
return txmbr
def addTrueInstall(self, po):
"""adds a package as an install
takes a packages object and returns a TransactionMember Object"""
txmbr = TransactionMember(po)
txmbr.current_state = TS_AVAILABLE
txmbr.output_state = TS_TRUEINSTALL
txmbr.po.state = TS_INSTALL
txmbr.ts_state = 'i'
txmbr.reason = 'user'
self.add(txmbr)
return txmbr
def addErase(self, po):
"""adds a package as an erasure
takes a packages object and returns a TransactionMember Object"""
txmbr = TransactionMember(po)
txmbr.current_state = TS_INSTALL
txmbr.output_state = TS_ERASE
txmbr.po.state = TS_INSTALL
txmbr.ts_state = 'e'
self.add(txmbr)
return txmbr
def addUpdate(self, po, oldpo=None):
"""adds a package as an update
takes a packages object and returns a TransactionMember Object"""
txmbr = TransactionMember(po)
txmbr.current_state = TS_AVAILABLE
txmbr.output_state = TS_UPDATE
txmbr.po.state = TS_UPDATE
txmbr.ts_state = 'u'
if oldpo:
txmbr.relatedto.append((oldpo.pkgtup, 'updates'))
txmbr.updates.append(oldpo)
self.add(txmbr)
return txmbr
def addObsoleting(self, po, oldpo):
"""adds a package as an obsolete over another pkg
takes a packages object and returns a TransactionMember Object"""
txmbr = TransactionMember(po)
txmbr.current_state = TS_AVAILABLE
txmbr.output_state = TS_OBSOLETING
txmbr.po.state = TS_OBSOLETING
txmbr.ts_state = 'u'
txmbr.relatedto.append((oldpo, 'obsoletes'))
txmbr.obsoletes.append(oldpo)
self.add(txmbr)
return txmbr
def addObsoleted(self, po, obsoleting_po):
"""adds a package as being obsoleted by another pkg
takes a packages object and returns a TransactionMember Object"""
txmbr = TransactionMember(po)
txmbr.current_state = TS_INSTALL
txmbr.output_state = TS_OBSOLETED
txmbr.po.state = TS_OBSOLETED
txmbr.ts_state = None
txmbr.relatedto.append((obsoleting_po, 'obsoletedby'))
txmbr.obsoleted_by.append(obsoleting_po)
self.add(txmbr)
return txmbr
class ConditionalTransactionData(TransactionData):
"""A transaction data implementing conditional package addition"""
def __init__(self):
# Key: package name to trigger condition
# Value: list of package objects to add
self.conditionals = {}
TransactionData.__init__(self)
def add(self, txmember):
TransactionData.add(self, txmember)
if self.conditionals.has_key(txmember.name):
for po in self.conditionals[txmember.name]:
condtxmbr = self.addInstall(po)
condtxmbr.setAsDep(po=txmember.po)
class SortableTransactionData(ConditionalTransactionData):
"""A transaction data implementing topological sort on it's members"""
def __init__(self):
# Cache of sort
self._sorted = []
# Current dependency path
self.path = []
# List of loops
self.loops = []
ConditionalTransactionData.__init__(self)
def _visit(self, txmbr):
self.path.append(txmbr.name)
txmbr.sortColour = TX_GREY
for po in txmbr.depends_on:
vertex = self.getMembers(pkgtup=po.pkgtup)[0]
if vertex.sortColour == TX_GREY:
self._doLoop(vertex.name)
if vertex.sortColour == TX_WHITE:
self._visit(vertex)
txmbr.sortColour = TX_BLACK
self._sorted.insert(0, txmbr.pkgtup)
def _doLoop(self, name):
self.path.append(name)
loop = self.path[self.path.index(self.path[-1]):]
if len(loop) > 2:
self.loops.append(loop)
def add(self, txmember):
txmember.sortColour = TX_WHITE
ConditionalTransactionData.add(self, txmember)
self._sorted = []
def remove(self, pkgtup):
ConditionalTransactionData.remove(self, pkgtup)
self._sorted = []
def sort(self):
if self._sorted:
return self._sorted
self._sorted = []
# loop over all members
for txmbr in self.getMembers():
if txmbr.sortColour == TX_WHITE:
self.path = [ ]
self._visit(txmbr)
self._sorted.reverse()
return self._sorted
class TransactionMember:
"""Class to describe a Transaction Member (a pkg to be installed/
updated/erased)."""
def __init__(self, po):
# holders for data
self.po = po # package object
self.current_state = None # where the package currently is (repo, installed)
self.ts_state = None # what state to put it into in the transaction set
self.output_state = None # what state to list if printing it
self.isDep = 0
self.reason = 'user' # reason for it to be in the transaction set
self.process = None #
self.relatedto = [] # ([relatedpkgtup, relationship)]
self.depends_on = []
self.obsoletes = []
self.obsoleted_by = []
self.updates = []
self.updated_by = []
self.groups = [] # groups it's in
self._poattr = ['pkgtup', 'repoid', 'name', 'arch', 'epoch', 'version',
'release']
for attr in self._poattr:
val = getattr(self.po, attr)
setattr(self, attr, val)
def setAsDep(self, po=None):
"""sets the transaction member as a dependency and maps the dep into the
relationship list attribute"""
self.isDep = 1
if po:
self.relatedto.append((po.pkgtup, 'dependson'))
self.depends_on.append(po)
def __cmp__(self, other):
if self.name > other.name:
return 1
if self.name < other.name:
return -1
if self.name == other.name:
return 0
def __hash__(self):
return hash(self.po.pkgtup)
def __str__(self):
return "%s.%s %s-%s-%s - %s" % (self.name, self.arch, self.epoch,
self.version, self.release, self.ts_state)
# This is the tricky part - how do we nicely setup all this data w/o going insane
# we could make the txmember object be created from a YumPackage base object
# we still may need to pass in 'groups', 'ts_state', 'output_state', 'reason', 'current_state'
# and any related packages. A world of fun that will be, you betcha
# definitions
# current and output states are defined in constants
# relationships are defined in constants
# ts states are: u, i, e