1
2 '''
3 # DESCRIPTION:
4 # Entropy Object Oriented Interface
5
6 Copyright (C) 2007-2009 Fabio Erculiani
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 '''
22 from __future__ import with_statement
23 from entropy.misc import Lifo
24 from entropy.const import *
25 from entropy.exceptions import *
26 from entropy.output import bold, darkgreen, darkred, blue, red
27 from entropy.i18n import _
28
30
32
33 if dbconn == None:
34 dbconn = self.clientDbconn
35
36 installed_packages = dbconn.listAllIdpackages()
37
38 pdepend_id = etpConst['spm']['pdepend_id']
39 deps_not_matched = set()
40
41 length = len(installed_packages)
42 count = 0
43 for idpackage in installed_packages:
44 count += 1
45
46 if (count%150 == 0) or (count == length) or (count == 1):
47 atom = dbconn.retrieveAtom(idpackage)
48 self.updateProgress(
49 darkgreen(_("Checking %s") % (bold(atom),)),
50 importance = 0,
51 type = "info",
52 back = True,
53 count = (count,length),
54 header = darkred(" @@ ")
55 )
56
57 xdeps = dbconn.retrieveDependencies(idpackage,
58 exclude_deptypes = (pdepend_id,))
59 needed_deps = [(x,dbconn.atomMatch(x),) for x in xdeps]
60 deps_not_matched |= set([x for x,(y,z,) in needed_deps if y == -1])
61
62 return deps_not_matched
63
79
81
82 packageInformation = {}
83 versionInformation = {}
84
85
86 tbz2repos = [x for x in results if x.endswith(etpConst['packagesext'])]
87 if tbz2repos:
88 del tbz2repos
89 newrepos = results.copy()
90 for x in newrepos:
91 if x.endswith(etpConst['packagesext']):
92 continue
93 del results[x]
94
95 version_duplicates = set()
96 versions = set()
97 for repo in results:
98 packageInformation[repo] = {}
99 if extended_results:
100 version = results[repo][1]
101 packageInformation[repo]['versiontag'] = results[repo][2]
102 packageInformation[repo]['revision'] = results[repo][3]
103 else:
104 dbconn = self.__atom_match_open_db(repo, server_inst)
105 packageInformation[repo]['versiontag'] = dbconn.retrieveVersionTag(results[repo])
106 packageInformation[repo]['revision'] = dbconn.retrieveRevision(results[repo])
107 version = dbconn.retrieveVersion(results[repo])
108 packageInformation[repo]['version'] = version
109 versionInformation[version] = repo
110 if version in versions:
111 version_duplicates.add(version)
112 versions.add(version)
113
114 newerVersion = self.entropyTools.get_newer_version(list(versions))[0]
115
116 if (not version_duplicates) or (newerVersion not in version_duplicates):
117 reponame = versionInformation.get(newerVersion)
118 return (results[reponame],reponame)
119
120
121
122
123 conflictingEntries = {}
124 tags_duplicates = set()
125 tags = set()
126 tagsInfo = {}
127 for repo in packageInformation:
128 if packageInformation[repo]['version'] != newerVersion:
129 continue
130 conflictingEntries[repo] = {}
131 versiontag = packageInformation[repo]['versiontag']
132 if versiontag in tags:
133 tags_duplicates.add(versiontag)
134 tags.add(versiontag)
135 tagsInfo[versiontag] = repo
136 conflictingEntries[repo]['versiontag'] = versiontag
137 conflictingEntries[repo]['revision'] = packageInformation[repo]['revision']
138
139
140 newerTag = sorted(list(tags), reverse = True)[0]
141 if newerTag not in tags_duplicates:
142 reponame = tagsInfo.get(newerTag)
143 return (results[reponame],reponame)
144
145
146
147
148 conflictingRevisions = {}
149 revisions = set()
150 revisions_duplicates = set()
151 revisionInfo = {}
152 for repo in conflictingEntries:
153 if conflictingEntries[repo]['versiontag'] == newerTag:
154 conflictingRevisions[repo] = {}
155 versionrev = conflictingEntries[repo]['revision']
156 if versionrev in revisions:
157 revisions_duplicates.add(versionrev)
158 revisions.add(versionrev)
159 revisionInfo[versionrev] = repo
160 conflictingRevisions[repo]['revision'] = versionrev
161
162 newerRevision = max(revisions)
163 if newerRevision not in revisions_duplicates:
164 reponame = revisionInfo.get(newerRevision)
165 return (results[reponame],reponame)
166
167
168
169
170 for reponame in valid_repos:
171 if reponame in conflictingRevisions:
172 return (results[reponame],reponame)
173
175
176 data, rc = cached_obj
177 if rc == 1: return cached_obj
178
179 if multiRepo or multiMatch:
180 matches = data
181 if extendedResults:
182
183 matches = [(x[0][0],x[1],) for x in data]
184 for m_id, m_repo in matches:
185 m_db = self.__atom_match_open_db(m_repo, server_inst)
186 if not m_db.isIDPackageAvailable(m_id): return None
187 else:
188 m_id, m_repo = cached_obj
189 if extendedResults:
190
191 m_id, m_repo = cached_obj[0][0],cached_obj[1]
192 m_db = self.__atom_match_open_db(m_repo, server_inst)
193 if not m_db.isIDPackageAvailable(m_id): return None
194
195 return cached_obj
196
203
204 - def atom_match(self, atom, caseSensitive = True, matchSlot = None,
205 matchBranches = (), matchTag = None, packagesFilter = True,
206 multiMatch = False, multiRepo = False, matchRevision = None,
207 matchRepo = None, server_repos = [], serverInstance = None,
208 extendedResults = False, useCache = True):
209
210
211
212 atom, repos = self.entropyTools.dep_get_match_in_repos(atom)
213 if (matchRepo == None) and (repos != None):
214 matchRepo = repos
215
216 u_hash = ""
217 m_hash = ""
218 k_ms = "//"
219 k_mt = "@#@"
220 k_mr = "-1"
221 if isinstance(matchRepo,(list,tuple,set,)): u_hash = hash(frozenset(matchRepo))
222 if isinstance(matchBranches,(list,tuple,set,)): m_hash = hash(frozenset(matchBranches))
223 if isinstance(matchSlot,basestring): k_ms = matchSlot
224 if isinstance(matchTag,basestring): k_mt = matchTag
225 if isinstance(matchRevision,basestring): k_mr = matchRevision
226
227 c_hash = "|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s" % (
228 atom,k_ms,k_mt,hash(packagesFilter),
229 hash(frozenset(self.validRepositories)),
230 hash(frozenset(self.SystemSettings['repositories']['available'])),
231 hash(multiMatch),hash(multiRepo),hash(caseSensitive),
232 k_mr,hash(extendedResults),
233 u_hash, m_hash
234 )
235 c_hash = "%s%s" % (self.atomMatchCacheKey,hash(c_hash),)
236
237 if self.xcache and useCache:
238 cached = self.Cacher.pop(c_hash)
239 if cached != None:
240 try:
241 cached = self.__validate_atom_match_cache(cached, multiMatch, extendedResults, multiRepo, serverInstance)
242 except (TypeError,ValueError,IndexError,KeyError,):
243 cached = None
244 if cached != None:
245 return cached
246
247 if server_repos:
248 if not serverInstance:
249 t = _("server_repos needs serverInstance")
250 raise IncorrectParameter("IncorrectParameter: %s" % (t,))
251 valid_repos = server_repos[:]
252 else:
253 valid_repos = self.validRepositories
254 if matchRepo and (type(matchRepo) in (list,tuple,set)):
255 valid_repos = list(matchRepo)
256
257 repoResults = {}
258 for repo in valid_repos:
259
260
261 dbconn = self.__atom_match_open_db(repo, serverInstance)
262 use_cache = useCache
263 while 1:
264 try:
265 query_data, query_rc = dbconn.atomMatch(
266 atom,
267 caseSensitive = caseSensitive,
268 matchSlot = matchSlot,
269 matchBranches = matchBranches,
270 matchTag = matchTag,
271 packagesFilter = packagesFilter,
272 matchRevision = matchRevision,
273 extendedResults = extendedResults,
274 useCache = use_cache
275 )
276 if query_rc == 0:
277
278 if extendedResults:
279 repoResults[repo] = (query_data[0],query_data[2],query_data[3],query_data[4])
280 else:
281 repoResults[repo] = query_data
282 except TypeError:
283 if not use_cache:
284 raise
285 use_cache = False
286 continue
287 break
288
289 dbpkginfo = (-1,1)
290 if extendedResults:
291 dbpkginfo = ((-1,None,None,None),1)
292
293 if multiRepo and repoResults:
294
295 data = set()
296 for repoid in repoResults:
297 data.add((repoResults[repoid],repoid))
298 dbpkginfo = (data,0)
299
300 elif len(repoResults) == 1:
301
302 repo = repoResults.keys()[0]
303 dbpkginfo = (repoResults[repo],repo)
304
305 elif len(repoResults) > 1:
306
307
308 mypkginfo = self.__handle_multi_repo_matches(repoResults, extendedResults, valid_repos, serverInstance)
309 if mypkginfo != None: dbpkginfo = mypkginfo
310
311
312 if multiMatch:
313
314 if dbpkginfo[1] == 1:
315 dbpkginfo = (set(), 1)
316 else:
317 if multiRepo:
318 data = set()
319 for q_id,q_repo in dbpkginfo[0]:
320 dbconn = self.__atom_match_open_db(q_repo, serverInstance)
321 query_data, query_rc = dbconn.atomMatch(
322 atom,
323 caseSensitive = caseSensitive,
324 matchSlot = matchSlot,
325 matchBranches = matchBranches,
326 matchTag = matchTag,
327 packagesFilter = packagesFilter,
328 multiMatch = True,
329 extendedResults = extendedResults
330 )
331 if extendedResults:
332 for item in query_data:
333 data.add(((item[0],item[2],item[3],item[4]),q_repo))
334 else:
335 for x in query_data: data.add((x,q_repo))
336 dbpkginfo = (data,0)
337 else:
338 dbconn = self.__atom_match_open_db(dbpkginfo[1], serverInstance)
339 query_data, query_rc = dbconn.atomMatch(
340 atom,
341 caseSensitive = caseSensitive,
342 matchSlot = matchSlot,
343 matchBranches = matchBranches,
344 matchTag = matchTag,
345 packagesFilter = packagesFilter,
346 multiMatch = True,
347 extendedResults = extendedResults
348 )
349 if extendedResults:
350 dbpkginfo = (set([((x[0],x[2],x[3],x[4]),dbpkginfo[1]) for x in query_data]),0)
351 else:
352 dbpkginfo = (set([(x,dbpkginfo[1]) for x in query_data]),0)
353
354 if self.xcache and useCache:
355 self.Cacher.push(c_hash,dbpkginfo)
356
357 return dbpkginfo
358
359
361 new_packages = []
362
363 for pkg_id in range(len(packages)):
364 package = packages[pkg_id]
365
366
367 if package.startswith(etpConst['packagesetprefix']):
368 set_pkgs = sorted(list(self.package_set_expand(package, raise_exceptions = False)))
369 new_packages.extend([x for x in set_pkgs if x not in packages])
370 else:
371 new_packages.append(package)
372
373 return new_packages
374
376
377 max_recursion_level = 50
378 recursion_level = 0
379
380 def do_expand(myset, recursion_level, max_recursion_level):
381 recursion_level += 1
382 if recursion_level > max_recursion_level:
383 raise InvalidPackageSet('InvalidPackageSet: corrupted, too many recursions: %s' % (myset,))
384 set_data, set_rc = self.package_set_match(myset[len(etpConst['packagesetprefix']):])
385 if not set_rc:
386 raise InvalidPackageSet('InvalidPackageSet: not found: %s' % (myset,))
387 (set_from, package_set, mydata,) = set_data
388
389 mypkgs = set()
390 for fset in mydata:
391 if fset.startswith(etpConst['packagesetprefix']):
392 mypkgs |= do_expand(fset, recursion_level, max_recursion_level)
393 else:
394 mypkgs.add(fset)
395
396 return mypkgs
397
398 if not package_set.startswith(etpConst['packagesetprefix']):
399 package_set = "%s%s" % (etpConst['packagesetprefix'],package_set,)
400
401 try:
402 mylist = do_expand(package_set, recursion_level, max_recursion_level)
403 except InvalidPackageSet:
404 if raise_exceptions: raise
405 mylist = set()
406
407 return mylist
408
409 - def package_set_list(self, server_repos = [], serverInstance = None, matchRepo = None):
410 return self.package_set_match('', matchRepo = matchRepo, server_repos = server_repos, serverInstance = serverInstance, search = True)[0]
411
412 - def package_set_search(self, package_set, server_repos = [], serverInstance = None, matchRepo = None):
413
414 if package_set == '*': package_set = ''
415 return self.package_set_match(package_set, matchRepo = matchRepo, server_repos = server_repos, serverInstance = serverInstance, search = True)[0]
416
423
424 - def package_set_match(self, package_set, multiMatch = False, matchRepo = None, server_repos = [], serverInstance = None, search = False):
425
426
427
428 package_set, repos = self.entropyTools.dep_get_match_in_repos(package_set)
429 if (matchRepo == None) and (repos != None):
430 matchRepo = repos
431
432 if server_repos:
433 if not serverInstance:
434 t = _("server_repos needs serverInstance")
435 raise IncorrectParameter("IncorrectParameter: %s" % (t,))
436 valid_repos = server_repos[:]
437 else:
438 valid_repos = self.validRepositories
439
440 if matchRepo and (type(matchRepo) in (list,tuple,set)):
441 valid_repos = list(matchRepo)
442
443
444 if search: multiMatch = True
445
446 set_data = []
447
448 while 1:
449
450
451 if not server_repos:
452 if search:
453 mysets = [x for x in self.SystemSettings['system_package_sets'].keys() if (x.find(package_set) != -1)]
454 for myset in mysets:
455 mydata = self.SystemSettings['system_package_sets'].get(myset)
456 set_data.append((etpConst['userpackagesetsid'], unicode(myset), mydata.copy(),))
457 else:
458 mydata = self.SystemSettings['system_package_sets'].get(package_set)
459 if mydata != None:
460 set_data.append((etpConst['userpackagesetsid'], unicode(package_set), mydata,))
461 if not multiMatch: break
462
463 for repoid in valid_repos:
464 dbconn = self.__package_set_match_open_db(repoid, serverInstance)
465 if search:
466 mysets = dbconn.searchSets(package_set)
467 for myset in mysets:
468 mydata = dbconn.retrievePackageSet(myset)
469 set_data.append((repoid, myset, mydata.copy(),))
470 else:
471 mydata = dbconn.retrievePackageSet(package_set)
472 if mydata: set_data.append((repoid, package_set, mydata,))
473 if not multiMatch: break
474
475 break
476
477 if not set_data: return (),False
478 if multiMatch: return set_data,True
479 return set_data.pop(0),True
480
482
483 if self.xcache:
484 c_data = sorted(dependencies)
485 client_checksum = self.clientDbconn.database_checksum()
486 c_hash = hash("%s|%s|%s" % (c_data,deep_deps,client_checksum,))
487 c_hash = "%s%s" % (etpCache['filter_satisfied_deps'],c_hash,)
488 cached = self.Cacher.pop(c_hash)
489 if cached != None: return cached
490
491 if not isinstance(depcache,dict):
492 depcache = {}
493
494 cdb_am = self.clientDbconn.atomMatch
495 am = self.atom_match
496 open_repo = self.open_repository
497 intf_error = self.dbapi2.InterfaceError
498 cdb_getversioning = self.clientDbconn.getVersioningData
499 etp_cmp = self.entropyTools.entropy_compare_versions
500 etp_get_rev = self.entropyTools.dep_get_entropy_revision
501
502
503 def fm_dep(dependency):
504
505 cached = depcache.get(dependency)
506 if cached != None: return cached
507
508
509 if dependency.startswith("!"):
510 idpackage,rc = cdb_am(dependency[1:])
511 if idpackage != -1:
512 depcache[dependency] = dependency
513 return dependency
514 depcache[dependency] = 0
515 return 0
516
517 c_id,c_rc = cdb_am(dependency)
518 if c_id == -1:
519 depcache[dependency] = dependency
520 return dependency
521
522
523
524
525
526 r_id,r_repo = am(dependency)
527 if r_id == -1:
528 depcache[dependency] = dependency
529 return dependency
530
531
532
533
534
535
536
537
538
539
540 dbconn = open_repo(r_repo)
541 try:
542 repo_pkgver, repo_pkgtag, repo_pkgrev = dbconn.getVersioningData(r_id)
543 except (intf_error,TypeError,):
544
545 return dependency
546
547 try:
548 installedVer, installedTag, installedRev = cdb_getversioning(c_id)
549 except TypeError:
550 installedVer = "0"
551 installedTag = ''
552 installedRev = 0
553
554
555
556 do_deep = deep_deps
557 if not do_deep:
558 string_rev = etp_get_rev(dependency)
559 if string_rev == -1:
560 do_deep = True
561
562 vcmp = etp_cmp((repo_pkgver,repo_pkgtag,repo_pkgrev,), (installedVer,installedTag,installedRev,))
563 if vcmp != 0:
564 if not do_deep and ((repo_pkgver,repo_pkgtag,) == (installedVer,installedTag,)) and (repo_pkgrev != installedRev):
565 depcache[dependency] = 0
566 return 0
567 depcache[dependency] = dependency
568 return dependency
569 depcache[dependency] = 0
570 return 0
571
572 unsatisfied = map(fm_dep,dependencies)
573 unsatisfied = set([x for x in unsatisfied if x != 0])
574
575 if self.xcache:
576 self.Cacher.push(c_hash,unsatisfied)
577
578 return unsatisfied
579
581
582 if not isinstance(matchfilter,set):
583 matchfilter = set()
584
585 maskedtree = {}
586 mybuffer = Lifo()
587 depcache = set()
588 treelevel = -1
589
590 match_id, match_repo = match
591
592 mydbconn = self.open_repository(match_repo)
593 myatom = mydbconn.retrieveAtom(match_id)
594 idpackage, idreason = mydbconn.idpackageValidator(match_id)
595 if idpackage == -1:
596 treelevel += 1
597 if atoms:
598 mydict = {myatom: idreason,}
599 else:
600 mydict = {match: idreason,}
601 if flat:
602 maskedtree.update(mydict)
603 else:
604 maskedtree[treelevel] = mydict
605
606 mydeps = mydbconn.retrieveDependencies(match_id)
607 for mydep in mydeps: mybuffer.push(mydep)
608 mydep = mybuffer.pop()
609
610 open_db = self.open_repository
611 am = self.atom_match
612 while mydep:
613
614 if mydep in depcache:
615 mydep = mybuffer.pop()
616 continue
617 depcache.add(mydep)
618
619 idpackage, repoid = am(mydep)
620 if (idpackage, repoid) in matchfilter:
621 mydep = mybuffer.pop()
622 continue
623
624 if idpackage != -1:
625
626
627 matchfilter.add((idpackage, repoid))
628
629
630 if idpackage == -1:
631 idpackage, repoid = am(mydep, packagesFilter = False)
632 if idpackage != -1:
633 treelevel += 1
634 if not maskedtree.has_key(treelevel) and not flat:
635 maskedtree[treelevel] = {}
636 dbconn = open_db(repoid)
637 vidpackage, idreason = dbconn.idpackageValidator(idpackage)
638 if atoms:
639 mydict = {dbconn.retrieveAtom(idpackage): idreason}
640 else:
641 mydict = {(idpackage,repoid): idreason}
642 if flat: maskedtree.update(mydict)
643 else: maskedtree[treelevel].update(mydict)
644
645
646 if idpackage != -1:
647 matchfilter.add((idpackage, repoid))
648 dbconn = open_db(repoid)
649 owndeps = dbconn.retrieveDependencies(idpackage)
650 for owndep in owndeps:
651 mybuffer.push(owndep)
652
653 mydep = mybuffer.pop()
654
655 return maskedtree
656
657
658 - def generate_dependency_tree(self,
659 matched_atom, empty_deps = False, deep_deps = False, matchfilter = None,
660 flat = False, filter_unsat_cache = None, treecache = None, keyslotcache = None):
661
662 if not isinstance(matchfilter,set):
663 matchfilter = set()
664 if not isinstance(filter_unsat_cache,dict):
665 filter_unsat_cache = {}
666 if not isinstance(treecache,set):
667 treecache = set()
668 if not isinstance(keyslotcache,set):
669 keyslotcache = set()
670
671 mydbconn = self.open_repository(matched_atom[1])
672 myatom = mydbconn.retrieveAtom(matched_atom[0])
673
674
675
676 deps_not_found = set()
677 conflicts = set()
678
679 mydep = (1,myatom)
680 mybuffer = Lifo()
681 deptree = set()
682 if matched_atom not in matchfilter:
683 deptree.add((1,matched_atom))
684
685 virgin = True
686 open_repo = self.open_repository
687 atom_match = self.atom_match
688 cdb_atom_match = self.clientDbconn.atomMatch
689 lookup_conflict_replacement = self._lookup_conflict_replacement
690 lookup_library_breakages = self._lookup_library_breakages
691 lookup_inverse_dependencies = self._lookup_inverse_dependencies
692 get_unsatisfied_deps = self.get_unsatisfied_dependencies
693
694 def my_dep_filter(x):
695 if x in treecache: return False
696 if tuple(x.split(":")) in keyslotcache: return False
697 return True
698
699 while mydep:
700
701 dep_level, dep_atom = mydep
702
703
704 if dep_atom in treecache:
705 mydep = mybuffer.pop()
706 continue
707 treecache.add(dep_atom)
708
709 if dep_atom == None:
710 mydep = mybuffer.pop()
711 continue
712
713
714 if dep_atom[0] == "!":
715 c_idpackage, xst = cdb_atom_match(dep_atom[1:])
716 if c_idpackage != -1:
717 myreplacement = lookup_conflict_replacement(dep_atom[1:], c_idpackage, deep_deps = deep_deps)
718 if (myreplacement != None) and (myreplacement not in treecache):
719 mybuffer.push((dep_level+1,myreplacement))
720 else:
721 conflicts.add(c_idpackage)
722 mydep = mybuffer.pop()
723 continue
724
725
726 if virgin:
727 virgin = False
728 m_idpackage, m_repo = matched_atom
729 dbconn = open_repo(m_repo)
730 myidpackage, idreason = dbconn.idpackageValidator(m_idpackage)
731 if myidpackage == -1: m_idpackage = -1
732 else:
733 m_idpackage, m_repo = atom_match(dep_atom)
734 if m_idpackage == -1:
735 deps_not_found.add(dep_atom)
736 mydep = mybuffer.pop()
737 continue
738
739
740 matchdb = open_repo(m_repo)
741 matchatom = matchdb.retrieveAtom(m_idpackage)
742 matchkey, matchslot = matchdb.retrieveKeySlot(m_idpackage)
743 if (dep_atom != matchatom) and (matchatom in treecache):
744 mydep = mybuffer.pop()
745 continue
746
747 treecache.add(matchatom)
748
749
750 if (matchslot,matchkey) in keyslotcache:
751 mydep = mybuffer.pop()
752 continue
753 else:
754 keyslotcache.add((matchslot,matchkey))
755
756 match = (m_idpackage, m_repo,)
757
758 if match in matchfilter:
759 mydep = mybuffer.pop()
760 continue
761
762
763 matchfilter.add(match)
764 treedepth = dep_level+1
765 deptree.add((dep_level,match))
766
767
768 cm_idpackage, cm_result = cdb_atom_match(matchkey, matchSlot = matchslot)
769 if cm_idpackage != -1:
770 broken_atoms = lookup_library_breakages(match, (cm_idpackage, cm_result,), deep_deps = deep_deps)
771 inverse_deps = lookup_inverse_dependencies(match, (cm_idpackage, cm_result,))
772 if inverse_deps:
773 deptree.remove((dep_level,match))
774 for ikey,islot in inverse_deps:
775 iks_str = '%s:%s' % (ikey,islot,)
776 if ((ikey,islot) not in keyslotcache) and (iks_str not in treecache):
777 mybuffer.push((dep_level,iks_str))
778 keyslotcache.add((ikey,islot))
779 deptree.add((treedepth,match))
780 treedepth += 1
781 for x in broken_atoms:
782 if (tuple(x.split(":")) not in keyslotcache) and (x not in treecache):
783 mybuffer.push((treedepth,x))
784
785 myundeps = filter(my_dep_filter,matchdb.retrieveDependenciesList(m_idpackage))
786 if not empty_deps:
787 myundeps = filter(my_dep_filter,get_unsatisfied_deps(myundeps, deep_deps, depcache = filter_unsat_cache))
788
789
790 if myundeps:
791 post_deps = [x for x in matchdb.retrievePostDependencies(m_idpackage) if x in myundeps]
792 if post_deps:
793
794 myundeps = [x for x in myundeps if x not in post_deps]
795 for x in post_deps: mybuffer.push((-1,x))
796
797 for x in myundeps: mybuffer.push((treedepth,x))
798 mydep = mybuffer.pop()
799
800 if deps_not_found:
801 return list(deps_not_found),-2
802
803 if flat: return [x[1] for x in deptree],0
804
805 newdeptree = {}
806 for key, item in deptree:
807 if key >= 0:
808
809 key += 1
810 obj = newdeptree.setdefault(key, set())
811 obj.add(item)
812
813 newdeptree[0] = conflicts
814
815 return newdeptree,0
816
817
819
820 data = self.SystemSettings['repos_system_mask']
821 if not data: return []
822 mydata = []
823 cached_items = set()
824 for atom in data:
825 mymatch = self.atom_match(atom)
826 if mymatch[0] == -1:
827 continue
828 if mymatch in cached_items:
829 continue
830 if mymatch not in mydata:
831
832 myaction = self.get_package_action(mymatch)
833
834 if myaction == 1: mydata.append(mymatch)
835 cached_items.add(mymatch)
836 return mydata
837
839 if self.entropyTools.isjustname(conflict_atom):
840 return None
841 conflict_match = self.atom_match(conflict_atom)
842 mykey, myslot = self.clientDbconn.retrieveKeySlot(client_idpackage)
843 new_match = self.atom_match(mykey, matchSlot = myslot)
844 if (conflict_match == new_match) or (new_match[1] == 1):
845 return None
846 action = self.get_package_action(new_match)
847 if (action == 0) and (not deep_deps):
848 return None
849 return "%s:%s" % (mykey,myslot,)
850
852
853 cmpstat = self.get_package_action(match)
854 if cmpstat == 0: return set()
855
856 keyslots = set()
857 mydepends = self.clientDbconn.retrieveDepends(clientmatch[0])
858 am = self.atom_match
859 cdb_rdeps = self.clientDbconn.retrieveDependencies
860 cdb_rks = self.clientDbconn.retrieveKeySlot
861 gpa = self.get_package_action
862 keyslots_cache = set()
863 match_cache = {}
864
865 for idpackage in mydepends:
866 try:
867 key, slot = cdb_rks(idpackage)
868 except TypeError:
869 continue
870 if (key,slot) in keyslots_cache: continue
871 keyslots_cache.add((key,slot))
872 if (key,slot) in keyslots: continue
873
874 mydeps = cdb_rdeps(idpackage)
875 found = False
876 for mydep in mydeps:
877 mymatch = match_cache.get(mydep, 0)
878 if mymatch == 0:
879 mymatch = am(mydep)
880 match_cache[mydep] = mymatch
881 if mymatch == match:
882 found = True
883 break
884 if not found:
885 mymatch = am(key, matchSlot = slot)
886 if mymatch[0] == -1: continue
887 cmpstat = gpa(mymatch)
888 if cmpstat == 0: continue
889 keyslots.add((key,slot))
890
891 return keyslots
892
894 repo_needed = match_db.retrieveNeeded(match_idpackage, extended = True, format = True)
895 client_needed = self.clientDbconn.retrieveNeeded(client_idpackage, extended = True, format = True)
896 repo_split = [x.split(".so")[0] for x in repo_needed]
897 client_split = [x.split(".so")[0] for x in client_needed]
898 client_side = [x for x in client_needed if (x not in repo_needed) and (x.split(".so")[0] in repo_split)]
899 repo_side = [x for x in repo_needed if (x not in client_needed) and (x.split(".so")[0] in client_split)]
900 return repo_needed, client_side, repo_side
901
903
904
905
906 c_hash = "%s|%s|%s" % (hash(tuple(match)),hash(deep_deps),hash(tuple(clientmatch)),)
907 c_hash = "%s%s" % (etpCache['library_breakage'],hash(c_hash),)
908 if self.xcache:
909 cached = self.Cacher.pop(c_hash)
910 if cached != None: return cached
911
912
913 repo_atoms = set()
914
915 client_atoms = set()
916
917 matchdb = self.open_repository(match[1])
918 reponeeded, client_side, repo_side = self.__get_lib_breaks_client_and_repo_side(matchdb,
919 match[0], clientmatch[0])
920
921
922 client_idpackages = set()
923 for needed in client_side: client_idpackages |= self.clientDbconn.searchNeeded(needed)
924
925 client_keyslots = set()
926 def mymf(idpackage):
927 if idpackage == clientmatch[0]:
928 return 0
929 ks = self.clientDbconn.retrieveKeySlot(idpackage)
930 if ks is None:
931 return 0
932 return ks
933 client_keyslots = set([x for x in map(mymf,client_idpackages) if x != 0])
934
935
936 repodata = {}
937 for needed in repo_side:
938 repodata[needed] = reponeeded[needed]
939 del repo_side,reponeeded
940
941 repo_dependencies = matchdb.retrieveDependencies(match[0])
942 matched_deps = set()
943 matched_repos = set()
944 for dependency in repo_dependencies:
945 depmatch = self.atom_match(dependency)
946 if depmatch[0] == -1:
947 continue
948 matched_repos.add(depmatch[1])
949 matched_deps.add(depmatch)
950
951 matched_repos = [x for x in self.SystemSettings['repositories']['order'] \
952 if x in matched_repos]
953 found_matches = set()
954 for needed in repodata:
955 for myrepo in matched_repos:
956 mydbc = self.open_repository(myrepo)
957 solved_needed = mydbc.resolveNeeded(needed,
958 repodata[needed])
959 found = False
960 for idpackage in solved_needed:
961 x = (idpackage, myrepo)
962 if x in matched_deps:
963 found_matches.add(x)
964 found = True
965 break
966 if found:
967 break
968
969 for idpackage,repo in found_matches:
970 if not deep_deps:
971 cmpstat = self.get_package_action((idpackage,repo))
972 if cmpstat == 0:
973 continue
974 mydbc = self.open_repository(repo)
975 repo_atoms.add(mydbc.retrieveAtom(idpackage))
976
977 for key, slot in client_keyslots:
978 idpackage, repo = self.atom_match(key, matchSlot = slot)
979 if idpackage == -1:
980 continue
981 if not deep_deps:
982 cmpstat = self.get_package_action((idpackage, repo))
983 if cmpstat == 0:
984 continue
985 mydbc = self.open_repository(repo)
986 client_atoms.add(mydbc.retrieveAtom(idpackage))
987
988 client_atoms |= repo_atoms
989
990 if self.xcache:
991 self.Cacher.push(c_hash,client_atoms)
992
993 return client_atoms
994
995
997
998 c_hash = "%s%s" % (etpCache['dep_tree'],hash("%s|%s|%s|%s" % (
999 hash(frozenset(sorted(matched_atoms))),hash(empty_deps),
1000 hash(deep_deps),self.clientDbconn.database_checksum(),
1001 )),)
1002 if self.xcache:
1003 cached = self.Cacher.pop(c_hash)
1004 if cached != None: return cached
1005
1006 deptree = {}
1007 deptree[0] = set()
1008
1009 atomlen = len(matched_atoms); count = 0
1010 error_generated = 0
1011 error_tree = set()
1012
1013
1014 forced_matches = self._lookup_system_mask_repository_deps()
1015 if forced_matches:
1016 if isinstance(matched_atoms, list):
1017 matched_atoms = forced_matches + [x for x in matched_atoms if x not in forced_matches]
1018 elif isinstance(matched_atoms, set):
1019 matched_atoms |= set(forced_matches)
1020
1021 sort_dep_text = _("Sorting dependencies")
1022 filter_unsat_cache = {}
1023 treecache = set()
1024 keyslotcache = set()
1025 matchfilter = set()
1026 for matched_atom in matched_atoms:
1027
1028 if not quiet:
1029 count += 1
1030 if (count%10 == 0) or (count == atomlen) or (count == 1):
1031 self.updateProgress(sort_dep_text, importance = 0, type = "info",
1032 back = True, header = ":: ", footer = " ::",
1033 percent = True, count = (count,atomlen))
1034
1035 if matched_atom in matchfilter: continue
1036 newtree, result = self.generate_dependency_tree(
1037 matched_atom, empty_deps, deep_deps,
1038 matchfilter = matchfilter, filter_unsat_cache = filter_unsat_cache, treecache = treecache,
1039 keyslotcache = keyslotcache
1040 )
1041
1042 if result == -2:
1043 error_generated = -2
1044 error_tree |= set(newtree)
1045 elif (result != 0):
1046 return newtree, result
1047 elif newtree:
1048
1049 max_parent_key = max(deptree)
1050 deptree[0] |= newtree.pop(0)
1051 levelcount = 0
1052 for mylevel in sorted(newtree.keys(), reverse = True):
1053 levelcount += 1
1054 deptree[max_parent_key+levelcount] = newtree.get(mylevel)
1055
1056 if error_generated != 0:
1057 return error_tree,error_generated
1058
1059 if self.xcache:
1060 self.Cacher.push(c_hash,(deptree,0))
1061
1062 return deptree,0
1063
1065 remove_depends = set()
1066 for d_idpackage in depends:
1067 mydeps = self.clientDbconn.retrieveDependencies(d_idpackage)
1068 for mydep in mydeps:
1069 matches, rslt = self.clientDbconn.atomMatch(mydep, multiMatch = True)
1070 if rslt == 1: continue
1071 if idpackage in matches and len(matches) > 1:
1072
1073 for mymatch in matches:
1074 if mymatch not in depends and mymatch not in monotree:
1075 remove_depends.add(d_idpackage)
1076 break
1077 depends -= remove_depends
1078 return depends
1079
1080
1082
1083 c_hash = "%s%s" % (etpCache['depends_tree'],hash("%s|%s" % (
1084 hash(tuple(sorted(idpackages))),hash(deep),),),)
1085 if self.xcache:
1086 cached = self.Cacher.pop(c_hash)
1087 if cached != None: return cached
1088
1089 dependscache = set()
1090 treeview = set(idpackages)
1091 treelevel = set(idpackages)
1092 tree = {}
1093
1094 treedepth = 0
1095 tree[treedepth] = set(idpackages)
1096 monotree = set(idpackages)
1097
1098
1099 pdepend_id = etpConst['spm']['pdepend_id']
1100
1101 self.clientDbconn.retrieveDepends(idpackages[0])
1102 count = 0
1103
1104 rem_dep_text = _("Calculating inverse dependencies for")
1105 while 1:
1106 treedepth += 1
1107 tree[treedepth] = set()
1108 for idpackage in treelevel:
1109
1110 count += 1
1111 p_atom = self.clientDbconn.retrieveAtom(idpackage)
1112 self.updateProgress(
1113 blue(rem_dep_text + " %s" % (red(p_atom),)),
1114 importance = 0,
1115 type = "info",
1116 back = True,
1117 header = '|/-\\'[count%4]+" "
1118 )
1119
1120 systempkg = not self.validate_package_removal(idpackage)
1121 if (idpackage in dependscache) or systempkg:
1122 if idpackage in treeview:
1123 treeview.remove(idpackage)
1124 continue
1125
1126
1127 depends = self.clientDbconn.retrieveDepends(idpackage,
1128 exclude_deptypes = (pdepend_id,))
1129
1130 depends = set([x for x in depends if x not in monotree])
1131 depends = set([x for x in depends if \
1132 self.validate_package_removal(x)])
1133 if depends:
1134 depends = self._filter_depends_multimatched_atoms(
1135 idpackage, depends, monotree)
1136 if depends:
1137 tree[treedepth] |= depends
1138 monotree |= depends
1139 treeview |= depends
1140 elif deep:
1141
1142 mydeps = set()
1143 for x in self.clientDbconn.retrieveDependencies(idpackage):
1144 match = self.clientDbconn.atomMatch(x)
1145 if match[0] != -1:
1146 mydeps.add(match[0])
1147
1148
1149 mydeps = [x for x in mydeps if x not in monotree and not \
1150 (self.clientDbconn.isSystemPackage(x) or \
1151 self.is_installed_idpackage_in_system_mask(x) )]
1152 for x in mydeps:
1153 mydepends = self.clientDbconn.retrieveDepends(x)
1154 mydepends -= set([y for y in mydepends if y \
1155 not in monotree])
1156 if not mydepends:
1157 tree[treedepth].add(x)
1158 monotree.add(x)
1159 treeview.add(x)
1160
1161 dependscache.add(idpackage)
1162 if idpackage in treeview:
1163 treeview.remove(idpackage)
1164
1165 treelevel = treeview.copy()
1166 if not treelevel:
1167 if not tree[treedepth]:
1168 del tree[treedepth]
1169 break
1170
1171
1172 for count in sorted(tree.keys(), reverse = True):
1173 x = 0
1174 while x < count:
1175 tree[x] -= tree[count]
1176 x += 1
1177
1178 if self.xcache:
1179 self.Cacher.push(c_hash,(tree,0))
1180
1181
1182 return tree,0
1183
1185
1186 branch = self.SystemSettings['repositories']['branch']
1187 c_hash = self.get_available_packages_chash(branch)
1188
1189 if use_cache and self.xcache:
1190 cached = self.get_available_packages_cache(myhash = c_hash)
1191 if cached != None:
1192 return cached
1193
1194 available = []
1195 self.setTotalCycles(len(self.validRepositories))
1196 avail_dep_text = _("Calculating available packages for")
1197 for repo in self.validRepositories:
1198 try:
1199 dbconn = self.open_repository(repo)
1200 dbconn.validateDatabase()
1201 except (RepositoryError,SystemDatabaseError):
1202 self.cycleDone()
1203 continue
1204 idpackages = [x for x in dbconn.listAllIdpackages(
1205 order_by = 'atom') if dbconn.idpackageValidator(x)[0] != -1]
1206 count = 0
1207 maxlen = len(idpackages)
1208 myavailable = []
1209 do_break = False
1210 for idpackage in idpackages:
1211 if do_break:
1212 break
1213 count += 1
1214 if (count % 10 == 0) or (count == 1) or (count == maxlen):
1215 self.updateProgress(
1216 avail_dep_text + " %s" % (repo,),
1217 importance = 0,
1218 type = "info",
1219 back = True,
1220 header = "::",
1221 count = (count,maxlen),
1222 percent = True,
1223 footer = " ::"
1224 )
1225
1226 try:
1227 key, slot = dbconn.retrieveKeySlot(idpackage)
1228 matches = self.clientDbconn.searchKeySlot(key, slot)
1229 except (self.dbapi2.DatabaseError,self.dbapi2.IntegrityError,self.dbapi2.OperationalError,):
1230 self.cycleDone()
1231 do_break = True
1232 continue
1233 if not matches: myavailable.append((idpackage,repo))
1234 available += myavailable[:]
1235 self.cycleDone()
1236
1237 if self.xcache:
1238 self.Cacher.push("%s%s" % (etpCache['world_available'],c_hash),available)
1239 return available
1240
1243
1244 if branch == None:
1245 branch = self.SystemSettings['repositories']['branch']
1246
1247 db_digest = self.all_repositories_checksum()
1248 if use_cache and self.xcache:
1249 cached = self.get_world_update_cache(empty_deps = empty_deps,
1250 branch = branch, db_digest = db_digest)
1251 if cached != None: return cached
1252
1253 misc_settings = self.SystemSettings[self.sys_settings_client_plugin_id]['misc']
1254 ignore_spm_downgrades = misc_settings['ignore_spm_downgrades']
1255 update = []
1256 remove = []
1257 fine = []
1258 spm_fine = []
1259
1260
1261 idpackages = self.clientDbconn.listAllIdpackages(order_by = 'atom')
1262 maxlen = len(idpackages)
1263 count = 0
1264 mytxt = _("Calculating world packages")
1265 for idpackage in idpackages:
1266
1267 count += 1
1268 if (count%10 == 0) or (count == maxlen) or (count == 1):
1269 self.updateProgress(
1270 mytxt,
1271 importance = 0,
1272 type = "info",
1273 back = True,
1274 header = ":: ",
1275 count = (count,maxlen),
1276 percent = True,
1277 footer = " ::"
1278 )
1279
1280 try:
1281 cl_pkgkey, cl_slot, cl_version, \
1282 cl_tag, cl_revision, \
1283 cl_atom = self.clientDbconn.getStrictData(idpackage)
1284 except TypeError:
1285
1286 continue
1287 use_match_cache = True
1288 do_continue = False
1289 while 1:
1290 try:
1291 match = self.atom_match(
1292 cl_pkgkey,
1293 matchSlot = cl_slot,
1294 matchBranches = (branch,),
1295 extendedResults = True,
1296 useCache = use_match_cache
1297 )
1298 except self.dbapi2.OperationalError:
1299
1300 do_continue = True
1301 break
1302 try:
1303 m_idpackage = match[0][0]
1304 except TypeError:
1305 if not use_match_cache: raise
1306 use_match_cache = False
1307 continue
1308 break
1309 if do_continue: continue
1310
1311
1312
1313
1314 if (m_idpackage != -1):
1315 repoid = match[1]
1316 version = match[0][1]
1317 tag = match[0][2]
1318 revision = match[0][3]
1319 if empty_deps:
1320 if (m_idpackage,repoid) not in update:
1321 update.append((m_idpackage,repoid))
1322 continue
1323 elif (cl_revision != revision):
1324
1325 if cl_revision == 9999 and ignore_spm_downgrades:
1326
1327 fine.append(cl_atom)
1328 if (m_idpackage,repoid) not in update:
1329 spm_fine.append((m_idpackage,repoid))
1330 continue
1331 else:
1332 if (m_idpackage,repoid) not in update:
1333 update.append((m_idpackage,repoid))
1334 continue
1335 elif (cl_version != version):
1336
1337 if (m_idpackage,repoid) not in update:
1338 update.append((m_idpackage,repoid))
1339 continue
1340 elif (cl_tag != tag):
1341
1342 if (m_idpackage,repoid) not in update:
1343 update.append((m_idpackage,repoid))
1344 continue
1345 else:
1346
1347 fine.append(cl_atom)
1348 continue
1349
1350
1351 maskedresults = self.atom_match(cl_pkgkey, matchSlot = cl_slot,
1352 matchBranches = (branch,), packagesFilter = False)
1353 if maskedresults[0] == -1:
1354 remove.append(idpackage)
1355
1356
1357 matchresults = self.atom_match(cl_pkgkey,
1358 matchBranches = (branch,))
1359 if matchresults[0] != -1:
1360 m_action = self.get_package_action(matchresults)
1361 if m_action > 0 and (matchresults not in update):
1362 update.append(matchresults)
1363
1364 if self.xcache:
1365 c_hash = self.get_world_update_cache_hash(db_digest, empty_deps,
1366 branch, ignore_spm_downgrades)
1367 data = {
1368 'r': (update, remove, fine, spm_fine,),
1369 'empty_deps': empty_deps,
1370 }
1371 self.Cacher.push("%s%s" % (etpCache['world_update'],c_hash,),
1372 data, async = False)
1373
1374 return update, remove, fine, spm_fine
1375
1377
1378 c_hash = "%s%s" % (etpCache['check_package_update'],hash("%s%s" % (atom,hash(deep),)),)
1379 if self.xcache:
1380 cached = self.Cacher.pop(c_hash)
1381 if cached != None:
1382 return cached
1383
1384 found = False
1385 match = self.clientDbconn.atomMatch(atom)
1386 matched = None
1387 if match[0] != -1:
1388 myatom = self.clientDbconn.retrieveAtom(match[0])
1389 mytag = self.entropyTools.dep_gettag(myatom)
1390 myatom = self.entropyTools.remove_tag(myatom)
1391 myrev = self.clientDbconn.retrieveRevision(match[0])
1392 pkg_match = "="+myatom+"~"+str(myrev)
1393 if mytag != None:
1394 pkg_match += "#%s" % (mytag,)
1395 pkg_unsatisfied = self.get_unsatisfied_dependencies([pkg_match], deep_deps = deep)
1396 if pkg_unsatisfied:
1397
1398 pkg_key = self.entropyTools.dep_getkey(myatom)
1399 pkg_id, pkg_repo = self.atom_match(pkg_key)
1400 if pkg_id != -1:
1401 found = True
1402 del pkg_unsatisfied
1403 matched = self.atom_match(pkg_match)
1404 del match
1405
1406 if self.xcache:
1407 self.Cacher.push(c_hash,(found, matched))
1408 return found, matched
1409
1410
1411
1412
1414 if branch == None:
1415 branch = self.SystemSettings['repositories']['branch']
1416 update, remove, fine, spm_fine = self.calculate_world_updates(
1417 empty_deps = empty_deps, branch = branch)
1418 del fine
1419 data = {}
1420 data['removed'] = list(remove)
1421 data['runQueue'] = []
1422 data['removalQueue'] = []
1423 status = -1
1424 if update:
1425
1426 install, removal, status = self.get_install_queue(
1427 update, empty_deps, deep_deps = False)
1428
1429 data['removed'] = [x for x in data['removed'] if x not in removal]
1430 data['runQueue'] += install
1431 data['removalQueue'] += removal
1432 return data,status
1433
1435
1436 pkgatom = self.clientDbconn.retrieveAtom(idpackage)
1437 pkgkey = self.entropyTools.dep_getkey(pkgatom)
1438 client_plugin_id = etpConst['system_settings_plugins_ids']['client_plugin']
1439 mask_installed_keys = self.SystemSettings[client_plugin_id]['system_mask']['repos_installed_keys']
1440
1441 if self.is_installed_idpackage_in_system_mask(idpackage):
1442 idpackages = mask_installed_keys.get(pkgkey)
1443 if not idpackages: return False
1444 if len(idpackages) > 1:
1445 return True
1446 return False
1447
1448
1449 system_pkg = self.clientDbconn.isSystemPackage(idpackage)
1450 if not system_pkg: return True
1451
1452 matches, rc = self.clientDbconn.atomMatch(pkgkey, multiMatch = True)
1453 if len(matches) < 2:
1454 return False
1455 return True
1456
1457
1459 queue = []
1460 if not idpackages:
1461 return queue
1462 treeview, status = self.generate_depends_tree(idpackages, deep = deep)
1463 if status == 0:
1464 for x in range(len(treeview))[::-1]: queue.extend(treeview[x])
1465 return queue
1466
1468
1469 install = []
1470 removal = []
1471 treepackages, result = self.get_required_packages(matched_atoms, empty_deps, deep_deps, quiet = quiet)
1472
1473 if result == -2:
1474 return treepackages,removal,result
1475
1476
1477 removal = treepackages.pop(0, set())
1478 for x in sorted(treepackages.keys()): install.extend(treepackages[x])
1479
1480
1481 if install and removal:
1482 myremmatch = {}
1483 for x in removal:
1484 atom = self.clientDbconn.retrieveAtom(x)
1485
1486 if atom == None: continue
1487 myremmatch[(self.entropyTools.dep_getkey(atom),self.clientDbconn.retrieveSlot(x),)] = x
1488 for pkg_id, pkg_repo in install:
1489 dbconn = self.open_repository(pkg_repo)
1490 testtuple = (self.entropyTools.dep_getkey(dbconn.retrieveAtom(pkg_id)),dbconn.retrieveSlot(pkg_id))
1491 removal.discard(myremmatch.get(testtuple))
1492
1493 return install, sorted(removal), 0
1494