1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """
24 Classes and functions for manipulating a transaction to be passed
25 to rpm.
26 """
27
28 from constants import *
29 from packageSack import PackageSack, PackageSackVersion
30 from packages import YumInstalledPackage
31 from sqlitesack import YumAvailablePackageSqlite
32 import Errors
33 import warnings
34 import misc
35
40
50 for (n, fl, (e,v,r)) in obj.returnPrco('provides'):
51 self._addToDictAsList(self.provides, n, obj)
52 for (n, fl, (e,v,r)) in obj.returnPrco('requires'):
53 self._addToDictAsList(self.requires, n, obj)
54 if self._need_index_files:
55 self.__addPackageToIndex_files(obj)
56 else:
57 self.__addPackageToIndex_primary_files(obj)
58
71
73 """Data Structure designed to hold information on a yum Transaction Set"""
75 self.flags = []
76 self.vsflags = []
77 self.probFilterFlags = []
78 self.root = '/'
79 self.pkgdict = {}
80 self._namedict = {}
81 self._unresolvedMembers = set()
82 self.debug = 0
83 self.changed = False
84 self.installonlypkgs = []
85
86 self.conditionals = {}
87
88 self.rpmdb = None
89 self.pkgSack = None
90 self.pkgSackPackages = 0
91 self.localSack = PackageSack()
92
93
94 self._inSack = None
95
96
97 self.instgroups = []
98 self.removedgroups = []
99 self.removed = []
100 self.installed = []
101 self.updated = []
102 self.obsoleted = []
103 self.depremoved = []
104 self.depinstalled = []
105 self.depupdated = []
106 self.reinstalled = []
107 self.downgraded = []
108
110 return len(self.pkgdict)
111
117
119 if self.debug:
120 print msg
121
123 return filter(lambda p: p.output_state in output_states,
124 self.getMembers(pkgtup))
125
127 """takes an optional package tuple and returns all transaction members
128 matching, no pkgtup means it returns all transaction members"""
129
130 returnlist = []
131
132 if pkgtup is None:
133 for members in self.pkgdict.itervalues():
134 returnlist.extend(members)
135 elif self.pkgdict.has_key(pkgtup):
136 returnlist.extend(self.pkgdict[pkgtup])
137 return returnlist
138
139
140
142 return list(sorted(self._unresolvedMembers))
143
145 self._unresolvedMembers.discard(txmbr)
146
148 if hard or len(self) < len(self._unresolvedMembers):
149 self._unresolvedMembers.clear()
150 self._unresolvedMembers.update(self.getMembers())
151 return True
152 return False
153
154 - def getMode(self, name=None, arch=None, epoch=None, ver=None, rel=None):
155 """returns the mode of the first match from the transaction set,
156 otherwise, returns None"""
157
158 txmbrs = self.matchNaevr(name=name, arch=arch, epoch=epoch, ver=ver, rel=rel)
159 if not len(txmbrs):
160 return None
161 states = []
162 for txmbr in txmbrs:
163 states.append(txmbr.ts_state)
164
165 if 'u' in states:
166 return 'u'
167 elif 'i' in states:
168 return 'i'
169 else:
170 return states[0]
171
172 - def matchNaevr(self, name=None, arch=None, epoch=None, ver=None, rel=None):
173 """returns the list of packages matching the args above"""
174 if name is None:
175 txmbrs = self.getMembers()
176 else:
177 txmbrs = self._namedict.get(name, [])
178 if arch is None and epoch is None and ver is None and rel is None:
179 return txmbrs[:]
180
181 result = []
182
183 for txmbr in txmbrs:
184 (n, a, e, v, r) = txmbr.pkgtup
185
186 if arch is not None and arch != a:
187 continue
188 if epoch is not None and epoch != e:
189 continue
190 if ver is not None and ver != v:
191 continue
192 if rel is not None and rel != r:
193 continue
194 result.append(txmbr)
195
196 return result
197
205
207 """takes a packageObject, returns 1 or 0 depending on if the package
208 should/can be installed multiple times with different vers
209 like kernels and kernel modules, for example"""
210
211 if po.name in self.installonlypkgs:
212 return True
213
214 provides = po.provides_names
215 if filter (lambda prov: prov in self.installonlypkgs, provides):
216 return True
217
218 return False
219
220 - def add(self, txmember):
221 """add a package to the transaction"""
222
223 for oldpo in txmember.updates:
224 self.addUpdated(oldpo, txmember.po)
225
226 if txmember.pkgtup not in self.pkgdict:
227 self.pkgdict[txmember.pkgtup] = []
228 else:
229 self.debugprint("Package: %s.%s - %s:%s-%s already in ts" % txmember.pkgtup)
230 for member in self.pkgdict[txmember.pkgtup]:
231 if member.ts_state == txmember.ts_state:
232 self.debugprint("Package in same mode, skipping.")
233 return
234 self.pkgdict[txmember.pkgtup].append(txmember)
235 self._namedict.setdefault(txmember.name, []).append(txmember)
236 self.changed = True
237 if self._isLocalPackage(txmember):
238 self.localSack.addPackage(txmember.po)
239 elif isinstance(txmember.po, YumAvailablePackageSqlite):
240 self.pkgSackPackages += 1
241 if self._inSack is not None and txmember.output_state in TS_INSTALL_STATES:
242 self._inSack.addPackage(txmember.po)
243
244 if self.conditionals.has_key(txmember.name):
245 for pkg in self.conditionals[txmember.name]:
246 if self.rpmdb.contains(po=pkg):
247 continue
248 for condtxmbr in self.install_method(po=pkg):
249 condtxmbr.setAsDep(po=txmember.po)
250
251 self._unresolvedMembers.add(txmember)
252
254 """remove a package from the transaction"""
255 if pkgtup not in self.pkgdict:
256 self.debugprint("Package: %s not in ts" %(pkgtup,))
257 return
258 for txmbr in self.pkgdict[pkgtup]:
259 txmbr.po.state = None
260 if self._isLocalPackage(txmbr):
261 self.localSack.delPackage(txmbr.po)
262 elif isinstance(txmbr.po, YumAvailablePackageSqlite):
263 self.pkgSackPackages -= 1
264 if self._inSack is not None and txmbr.output_state in TS_INSTALL_STATES:
265 self._inSack.delPackage(txmbr.po)
266 self._namedict[txmbr.name].remove(txmbr)
267 self._unresolvedMembers.add(txmbr)
268
269 del self.pkgdict[pkgtup]
270 if not self._namedict[pkgtup[0]]:
271 del self._namedict[pkgtup[0]]
272 self.changed = True
273
275 """tells if the pkg is in the class"""
276 if self.pkgdict.has_key(pkgtup):
277 if len(self.pkgdict[pkgtup]) != 0:
278 return 1
279
280 return 0
281
283 """true if the pkgtup is marked to be obsoleted"""
284 if self.exists(pkgtup):
285 for txmbr in self.getMembers(pkgtup=pkgtup):
286 if txmbr.output_state == TS_OBSOLETED:
287 return True
288
289 return False
290
291 - def makelists(self, include_reinstall=False, include_downgrade=False):
292 """returns lists of transaction Member objects based on mode:
293 updated, installed, erased, obsoleted, depupdated, depinstalled
294 deperased"""
295
296 self.instgroups = []
297 self.removedgroups = []
298 self.removed = []
299 self.installed = []
300 self.updated = []
301 self.obsoleted = []
302 self.depremoved = []
303 self.depinstalled = []
304 self.depupdated = []
305 self.reinstalled = []
306 self.downgraded = []
307 self.failed = []
308
309 for txmbr in self.getMembers():
310 if txmbr.output_state == TS_UPDATE:
311 if txmbr.isDep:
312 self.depupdated.append(txmbr)
313 else:
314 self.updated.append(txmbr)
315
316 elif txmbr.output_state in (TS_INSTALL, TS_TRUEINSTALL):
317 if include_reinstall and self.rpmdb.contains(po=txmbr.po):
318 txmbr.reinstall = True
319 self.reinstalled.append(txmbr)
320 continue
321
322 if include_downgrade and txmbr.downgrades:
323 self.downgraded.append(txmbr)
324 continue
325
326 if txmbr.groups:
327 for g in txmbr.groups:
328 if g not in self.instgroups:
329 self.instgroups.append(g)
330 if txmbr.isDep:
331 self.depinstalled.append(txmbr)
332 else:
333 self.installed.append(txmbr)
334
335 elif txmbr.output_state == TS_ERASE:
336 if include_downgrade and txmbr.downgraded_by:
337 continue
338
339 for g in txmbr.groups:
340 if g not in self.instgroups:
341 self.removedgroups.append(g)
342 if txmbr.isDep:
343 self.depremoved.append(txmbr)
344 else:
345 self.removed.append(txmbr)
346
347 elif txmbr.output_state == TS_OBSOLETED:
348 self.obsoleted.append(txmbr)
349
350 elif txmbr.output_state == TS_OBSOLETING:
351 self.installed.append(txmbr)
352 elif txmbr.output_state == TS_FAILED:
353 self.failed.append(txmbr)
354
355 else:
356 pass
357
358 self.updated.sort()
359 self.installed.sort()
360 self.removed.sort()
361 self.obsoleted.sort()
362 self.depupdated.sort()
363 self.depinstalled.sort()
364 self.depremoved.sort()
365 self.instgroups.sort()
366 self.removedgroups.sort()
367 self.reinstalled.sort()
368 self.downgraded.sort()
369 self.failed.sort()
370
371
387
389 """adds a package as an install
390 takes a packages object and returns a TransactionMember Object"""
391
392 txmbr = TransactionMember(po)
393 txmbr.current_state = TS_AVAILABLE
394 txmbr.output_state = TS_TRUEINSTALL
395 txmbr.po.state = TS_INSTALL
396 txmbr.ts_state = 'i'
397 txmbr.reason = 'user'
398 self.add(txmbr)
399 return txmbr
400
401
403 """adds a package as an erasure
404 takes a packages object and returns a TransactionMember Object"""
405
406 txmbr = TransactionMember(po)
407 txmbr.current_state = TS_INSTALL
408 txmbr.output_state = TS_ERASE
409 txmbr.po.state = TS_INSTALL
410 txmbr.ts_state = 'e'
411 self.add(txmbr)
412 return txmbr
413
415 """adds a package as an update
416 takes a packages object and returns a TransactionMember Object"""
417
418 if self._allowedMultipleInstalls(po):
419 return self.addTrueInstall(po)
420
421 txmbr = TransactionMember(po)
422 txmbr.current_state = TS_AVAILABLE
423 txmbr.output_state = TS_UPDATE
424 txmbr.po.state = TS_UPDATE
425 txmbr.ts_state = 'u'
426 if oldpo:
427 txmbr.relatedto.append((oldpo, 'updates'))
428 txmbr.updates.append(oldpo)
429
430 self.add(txmbr)
431 return txmbr
432
434 """adds a package as an downgrade takes a packages object and returns
435 a pair of TransactionMember Objects"""
436
437 itxmbr = self.addErase(oldpo)
438 itxmbr.relatedto.append((po, 'downgradedby'))
439 itxmbr.downgraded_by.append(po)
440
441 atxmbr = self.addInstall(po)
442 if not atxmbr:
443 self.remove(itxmbr.pkgtup)
444 return None
445 atxmbr.relatedto.append((oldpo, 'downgrades'))
446 atxmbr.downgrades.append(oldpo)
447
448 return (itxmbr, atxmbr)
449
451 """adds a package as being updated by another pkg
452 takes a packages object and returns a TransactionMember Object"""
453
454 txmbr = TransactionMember(po)
455 txmbr.current_state = TS_INSTALL
456 txmbr.output_state = TS_UPDATED
457 txmbr.po.state = TS_UPDATED
458 txmbr.ts_state = None
459 txmbr.relatedto.append((updating_po, 'updatedby'))
460 txmbr.updated_by.append(updating_po)
461 self.add(txmbr)
462 return txmbr
463
465 """adds a package as an obsolete over another pkg
466 takes a packages object and returns a TransactionMember Object"""
467
468 txmbr = TransactionMember(po)
469 txmbr.current_state = TS_AVAILABLE
470 txmbr.output_state = TS_OBSOLETING
471 txmbr.po.state = TS_OBSOLETING
472 txmbr.ts_state = 'u'
473 txmbr.relatedto.append((oldpo, 'obsoletes'))
474 txmbr.obsoletes.append(oldpo)
475 self.add(txmbr)
476 return txmbr
477
479 """adds a package as being obsoleted by another pkg
480 takes a packages object and returns a TransactionMember Object"""
481
482 txmbr = TransactionMember(po)
483 txmbr.current_state = TS_INSTALL
484 txmbr.output_state = TS_OBSOLETED
485 txmbr.po.state = TS_OBSOLETED
486 txmbr.ts_state = None
487 txmbr.relatedto.append((obsoleting_po, 'obsoletedby'))
488 txmbr.obsoleted_by.append(obsoleting_po)
489 self.add(txmbr)
490 for otxmbr in self.getMembersWithState(obsoleting_po.pkgtup,
491 [TS_OBSOLETING]):
492 if po in otxmbr.obsoletes:
493 continue
494 otxmbr.relatedto.append((po, 'obsoletes'))
495 otxmbr.obsoletes.append(po)
496 return txmbr
497
498
502
503 - def getNewProvides(self, name, flag=None, version=(None, None, None)):
518
519 - def getOldProvides(self, name, flag=None, version=(None, None, None)):
527
528 - def getProvides(self, name, flag=None, version=(None, None, None)):
533
534 - def getNewRequires(self, name, flag=None, version=(None, None, None)):
550
551
552 - def getOldRequires(self, name, flag=None, version=(None, None, None)):
560
561 - def getRequires(self, name, flag=None, version=(None, None, None)):
566
568 """ Return a simple version for the future rpmdb. Works like
569 rpmdb.simpleVersion(main_only=True)[0], but for the state the rpmdb
570 will be in after the transaction. """
571 pkgs = self.rpmdb.returnPackages()
572 _reinstalled_pkgtups = {}
573 for txmbr in self.getMembersWithState(None, TS_INSTALL_STATES):
574
575
576 if hasattr(txmbr, 'reinstall') and txmbr.reinstall:
577 _reinstalled_pkgtups[txmbr.po.pkgtup] = txmbr.po
578 pkgs.append(txmbr.po)
579
580 self.rpmdb.preloadPackageChecksums()
581 main = PackageSackVersion()
582 pkg_checksum_tups = []
583 for pkg in sorted(pkgs):
584 if pkg.repoid != 'installed':
585
586 csum = pkg.returnIdSum()
587 main.update(pkg, csum)
588 pkg_checksum_tups.append((pkg.pkgtup, csum))
589 continue
590
591
592 if self.getMembersWithState(pkg.pkgtup, TS_REMOVE_STATES):
593 continue
594
595 if pkg.pkgtup in _reinstalled_pkgtups:
596 continue
597
598
599 ydbi = pkg.yumdb_info
600 csum = None
601 if 'checksum_type' in ydbi and 'checksum_data' in ydbi:
602 csum = (ydbi.checksum_type, ydbi.checksum_data)
603 pkg_checksum_tups.append((pkg.pkgtup, csum))
604 main.update(pkg, csum)
605
606 self.rpmdb.transactionCachePackageChecksums(pkg_checksum_tups)
607
608 return main
609
611 """A transaction data implementing conditional package addition"""
616
618 """A transaction data implementing topological sort on it's members"""
627
629 self.path.append(txmbr.name)
630 txmbr.sortColour = TX_GREY
631 for po in txmbr.depends_on:
632 vertex = self.getMembers(pkgtup=po.pkgtup)[0]
633 if vertex.sortColour == TX_GREY:
634 self._doLoop(vertex.name)
635 if vertex.sortColour == TX_WHITE:
636 self._visit(vertex)
637 txmbr.sortColour = TX_BLACK
638 self._sorted.insert(0, txmbr.pkgtup)
639
641 self.path.append(name)
642 loop = self.path[self.path.index(self.path[-1]):]
643 if len(loop) > 2:
644 self.loops.append(loop)
645
646 - def add(self, txmember):
650
654
656 if self._sorted:
657 return self._sorted
658 self._sorted = []
659
660 for txmbr in self.getMembers():
661 if txmbr.sortColour == TX_WHITE:
662 self.path = [ ]
663 self._visit(txmbr)
664 self._sorted.reverse()
665 return self._sorted
666
667
669 """Class to describe a Transaction Member (a pkg to be installed/
670 updated/erased)."""
671
673
674 self.po = po
675 self.current_state = None
676 self.ts_state = None
677 self.output_state = None
678 self.isDep = 0
679 self.reason = 'user'
680 self.process = None
681 self.relatedto = []
682 self.depends_on = []
683 self.obsoletes = []
684 self.obsoleted_by = []
685 self.updates = []
686 self.updated_by = []
687 self.downgrades = []
688 self.downgraded_by = []
689 self.groups = []
690 self._poattr = ['pkgtup', 'repoid', 'name', 'arch', 'epoch', 'version',
691 'release']
692
693 for attr in self._poattr:
694 val = getattr(self.po, attr)
695 setattr(self, attr, val)
696
698 """sets the transaction member as a dependency and maps the dep into the
699 relationship list attribute"""
700
701 self.isDep = 1
702 if po:
703 self.relatedto.append((po, 'dependson'))
704 self.depends_on.append(po)
705
707 return cmp(self.po, other.po)
708
711
715
717 return "<%s : %s (%s)>" % (self.__class__.__name__, str(self),hex(id(self)))
718
719
720
721
722
723
724
725
726
727
728
729