1
2 """
3
4 @author: Fabio Erculiani <lxnay@sabayonlinux.org>
5 @contact: lxnay@sabayonlinux.org
6 @copyright: Fabio Erculiani
7 @license: GPL-2
8
9 B{Entropy Framework repository database module}.
10 Entropy repositories (server and client) are implemented as relational
11 databases. Currently, EntropyRepository class is the object that wraps
12 sqlite3 database queries and repository logic: there are no more
13 abstractions between the two because there is only one implementation
14 available at this time. In future, entropy.db will feature more backends
15 such as MySQL embedded, SparQL, remote repositories support via TCP socket,
16 etc. This will require a new layer between the repository interface now
17 offered by EntropyRepository and the underlying data retrieval logic.
18 Every repository interface available inherits from EntropyRepository
19 class and has to reimplement its own Schema subclass and its get_init
20 method (see EntropyRepository documentation for more information).
21
22 I{EntropyRepository} is the sqlite3 implementation of the repository
23 interface, as written above.
24
25 @todo: migrate to "_" (underscore) convention
26
27 """
28 import sys
29 import os
30 import shutil
31 from entropy.const import etpConst, etpCache, const_setup_file, \
32 const_isunicode, const_convert_to_unicode, const_get_buffer, \
33 const_convert_to_rawstring, const_cmp
34 from entropy.exceptions import IncorrectParameter, InvalidAtom, \
35 SystemDatabaseError, OperationNotPermitted, RepositoryPluginError, SPMError
36 from entropy.i18n import _
37 from entropy.output import brown, bold, red, blue, purple, darkred, darkgreen, \
38 TextInterface
39 from entropy.cache import EntropyCacher
40 from entropy.core.settings.base import SystemSettings
41 from entropy.spm.plugins.factory import get_default_instance as get_spm
42 from entropy.db.plugin_store import EntropyRepositoryPluginStore
43
44 try:
45 from sqlite3 import dbapi2
46 except ImportError:
47 try:
48 from pysqlite2 import dbapi2
49 except ImportError as e:
50 raise SystemError(
51 "%s. %s: %s" % (
52 _("Entropy needs Python compiled with sqlite3 support"),
53 _("Error"),
54 e,
55 )
56 )
57
59
60 """
61 EntropyRepository implements SQLite3 based storage. In a Model-View based
62 pattern, it can be considered the "model".
63 Actually it's the only one available but more model backends will be
64 supported in future (which will inherit this class directly).
65
66 Every Entropy repository storage interface MUST inherit from this base
67 class.
68
69 @todo: refactoring and generalization needed
70 """
71
72 SETTING_KEYS = [ "arch", "on_delete_cascade" ]
73
75
77 return """
78 CREATE TABLE baseinfo (
79 idpackage INTEGER PRIMARY KEY AUTOINCREMENT,
80 atom VARCHAR,
81 idcategory INTEGER,
82 name VARCHAR,
83 version VARCHAR,
84 versiontag VARCHAR,
85 revision INTEGER,
86 branch VARCHAR,
87 slot VARCHAR,
88 idlicense INTEGER,
89 etpapi INTEGER,
90 trigger INTEGER
91 );
92
93 CREATE TABLE extrainfo (
94 idpackage INTEGER PRIMARY KEY,
95 description VARCHAR,
96 homepage VARCHAR,
97 download VARCHAR,
98 size VARCHAR,
99 idflags INTEGER,
100 digest VARCHAR,
101 datecreation VARCHAR,
102 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
103 );
104
105 CREATE TABLE content (
106 idpackage INTEGER,
107 file VARCHAR,
108 type VARCHAR,
109 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
110 );
111
112 CREATE TABLE provide (
113 idpackage INTEGER,
114 atom VARCHAR,
115 is_default INTEGER DEFAULT 0,
116 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
117 );
118
119 CREATE TABLE dependencies (
120 idpackage INTEGER,
121 iddependency INTEGER,
122 type INTEGER,
123 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
124 );
125
126 CREATE TABLE dependenciesreference (
127 iddependency INTEGER PRIMARY KEY AUTOINCREMENT,
128 dependency VARCHAR
129 );
130
131 CREATE TABLE dependstable (
132 iddependency INTEGER PRIMARY KEY,
133 idpackage INTEGER
134 );
135
136 CREATE TABLE conflicts (
137 idpackage INTEGER,
138 conflict VARCHAR,
139 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
140 );
141
142 CREATE TABLE mirrorlinks (
143 mirrorname VARCHAR,
144 mirrorlink VARCHAR
145 );
146
147 CREATE TABLE sources (
148 idpackage INTEGER,
149 idsource INTEGER,
150 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
151 );
152
153 CREATE TABLE sourcesreference (
154 idsource INTEGER PRIMARY KEY AUTOINCREMENT,
155 source VARCHAR
156 );
157
158 CREATE TABLE useflags (
159 idpackage INTEGER,
160 idflag INTEGER,
161 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
162 );
163
164 CREATE TABLE useflagsreference (
165 idflag INTEGER PRIMARY KEY AUTOINCREMENT,
166 flagname VARCHAR
167 );
168
169 CREATE TABLE keywords (
170 idpackage INTEGER,
171 idkeyword INTEGER,
172 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
173 );
174
175 CREATE TABLE keywordsreference (
176 idkeyword INTEGER PRIMARY KEY AUTOINCREMENT,
177 keywordname VARCHAR
178 );
179
180 CREATE TABLE categories (
181 idcategory INTEGER PRIMARY KEY AUTOINCREMENT,
182 category VARCHAR
183 );
184
185 CREATE TABLE licenses (
186 idlicense INTEGER PRIMARY KEY AUTOINCREMENT,
187 license VARCHAR
188 );
189
190 CREATE TABLE flags (
191 idflags INTEGER PRIMARY KEY AUTOINCREMENT,
192 chost VARCHAR,
193 cflags VARCHAR,
194 cxxflags VARCHAR
195 );
196
197 CREATE TABLE configprotect (
198 idpackage INTEGER PRIMARY KEY,
199 idprotect INTEGER,
200 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
201 );
202
203 CREATE TABLE configprotectmask (
204 idpackage INTEGER PRIMARY KEY,
205 idprotect INTEGER,
206 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
207 );
208
209 CREATE TABLE configprotectreference (
210 idprotect INTEGER PRIMARY KEY AUTOINCREMENT,
211 protect VARCHAR
212 );
213
214 CREATE TABLE systempackages (
215 idpackage INTEGER PRIMARY KEY,
216 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
217 );
218
219 CREATE TABLE injected (
220 idpackage INTEGER PRIMARY KEY,
221 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
222 );
223
224 CREATE TABLE installedtable (
225 idpackage INTEGER PRIMARY KEY,
226 repositoryname VARCHAR,
227 source INTEGER,
228 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
229 );
230
231 CREATE TABLE sizes (
232 idpackage INTEGER PRIMARY KEY,
233 size INTEGER,
234 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
235 );
236
237 CREATE TABLE messages (
238 idpackage INTEGER,
239 message VARCHAR,
240 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
241 );
242
243 CREATE TABLE counters (
244 counter INTEGER,
245 idpackage INTEGER,
246 branch VARCHAR,
247 PRIMARY KEY(idpackage,branch),
248 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
249 );
250
251 CREATE TABLE trashedcounters (
252 counter INTEGER
253 );
254
255 CREATE TABLE eclasses (
256 idpackage INTEGER,
257 idclass INTEGER,
258 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
259 );
260
261 CREATE TABLE eclassesreference (
262 idclass INTEGER PRIMARY KEY AUTOINCREMENT,
263 classname VARCHAR
264 );
265
266 CREATE TABLE needed (
267 idpackage INTEGER,
268 idneeded INTEGER,
269 elfclass INTEGER,
270 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
271 );
272
273 CREATE TABLE neededreference (
274 idneeded INTEGER PRIMARY KEY AUTOINCREMENT,
275 library VARCHAR
276 );
277
278 CREATE TABLE provided_libs (
279 idpackage INTEGER,
280 library VARCHAR,
281 path VARCHAR,
282 elfclass INTEGER,
283 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
284 );
285
286 CREATE TABLE treeupdates (
287 repository VARCHAR PRIMARY KEY,
288 digest VARCHAR
289 );
290
291 CREATE TABLE treeupdatesactions (
292 idupdate INTEGER PRIMARY KEY AUTOINCREMENT,
293 repository VARCHAR,
294 command VARCHAR,
295 branch VARCHAR,
296 date VARCHAR
297 );
298
299 CREATE TABLE licensedata (
300 licensename VARCHAR UNIQUE,
301 text BLOB,
302 compressed INTEGER
303 );
304
305 CREATE TABLE licenses_accepted (
306 licensename VARCHAR UNIQUE
307 );
308
309 CREATE TABLE triggers (
310 idpackage INTEGER PRIMARY KEY,
311 data BLOB,
312 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
313 );
314
315 CREATE TABLE entropy_misc_counters (
316 idtype INTEGER PRIMARY KEY,
317 counter INTEGER
318 );
319
320 CREATE TABLE categoriesdescription (
321 category VARCHAR,
322 locale VARCHAR,
323 description VARCHAR
324 );
325
326 CREATE TABLE packagesets (
327 setname VARCHAR,
328 dependency VARCHAR
329 );
330
331 CREATE TABLE packagechangelogs (
332 category VARCHAR,
333 name VARCHAR,
334 changelog BLOB,
335 PRIMARY KEY (category, name)
336 );
337
338 CREATE TABLE automergefiles (
339 idpackage INTEGER,
340 configfile VARCHAR,
341 md5 VARCHAR,
342 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
343 );
344
345 CREATE TABLE packagesignatures (
346 idpackage INTEGER PRIMARY KEY,
347 sha1 VARCHAR,
348 sha256 VARCHAR,
349 sha512 VARCHAR,
350 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
351 );
352
353 CREATE TABLE packagespmphases (
354 idpackage INTEGER PRIMARY KEY,
355 phases VARCHAR,
356 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
357 );
358
359 CREATE TABLE packagespmrepository (
360 idpackage INTEGER PRIMARY KEY,
361 repository VARCHAR,
362 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
363 );
364
365 CREATE TABLE entropy_branch_migration (
366 repository VARCHAR,
367 from_branch VARCHAR,
368 to_branch VARCHAR,
369 post_migration_md5sum VARCHAR,
370 post_upgrade_md5sum VARCHAR,
371 PRIMARY KEY (repository, from_branch, to_branch)
372 );
373
374 CREATE TABLE xpakdata (
375 idpackage INTEGER PRIMARY KEY,
376 data BLOB
377 );
378
379 CREATE TABLE settings (
380 setting_name VARCHAR,
381 setting_value VARCHAR,
382 PRIMARY KEY(setting_name)
383 );
384
385 """
386
387 import entropy.tools as entropyTools
388 import entropy.dump as dumpTools
389 import threading
390 - def __init__(self, readOnly = False, dbFile = None, xcache = False,
391 dbname = 'etpdb:', indexing = True, skipChecks = False):
392
393 """
394 EntropyRepository constructor.
395
396 @keyword readOnly: open file in read-only mode
397 @type readOnly: bool
398 @keyword dbFile: path to database to open
399 @type dbFile: string
400 @keyword xcache: enable on-disk cache
401 @type xcache: bool
402 @keyword dbname: EntropyRepository instance identifier
403 @type dbname: string
404 @keyword indexing: enable database indexes
405 @type indexing: bool
406 @keyword skipChecks: if True, skip integrity checks
407 @type skipChecks: bool
408 """
409 EntropyRepositoryPluginStore.__init__(self)
410
411 self.dbclosed = True
412 self.SystemSettings = SystemSettings()
413 self.dbMatchCacheKey = etpCache['dbMatch']
414 self.client_settings_plugin_id = \
415 etpConst['system_settings_plugins_ids']['client_plugin']
416 self.db_branch = self.SystemSettings['repositories']['branch']
417 self.Cacher = EntropyCacher()
418
419 self.dbname = dbname
420 if self.dbname == etpConst['clientdbid']:
421 self.db_branch = None
422
423 if dbFile is None:
424 raise IncorrectParameter("IncorrectParameter: %s" % (
425 _("valid database path needed"),) )
426
427 self.__write_mutex = self.threading.RLock()
428 self.dbapi2 = dbapi2
429
430 self.readOnly = readOnly
431 self.xcache = xcache
432 self.indexing = indexing
433 self.skipChecks = skipChecks
434 self.dbFile = dbFile
435 self.live_cache = {}
436
437
438 self.connection = self.dbapi2.connect(dbFile, timeout=300.0,
439 check_same_thread = False)
440 self.cursor = self.connection.cursor()
441
442
443
444 self.cursor.execute("pragma foreign_keys = 1")
445
446 structure_update = False
447 if not self.skipChecks:
448
449 if not self.entropyTools.is_user_in_entropy_group():
450
451 self.indexing = False
452
453 if self.entropyTools.islive():
454 self.indexing = False
455
456 try:
457 if os.access(self.dbFile, os.W_OK) and \
458 self._doesTableExist('baseinfo') and \
459 self._doesTableExist('extrainfo'):
460
461 if self.entropyTools.islive():
462 if etpConst['systemroot']:
463 structure_update = True
464 else:
465 structure_update = True
466
467 except self.dbapi2.Error:
468 self.cursor.close()
469 self.connection.close()
470 raise
471
472
473 self.dbclosed = False
474
475 if structure_update:
476 self._databaseStructureUpdates()
477
479 """
480 Change low-level, storage engine based cache size.
481
482 @param size: new size
483 @type size: int
484 """
485 self.cursor.execute('PRAGMA cache_size = %s' % (size,))
486
488 """
489 Change default low-level, storage engine based cache size.
490
491 @param size: new default size
492 @type size: int
493 """
494 self.cursor.execute('PRAGMA default_cache_size = %s' % (size,))
495
496
498 if not self.dbclosed:
499 self.closeDB()
500
502 """
503 Close repository storage communication.
504 Note: once issues this, you won't be able to use such instance
505 anymore.
506 """
507 self.dbclosed = True
508
509 try:
510
511 if not self.readOnly:
512 self.commitChanges()
513
514 plugins = self.get_plugins()
515 for plugin_id in sorted(plugins):
516 plug_inst = plugins[plugin_id]
517 exec_rc = plug_inst.close_repo_hook(self)
518 if exec_rc:
519 raise RepositoryPluginError(
520 "[close_repo_hook] %s: status: %s" % (
521 plug_inst.get_id(), exec_rc,))
522
523 finally:
524 self.cursor.close()
525 self.connection.close()
526
528 """
529 Repository storage cleanup and optimization function.
530 """
531 self.cursor.execute("vacuum")
532
534 """
535 Commit actual changes and make them permanently stored.
536
537 @keyword force: force commit, despite read-only bit being set
538 @type force: bool
539 """
540
541 if force or (not self.readOnly):
542 try:
543 self.connection.commit()
544 except self.dbapi2.Error:
545 pass
546
547 if no_plugins:
548 return
549
550 plugins = self.get_plugins()
551 for plugin_id in sorted(plugins):
552 plug_inst = plugins[plugin_id]
553 exec_rc = plug_inst.commit_hook(self)
554 if exec_rc:
555 raise RepositoryPluginError("[commit_hook] %s: status: %s" % (
556 plug_inst.get_id(), exec_rc,))
557
559 """
560 WARNING: it will erase your database.
561 This method (re)initializes the repository, dropping all its content.
562 """
563 my = self.Schema()
564 for table in self.listAllTables():
565 try:
566 self.cursor.execute("DROP TABLE %s" % (table,))
567 except self.dbapi2.OperationalError:
568
569 continue
570 self.cursor.executescript(my.get_init())
571 self._databaseStructureUpdates()
572
573 self.setCacheSize(8192)
574 self.setDefaultCacheSize(8192)
575 self._setupInitialSettings()
576
577 plugins = self.get_plugins()
578 for plugin_id in sorted(plugins):
579 plug_inst = plugins[plugin_id]
580 exec_rc = plug_inst.initialize_repo_hook(self)
581 if exec_rc:
582 raise RepositoryPluginError(
583 "[initialize_repo_hook] %s: status: %s" % (
584 plug_inst.get_id(), exec_rc,))
585
586 self.commitChanges()
587
589 """
590 This method should be considered internal and not suited for general
591 audience. Given a raw package name/slot updates list, it returns
592 the action that should be really taken because not applied.
593
594 @param actions: list of raw treeupdates actions, for example:
595 ['move x11-foo/bar app-foo/bar', 'slotmove x11-foo/bar 2 3']
596 @type actions: list
597 @return: list of raw treeupdates actions that should be really
598 worked out
599 @rtype: list
600 """
601 new_actions = []
602 for action in actions:
603
604 if action in new_actions:
605 continue
606
607 doaction = action.split()
608 if doaction[0] == "slotmove":
609
610
611 atom = doaction[1]
612 from_slot = doaction[2]
613 to_slot = doaction[3]
614 atom_key = self.entropyTools.dep_getkey(atom)
615 category = atom_key.split("/")[0]
616 matches, sm_rc = self.atomMatch(atom, matchSlot = from_slot,
617 multiMatch = True)
618 if sm_rc == 1:
619
620
621
622 continue
623 found = False
624
625 for idpackage in matches:
626 myslot = self.retrieveSlot(idpackage)
627 mycategory = self.retrieveCategory(idpackage)
628 if mycategory == category:
629 if (myslot != to_slot) and \
630 (action not in new_actions):
631 new_actions.append(action)
632 found = True
633 break
634 if found:
635 continue
636
637
638 dep_atoms = self.searchDependency(atom_key, like = True,
639 multi = True, strings = True)
640 dep_atoms = [x for x in dep_atoms if x.endswith(":"+from_slot) \
641 and self.entropyTools.dep_getkey(x) == atom_key]
642 if dep_atoms:
643 new_actions.append(action)
644
645 elif doaction[0] == "move":
646
647 atom = doaction[1]
648 atom_key = self.entropyTools.dep_getkey(atom)
649 category = atom_key.split("/")[0]
650 matches, m_rc = self.atomMatch(atom, multiMatch = True)
651 if m_rc == 1:
652
653
654
655 continue
656 found = False
657 for idpackage in matches:
658 mycategory = self.retrieveCategory(idpackage)
659 if (mycategory == category) and (action \
660 not in new_actions):
661 new_actions.append(action)
662 found = True
663 break
664 if found:
665 continue
666
667
668 dep_atoms = self.searchDependency(atom_key, like = True,
669 multi = True, strings = True)
670 dep_atoms = [x for x in dep_atoms if \
671 self.entropyTools.dep_getkey(x) == atom_key]
672 if dep_atoms:
673 new_actions.append(action)
674
675 return new_actions
676
678
679 """
680 Method not suited for general purpose usage.
681 Executes package name/slot update actions passed.
682
683 @param actions: list of raw treeupdates actions, for example:
684 ['move x11-foo/bar app-foo/bar', 'slotmove x11-foo/bar 2 3']
685 @type actions: list
686
687 @return: list (set) of packages that should be repackaged
688 @rtype: set
689 """
690 mytxt = "%s: %s, %s." % (
691 bold(_("SPM")),
692 blue(_("Running fixpackages")),
693 red(_("it could take a while")),
694 )
695 self.updateProgress(
696 mytxt,
697 importance = 1,
698 type = "warning",
699 header = darkred(" * ")
700 )
701 try:
702 spm = get_spm(self)
703 spm.packages_repositories_metadata_update()
704 except:
705 self.entropyTools.print_traceback()
706
707 spm_moves = set()
708 quickpkg_atoms = set()
709 for action in actions:
710 command = action.split()
711 mytxt = "%s: %s: %s." % (
712 bold(_("ENTROPY")),
713 red(_("action")),
714 blue(action),
715 )
716 self.updateProgress(
717 mytxt,
718 importance = 1,
719 type = "warning",
720 header = darkred(" * ")
721 )
722 if command[0] == "move":
723 spm_moves.add(action)
724 quickpkg_atoms |= self.runTreeUpdatesMoveAction(command[1:],
725 quickpkg_atoms)
726 elif command[0] == "slotmove":
727 quickpkg_atoms |= self.runTreeUpdatesSlotmoveAction(command[1:],
728 quickpkg_atoms)
729
730 mytxt = "%s: %s." % (
731 bold(_("ENTROPY")),
732 blue(_("package move actions complete")),
733 )
734 self.updateProgress(
735 mytxt,
736 importance = 1,
737 type = "info",
738 header = purple(" @@ ")
739 )
740
741 if spm_moves:
742 try:
743 self.doTreeupdatesSpmCleanup(spm_moves)
744 except Exception as e:
745 mytxt = "%s: %s: %s, %s." % (
746 bold(_("WARNING")),
747 red(_("Cannot run SPM cleanup, error")),
748 Exception,
749 e,
750 )
751 self.entropyTools.print_traceback()
752
753 mytxt = "%s: %s." % (
754 bold(_("ENTROPY")),
755 blue(_("package moves completed successfully")),
756 )
757 self.updateProgress(
758 mytxt,
759 importance = 1,
760 type = "info",
761 header = brown(" @@ ")
762 )
763
764
765 self.clearCache()
766
767 return quickpkg_atoms
768
769
771
772
773
774
775
776
777 """
778 Method not suited for general purpose usage.
779 Executes package name move action passed.
780
781 @param move_command: raw treeupdates move action, for example:
782 'move x11-foo/bar app-foo/bar'
783 @type move_command: string
784 @param quickpkg_queue: current package regeneration queue
785 @type quickpkg_queue: list
786 @return: updated package regeneration queue
787 @rtype: list
788 """
789 dep_from = move_command[0]
790 key_from = self.entropyTools.dep_getkey(dep_from)
791 key_to = move_command[1]
792 cat_to = key_to.split("/")[0]
793 name_to = key_to.split("/")[1]
794 matches = self.atomMatch(dep_from, multiMatch = True)
795 iddependencies = set()
796
797 for idpackage in matches[0]:
798
799 slot = self.retrieveSlot(idpackage)
800 old_atom = self.retrieveAtom(idpackage)
801 new_atom = old_atom.replace(key_from, key_to)
802
803
804
805 self.setCategory(idpackage, cat_to)
806
807 self.setName(idpackage, name_to)
808
809 self.setAtom(idpackage, new_atom)
810
811
812 quickpkg_queue.add(key_to+":"+slot)
813
814 plugins = self.get_plugins()
815 for plugin_id in sorted(plugins):
816 plug_inst = plugins[plugin_id]
817 exec_rc = plug_inst.treeupdates_move_action_hook(self,
818 idpackage)
819 if exec_rc:
820 raise RepositoryPluginError(
821 "[treeupdates_move_action_hook] %s: status: %s" % (
822 plug_inst.get_id(), exec_rc,))
823
824 iddeps = self.searchDependency(key_from, like = True, multi = True)
825 for iddep in iddeps:
826
827 mydep = self.getDependency(iddep)
828 mydep_key = self.entropyTools.dep_getkey(mydep)
829
830
831 if mydep_key != key_from:
832 continue
833 mydep = mydep.replace(key_from, key_to)
834
835
836 self.setDependency(iddep, mydep)
837
838 iddependencies |= self.searchIdpackageFromIddependency(iddep)
839
840 self.commitChanges()
841 quickpkg_queue = list(quickpkg_queue)
842 for x in range(len(quickpkg_queue)):
843 myatom = quickpkg_queue[x]
844 myatom = myatom.replace(key_from, key_to)
845 quickpkg_queue[x] = myatom
846 quickpkg_queue = set(quickpkg_queue)
847 for idpackage_owner in iddependencies:
848 myatom = self.retrieveAtom(idpackage_owner)
849 myatom = myatom.replace(key_from, key_to)
850 quickpkg_queue.add(myatom)
851 return quickpkg_queue
852
853
855
856
857
858
859
860
861
862
863 """
864 Method not suited for general purpose usage.
865 Executes package slot move action passed.
866
867 @param slotmove_command: raw treeupdates slot move action, for example:
868 'slotmove x11-foo/bar 2 3'
869 @type slotmove_command: string
870 @param quickpkg_queue: current package regeneration queue
871 @type quickpkg_queue: list
872 @return: updated package regeneration queue
873 @rtype: list
874 """
875 atom = slotmove_command[0]
876 atomkey = self.entropyTools.dep_getkey(atom)
877 slot_from = slotmove_command[1]
878 slot_to = slotmove_command[2]
879 matches = self.atomMatch(atom, multiMatch = True)
880 iddependencies = set()
881
882 matched_idpackages = matches[0]
883 for idpackage in matched_idpackages:
884
885
886
887 self.setSlot(idpackage, slot_to)
888
889
890
891 quickpkg_queue.add(atom+":"+slot_to)
892
893
894 iddeps = self.searchDependency(atomkey, like = True, multi = True)
895 for iddep in iddeps:
896
897 mydep = self.getDependency(iddep)
898 mydep_key = self.entropyTools.dep_getkey(mydep)
899 if mydep_key != atomkey:
900 continue
901 if not mydep.endswith(":"+slot_from):
902 continue
903 mydep_match = self.atomMatch(mydep)
904 if mydep_match not in matched_idpackages:
905 continue
906 mydep = mydep.replace(":"+slot_from, ":"+slot_to)
907
908
909 self.setDependency(iddep, mydep)
910
911 iddependencies |= self.searchIdpackageFromIddependency(iddep)
912
913 plugins = self.get_plugins()
914 for plugin_id in sorted(plugins):
915 plug_inst = plugins[plugin_id]
916 exec_rc = plug_inst.treeupdates_slot_move_action_hook(self,
917 idpackage)
918 if exec_rc:
919 raise RepositoryPluginError(
920 "[treeupdates_slot_move_action_hook] %s: status: %s" % (
921 plug_inst.get_id(), exec_rc,))
922
923 self.commitChanges()
924 for idpackage_owner in iddependencies:
925 myatom = self.retrieveAtom(idpackage_owner)
926 quickpkg_queue.add(myatom)
927 return quickpkg_queue
928
930 """
931 Erase dead Source Package Manager db entries.
932
933 @todo: make more Portage independent (create proper entropy.spm
934 methods for dealing with this)
935 @param spm_moves: list of raw package name/slot update actions.
936 @type spm_moves: list
937 """
938
939 for action in spm_moves:
940 command = action.split()
941 if len(command) < 2:
942 continue
943
944 key = command[1]
945 category, name = key.split("/", 1)
946 dep_key = self.entropyTools.dep_getkey(key)
947
948 try:
949 spm = get_spm(self)
950 except:
951 self.entropyTools.print_traceback()
952 continue
953
954 script_path = spm.get_installed_package_build_script_path(dep_key)
955 pkg_path = os.path.dirname(os.path.dirname(script_path))
956 if not os.path.isdir(pkg_path):
957
958 continue
959
960 mydirs = [os.path.join(pkg_path, x) for x in \
961 os.listdir(pkg_path) if \
962 self.entropyTools.dep_getkey(os.path.join(category, x)) \
963 == dep_key]
964 mydirs = [x for x in mydirs if os.path.isdir(x)]
965
966
967 for mydir in mydirs:
968 to_path = os.path.join(etpConst['packagestmpdir'],
969 os.path.basename(mydir))
970 mytxt = "%s: %s '%s' %s '%s'" % (
971 bold(_("SPM")),
972 red(_("Moving old entry")),
973 blue(mydir),
974 red(_("to")),
975 blue(to_path),
976 )
977 self.updateProgress(
978 mytxt,
979 importance = 1,
980 type = "warning",
981 header = darkred(" * ")
982 )
983 if os.path.isdir(to_path):
984 shutil.rmtree(to_path, True)
985 try:
986 os.rmdir(to_path)
987 except OSError:
988 pass
989 shutil.move(mydir, to_path)
990
991
992 - def handlePackage(self, pkg_data, forcedRevision = -1,
993 formattedContent = False):
994 """
995 Update or add a package to repository automatically handling
996 its scope and thus removal of previous versions if requested by
997 the given metadata.
998 pkg_data is a dict() containing all the information bound to
999 a package:
1000
1001 {
1002 'signatures':
1003 {
1004 'sha256': 'zzz',
1005 'sha1': 'zzz',
1006 'sha512': 'zzz'
1007 },
1008 'slot': '0',
1009 'datecreation': '1247681752.93',
1010 'description': 'Standard (de)compression library',
1011 'useflags': set(['kernel_linux']),
1012 'eclasses': set(['multilib']),
1013 'config_protect_mask': 'string string', 'etpapi': 3,
1014 'mirrorlinks': [],
1015 'cxxflags': '-Os -march=x86-64 -pipe',
1016 'injected': False,
1017 'licensedata': {'ZLIB': u"lictext"},
1018 'dependencies': {},
1019 'chost': 'x86_64-pc-linux-gn',
1020 'config_protect': 'string string',
1021 'download': 'packages/amd64/4/sys-libs:zlib-1.2.3-r1.tbz2',
1022 'conflicts': set([]),
1023 'digest': 'fd54248ae060c287b1ec939de3e55332',
1024 'size': '136302',
1025 'category': 'sys-libs',
1026 'license': 'ZLIB',
1027 'sources': set(),
1028 'name': 'zlib',
1029 'versiontag': '',
1030 'changelog': u"text",
1031 'provide': set([]),
1032 'trigger': 'text',
1033 'counter': 22331,
1034 'messages': [],
1035 'branch': '4',
1036 'content': {},
1037 'needed': [('libc.so.6', 2)],
1038 'version': '1.2.3-r1',
1039 'keywords': set(),
1040 'cflags': '-Os -march=x86-64 -pipe',
1041 'disksize': 932206, 'spm_phases': None,
1042 'homepage': 'http://www.zlib.net/',
1043 'systempackage': True,
1044 'revision': 0
1045 }
1046
1047 @param pkg_data: Entropy package metadata dict
1048 @type pkg_data: dict
1049 @keyword forcedRevision: force a specific package revision
1050 @type forcedRevision: int
1051 @keyword formattedContent: tells whether content metadata is already
1052 formatted for insertion
1053 @type formattedContent: bool
1054 @return: tuple composed by
1055 - idpackage: unique Entropy Repository package identifier
1056 - revision: final package revision selected
1057 - pkg_data: new Entropy package metadata dict
1058 @rtype: tuple
1059 """
1060
1061 def remove_conflicting_packages(pkgdata):
1062
1063 manual_deps = set()
1064 removelist = self.retrieve_packages_to_remove(
1065 pkgdata['name'], pkgdata['category'],
1066 pkgdata['slot'], pkgdata['injected']
1067 )
1068
1069 for r_idpackage in removelist:
1070 manual_deps |= self.retrieveManualDependencies(r_idpackage)
1071 self.removePackage(r_idpackage, do_cleanup = False,
1072 do_commit = False)
1073
1074
1075 for manual_dep in manual_deps:
1076 if manual_dep in pkgdata['dependencies']:
1077 continue
1078 pkgdata['dependencies'][manual_dep] = \
1079 etpConst['dependency_type_ids']['mdepend_id']
1080
1081
1082
1083
1084
1085 client_repo = self.get_plugins_metadata().get('client_repo')
1086 if client_repo:
1087 remove_conflicting_packages(pkg_data)
1088 return self.addPackage(pkg_data, revision = forcedRevision,
1089 formatted_content = formattedContent)
1090
1091
1092 pkgatom = self.entropyTools.create_package_atom_string(
1093 pkg_data['category'], pkg_data['name'], pkg_data['version'],
1094 pkg_data['versiontag'])
1095
1096 foundid = self.isAtomAvailable(pkgatom)
1097 if foundid < 0:
1098 remove_conflicting_packages(pkg_data)
1099 return self.addPackage(pkg_data, revision = forcedRevision,
1100 formatted_content = formattedContent)
1101
1102 idpackages = self.getIDPackages(pkgatom)
1103 current_rev = forcedRevision
1104
1105 for idpackage in idpackages:
1106
1107 if forcedRevision == -1:
1108 myrev = self.retrieveRevision(idpackage)
1109 if myrev > current_rev:
1110 current_rev = myrev
1111
1112
1113 self.removePackage(idpackage, do_cleanup = False, do_commit = False)
1114
1115 if forcedRevision == -1:
1116 current_rev += 1
1117
1118
1119 remove_conflicting_packages(pkg_data)
1120 return self.addPackage(pkg_data, revision = current_rev,
1121 formatted_content = formattedContent)
1122
1124 """
1125 Return a list of packages that would be removed given name, category,
1126 slot and injection status.
1127
1128 @param name: package name
1129 @type name: string
1130 @param category: package category
1131 @type category: string
1132 @param slot: package slot
1133 @type slot: string
1134 @param injected: injection status (packages marked as injected are
1135 always considered not automatically removable)
1136 @type injected: bool
1137
1138 @return: list (set) of removable packages (idpackages)
1139 @rtype: set
1140 """
1141
1142 removelist = set()
1143 if injected:
1144
1145
1146
1147 return removelist
1148
1149 searchsimilar = self.searchPackagesByNameAndCategory(
1150 name = name,
1151 category = category,
1152 sensitive = True
1153 )
1154
1155
1156
1157
1158
1159
1160
1161 filter_similar = False
1162 srv_ss_plg = etpConst['system_settings_plugins_ids']['server_plugin']
1163 srv_ss_fs_plg = \
1164 etpConst['system_settings_plugins_ids']['server_plugin_fatscope']
1165
1166 srv_plug_settings = self.SystemSettings.get(srv_ss_plg)
1167 if srv_plug_settings is not None:
1168 if srv_plug_settings['server']['exp_based_scope']:
1169
1170 filter_similar = True
1171
1172 if filter_similar:
1173
1174 idpkgs = self.SystemSettings[srv_ss_fs_plg]['repos'].get(
1175 self.dbname)
1176 if idpkgs:
1177 if -1 in idpkgs:
1178 del searchsimilar[:]
1179 else:
1180 searchsimilar = [x for x in searchsimilar if x[1] \
1181 not in idpkgs]
1182
1183
1184
1185
1186
1187 for atom, idpackage in searchsimilar:
1188
1189 myslot = self.retrieveSlot(idpackage)
1190
1191
1192 if self.isInjected(idpackage):
1193 continue
1194 if slot == myslot:
1195
1196 removelist.add(idpackage)
1197
1198 return removelist
1199
1200 - def addPackage(self, pkg_data, revision = -1, idpackage = None,
1201 do_commit = True, formatted_content = False):
1202 """
1203 Add package to this Entropy repository. The main difference between
1204 handlePackage and this is that from here, no packages are going to be
1205 removed, in any case.
1206 For more information about pkg_data layout, please see
1207 I{handlePackage()}.
1208
1209 @param pkg_data: Entropy package metadata
1210 @type pkg_data: dict
1211 @keyword revision: force a specific Entropy package revision
1212 @type revision: int
1213 @keyword idpackage: add package to Entropy repository using the
1214 provided package identifier, this is very dangerous and could
1215 cause packages with the same identifier to be removed.
1216 @type idpackage: int
1217 @keyword do_commit: if True, automatically commits the executed
1218 transaction (could cause slowness)
1219 @type do_commit: bool
1220 @keyword formatted_content: if True, determines whether the content
1221 metadata (usually the biggest part) in pkg_data is already
1222 prepared for insertion
1223 @type formatted_content: bool
1224 @return: tuple composed by
1225 - idpackage: unique Entropy Repository package identifier
1226 - revision: final package revision selected
1227 - pkg_data: new Entropy package metadata dict
1228 @rtype: tuple
1229 """
1230 if revision == -1:
1231 try:
1232 revision = int(pkg_data['revision'])
1233 except (KeyError, ValueError):
1234 pkg_data['revision'] = 0
1235 revision = 0
1236 elif 'revision' not in pkg_data:
1237 pkg_data['revision'] = revision
1238
1239
1240 catid = self.isCategoryAvailable(pkg_data['category'])
1241 if catid == -1:
1242 catid = self.addCategory(pkg_data['category'])
1243
1244
1245 licid = self.isLicenseAvailable(pkg_data['license'])
1246 if licid == -1:
1247 licid = self.addLicense(pkg_data['license'])
1248
1249 idprotect = self.isProtectAvailable(pkg_data['config_protect'])
1250 if idprotect == -1:
1251 idprotect = self.addProtect(pkg_data['config_protect'])
1252
1253 idprotect_mask = self.isProtectAvailable(
1254 pkg_data['config_protect_mask'])
1255 if idprotect_mask == -1:
1256 idprotect_mask = self.addProtect(pkg_data['config_protect_mask'])
1257
1258 idflags = self.areCompileFlagsAvailable(pkg_data['chost'],
1259 pkg_data['cflags'], pkg_data['cxxflags'])
1260 if idflags == -1:
1261 idflags = self.addCompileFlags(pkg_data['chost'],
1262 pkg_data['cflags'], pkg_data['cxxflags'])
1263
1264 trigger = 0
1265 if pkg_data['trigger']:
1266 trigger = 1
1267
1268
1269 pkgatom = self.entropyTools.create_package_atom_string(
1270 pkg_data['category'], pkg_data['name'], pkg_data['version'],
1271 pkg_data['versiontag'])
1272
1273 pkg_data['atom'] = pkgatom
1274
1275 mybaseinfo_data = (pkgatom, catid, pkg_data['name'],
1276 pkg_data['version'], pkg_data['versiontag'], revision,
1277 pkg_data['branch'], pkg_data['slot'],
1278 licid, pkg_data['etpapi'], trigger,
1279 )
1280
1281 myidpackage_string = 'NULL'
1282 if isinstance(idpackage, int):
1283
1284 manual_deps = self.retrieveManualDependencies(idpackage)
1285
1286
1287 self.removePackage(idpackage, do_cleanup = False,
1288 do_commit = False, from_add_package = True)
1289 myidpackage_string = '?'
1290 mybaseinfo_data = (idpackage,)+mybaseinfo_data
1291
1292
1293 dep_dict = pkg_data['dependencies']
1294 for manual_dep in manual_deps:
1295 if manual_dep in dep_dict:
1296 continue
1297 dep_dict[manual_dep] = \
1298 etpConst['dependency_type_ids']['mdepend_id']
1299
1300 else:
1301
1302 idpackage = None
1303
1304
1305 with self.__write_mutex:
1306
1307 cur = self.cursor.execute("""
1308 INSERT INTO baseinfo VALUES (%s,?,?,?,?,?,?,?,?,?,?,?)""" % (
1309 myidpackage_string,), mybaseinfo_data)
1310 if idpackage is None:
1311 idpackage = cur.lastrowid
1312
1313
1314 self.cursor.execute(
1315 'INSERT INTO extrainfo VALUES (?,?,?,?,?,?,?,?)',
1316 ( idpackage,
1317 pkg_data['description'],
1318 pkg_data['homepage'],
1319 pkg_data['download'],
1320 pkg_data['size'],
1321 idflags,
1322 pkg_data['digest'],
1323 pkg_data['datecreation'],
1324 )
1325 )
1326
1327
1328
1329
1330 self.insertEclasses(idpackage, pkg_data['eclasses'])
1331 self.insertNeeded(idpackage, pkg_data['needed'])
1332 self.insertDependencies(idpackage, pkg_data['dependencies'])
1333 self.insertSources(idpackage, pkg_data['sources'])
1334 self.insertUseflags(idpackage, pkg_data['useflags'])
1335 self.insertKeywords(idpackage, pkg_data['keywords'])
1336 self.insertLicenses(pkg_data['licensedata'])
1337 self.insertMirrors(pkg_data['mirrorlinks'])
1338
1339 if pkg_data.get('changelog'):
1340 self.insertChangelog(pkg_data['category'], pkg_data['name'],
1341 pkg_data['changelog'])
1342
1343 if pkg_data.get('signatures'):
1344 signatures = pkg_data['signatures']
1345 sha1, sha256, sha512 = signatures['sha1'], \
1346 signatures['sha256'], signatures['sha512']
1347 self.insertSignatures(idpackage, sha1, sha256, sha512)
1348
1349 if pkg_data.get('provided_libs'):
1350 self._insertProvidedLibraries(idpackage, pkg_data['provided_libs'])
1351
1352
1353 if pkg_data.get('spm_phases') is not None:
1354 self._insertSpmPhases(idpackage, pkg_data['spm_phases'])
1355
1356 if pkg_data.get('spm_repository') is not None:
1357 self._insertSpmRepository(idpackage, pkg_data['spm_repository'])
1358
1359
1360 self.insertContent(idpackage, pkg_data['content'],
1361 already_formatted = formatted_content)
1362
1363
1364 pkg_data['counter'] = int(pkg_data['counter'])
1365 if not pkg_data['injected'] and (pkg_data['counter'] != -1):
1366 pkg_data['counter'] = self.bindSpmPackageUid(
1367 idpackage, pkg_data['counter'], pkg_data['branch'])
1368
1369 self.insertOnDiskSize(idpackage, pkg_data['disksize'])
1370 if pkg_data['trigger']:
1371 self.insertTrigger(idpackage, pkg_data['trigger'])
1372 self.insertConflicts(idpackage, pkg_data['conflicts'])
1373
1374 if "provide_extended" not in pkg_data:
1375 self.insertProvide(idpackage, pkg_data['provide'])
1376 else:
1377 self.insertProvide(idpackage, pkg_data['provide_extended'])
1378
1379 self.insertMessages(idpackage, pkg_data['messages'])
1380 self.insertConfigProtect(idpackage, idprotect)
1381 self.insertConfigProtect(idpackage, idprotect_mask, mask = True)
1382
1383 if pkg_data.get('injected'):
1384 self.setInjected(idpackage, do_commit = False)
1385
1386 if pkg_data.get('systempackage'):
1387 self.setSystemPackage(idpackage, do_commit = False)
1388
1389 self.clearCache()
1390 if do_commit:
1391 self.commitChanges()
1392
1393 plugins = self.get_plugins()
1394 for plugin_id in sorted(plugins):
1395 plug_inst = plugins[plugin_id]
1396 exec_rc = plug_inst.add_package_hook(self, idpackage, pkg_data)
1397 if exec_rc:
1398 raise RepositoryPluginError(
1399 "[add_package_hook] %s: status: %s" % (
1400 plug_inst.get_id(), exec_rc,))
1401
1402 return idpackage, revision, pkg_data
1403
1404 - def removePackage(self, idpackage, do_cleanup = True, do_commit = True,
1405 from_add_package = False):
1406 """
1407 Remove package from this Entropy repository using it's identifier
1408 (idpackage).
1409
1410 @param idpackage: Entropy repository package indentifier
1411 @type idpackage: int
1412 @keyword do_cleanup: if True, executes repository metadata cleanup
1413 at the end
1414 @type do_cleanup: bool
1415 @keyword do_commit: if True, commits the transaction (could cause
1416 slowness)
1417 @type do_commit: bool
1418 @keyword from_add_package: inform function that it's being called from
1419 inside addPackage().
1420 @type from_add_package: bool
1421 """
1422
1423 self.clearCache()
1424
1425 plugins = self.get_plugins()
1426 for plugin_id in sorted(plugins):
1427 plug_inst = plugins[plugin_id]
1428 exec_rc = plug_inst.remove_package_hook(self, idpackage,
1429 from_add_package)
1430 if exec_rc:
1431 raise RepositoryPluginError(
1432 "[remove_package_hook] %s: status: %s" % (
1433 plug_inst.get_id(), exec_rc,))
1434
1435 with self.__write_mutex:
1436
1437 try:
1438 new_way = self.getSetting("on_delete_cascade")
1439 except KeyError:
1440 new_way = ''
1441
1442 if new_way:
1443
1444 self.cursor.execute(
1445 "DELETE FROM baseinfo WHERE idpackage = (?)", (idpackage,))
1446 else:
1447 r_tup = (idpackage,)*20
1448 self.cursor.executescript("""
1449 DELETE FROM baseinfo WHERE idpackage = %d;
1450 DELETE FROM extrainfo WHERE idpackage = %d;
1451 DELETE FROM dependencies WHERE idpackage = %d;
1452 DELETE FROM provide WHERE idpackage = %d;
1453 DELETE FROM conflicts WHERE idpackage = %d;
1454 DELETE FROM configprotect WHERE idpackage = %d;
1455 DELETE FROM configprotectmask WHERE idpackage = %d;
1456 DELETE FROM sources WHERE idpackage = %d;
1457 DELETE FROM useflags WHERE idpackage = %d;
1458 DELETE FROM keywords WHERE idpackage = %d;
1459 DELETE FROM content WHERE idpackage = %d;
1460 DELETE FROM messages WHERE idpackage = %d;
1461 DELETE FROM counters WHERE idpackage = %d;
1462 DELETE FROM sizes WHERE idpackage = %d;
1463 DELETE FROM eclasses WHERE idpackage = %d;
1464 DELETE FROM needed WHERE idpackage = %d;
1465 DELETE FROM triggers WHERE idpackage = %d;
1466 DELETE FROM systempackages WHERE idpackage = %d;
1467 DELETE FROM injected WHERE idpackage = %d;
1468 DELETE FROM installedtable WHERE idpackage = %d;
1469 """ % r_tup)
1470
1471 if do_cleanup:
1472
1473 self.doCleanups()
1474
1475 if do_commit:
1476 self.commitChanges()
1477
1479 """
1480 Remove source packages mirror entries from database for the given
1481 mirror name. This is a representation of Portage's "thirdpartymirrors".
1482
1483 @param mirrorname: mirror name
1484 @type mirrorname: string
1485 """
1486 with self.__write_mutex:
1487 self.cursor.execute("""
1488 DELETE FROM mirrorlinks WHERE mirrorname = (?)
1489 """, (mirrorname,))
1490
1492 """
1493 Add source package mirror entry to database.
1494 This is a representation of Portage's "thirdpartymirrors".
1495
1496 @param mirrorname: name of the mirror from which "mirrorlist" belongs
1497 @type mirrorname: string
1498 @param mirrorlist: list of URLs belonging to the given mirror name
1499 @type mirrorlist: list
1500 """
1501 with self.__write_mutex:
1502 self.cursor.executemany("""
1503 INSERT into mirrorlinks VALUES (?,?)
1504 """, [(mirrorname, x,) for x in mirrorlist])
1505
1507 """
1508 Add package category string to repository. Return its identifier
1509 (idcategory).
1510
1511 @param category: name of the category to add
1512 @type category: string
1513 @return: category identifier (idcategory)
1514 @rtype: int
1515 """
1516 with self.__write_mutex:
1517 cur = self.cursor.execute("""
1518 INSERT into categories VALUES (NULL,?)
1519 """, (category,))
1520 return cur.lastrowid
1521
1523 """
1524 Add a single, generic CONFIG_PROTECT (not defined as _MASK/whatever
1525 here) path. Return its identifier (idprotect).
1526
1527 @param protect: CONFIG_PROTECT path to add
1528 @type protect: string
1529 @return: protect identifier (idprotect)
1530 @rtype: int
1531 """
1532 with self.__write_mutex:
1533 cur = self.cursor.execute("""
1534 INSERT into configprotectreference VALUES (NULL,?)
1535 """, (protect,))
1536 return cur.lastrowid
1537
1539 """
1540 Add source code package download path to repository. Return its
1541 identifier (idsource).
1542
1543 @param source: source package download path
1544 @type source: string
1545 @return: source identifier (idprotect)
1546 @rtype: int
1547 """
1548 with self.__write_mutex:
1549 cur = self.cursor.execute("""
1550 INSERT into sourcesreference VALUES (NULL,?)
1551 """, (source,))
1552 return cur.lastrowid
1553
1555 """
1556 Add dependency string to repository. Return its identifier
1557 (iddependency).
1558
1559 @param dependency: dependency string
1560 @type dependency: string
1561 @return: dependency identifier (iddependency)
1562 @rtype: int
1563 """
1564 with self.__write_mutex:
1565 cur = self.cursor.execute("""
1566 INSERT into dependenciesreference VALUES (NULL,?)
1567 """, (dependency,))
1568 return cur.lastrowid
1569
1571 """
1572 Add package SPM keyword string to repository.
1573 Return its identifier (idkeyword).
1574
1575 @param keyword: keyword string
1576 @type keyword: string
1577 @return: keyword identifier (idkeyword)
1578 @rtype: int
1579 """
1580 with self.__write_mutex:
1581 cur = self.cursor.execute("""
1582 INSERT into keywordsreference VALUES (NULL,?)
1583 """, (keyword,))
1584 return cur.lastrowid
1585
1587 """
1588 Add package USE flag string to repository.
1589 Return its identifier (iduseflag).
1590
1591 @param useflag: useflag string
1592 @type useflag: string
1593 @return: useflag identifier (iduseflag)
1594 @rtype: int
1595 """
1596 with self.__write_mutex:
1597 cur = self.cursor.execute("""
1598 INSERT into useflagsreference VALUES (NULL,?)
1599 """, (useflag,))
1600 return cur.lastrowid
1601
1603 """
1604 Add package SPM Eclass string to repository.
1605 Return its identifier (ideclass).
1606
1607 @param eclass: eclass string
1608 @type eclass: string
1609 @return: eclass identifier (ideclass)
1610 @rtype: int
1611 """
1612 with self.__write_mutex:
1613 cur = self.cursor.execute("""
1614 INSERT into eclassesreference VALUES (NULL,?)
1615 """, (eclass,))
1616 return cur.lastrowid
1617
1619 """
1620 Add package libraries' ELF object NEEDED string to repository.
1621 Return its identifier (idneeded).
1622
1623 @param needed: NEEDED string (as shown in `readelf -d elf.so`)
1624 @type needed: string
1625 @return: needed identifier (idneeded)
1626 @rtype: int
1627 """
1628 with self.__write_mutex:
1629 cur = self.cursor.execute("""
1630 INSERT into neededreference VALUES (NULL,?)
1631 """, (needed,))
1632 return cur.lastrowid
1633
1635 """
1636 Add package license name string to repository.
1637 Return its identifier (idlicense).
1638
1639 @param pkglicense: license name string
1640 @type pkglicense: string
1641 @return: license name identifier (idlicense)
1642 @rtype: int
1643 """
1644 if not self.entropyTools.is_valid_string(pkglicense):
1645 pkglicense = ' '
1646 with self.__write_mutex:
1647 cur = self.cursor.execute("""
1648 INSERT into licenses VALUES (NULL,?)
1649 """, (pkglicense,))
1650 return cur.lastrowid
1651
1653 """
1654 Add package Compiler flags used to repository.
1655 Return its identifier (idflags).
1656
1657 @param chost: CHOST string
1658 @type chost: string
1659 @param cflags: CFLAGS string
1660 @type cflags: string
1661 @param cxxflags: CXXFLAGS string
1662 @type cxxflags: string
1663 @return: Compiler flags triple identifier (idflags)
1664 @rtype: int
1665 """
1666 with self.__write_mutex:
1667 cur = self.cursor.execute("""
1668 INSERT into flags VALUES (NULL,?,?,?)
1669 """, (chost, cflags, cxxflags,))
1670 return cur.lastrowid
1671
1673 """
1674 Mark a package as system package, which means that entropy.client
1675 will deny its removal.
1676
1677 @param idpackage: package identifier
1678 @type idpackage: int
1679 @keyword do_commit: determine whether executing commit or not
1680 @type do_commit: bool
1681 """
1682 with self.__write_mutex:
1683 self.cursor.execute("""
1684 INSERT into systempackages VALUES (?)
1685 """, (idpackage,))
1686 if do_commit:
1687 self.commitChanges()
1688
1690 """
1691 Mark package as injected, injection is usually set for packages
1692 manually added to repository. Injected packages are not removed
1693 automatically even when featuring conflicting scope with other
1694 that are being added. If a package is injected, it means that
1695 maintainers have to handle it manually.
1696
1697 @param idpackage: package indentifier
1698 @type idpackage: int
1699 @keyword do_commit: determine whether executing commit or not
1700 @type do_commit: bool
1701 """
1702 with self.__write_mutex:
1703 if not self.isInjected(idpackage):
1704 self.cursor.execute("""
1705 INSERT into injected VALUES (?)
1706 """, (idpackage,))
1707 if do_commit:
1708 self.commitChanges()
1709
1711 """
1712 Update the creation date for package. Creation date is stored in
1713 string based unix time format.
1714
1715 @param idpackage: package indentifier
1716 @type idpackage: int
1717 @param date: unix time in string form
1718 @type date: string
1719 """
1720 with self.__write_mutex:
1721 self.cursor.execute("""
1722 UPDATE extrainfo SET datecreation = (?) WHERE idpackage = (?)
1723 """, (str(date), idpackage,))
1724 self.commitChanges()
1725
1727 """
1728 Set package file md5sum for package. This information is used
1729 by entropy.client when downloading packages.
1730
1731 @param idpackage: package indentifier
1732 @type idpackage: int
1733 @param digest: md5 hash for package file
1734 @type digest: string
1735 """
1736 with self.__write_mutex:
1737 self.cursor.execute("""
1738 UPDATE extrainfo SET digest = (?) WHERE idpackage = (?)
1739 """, (digest, idpackage,))
1740 self.commitChanges()
1741
1743 """
1744 Set package file extra hashes (sha1, sha256, sha512) for package.
1745
1746 @param idpackage: package indentifier
1747 @type idpackage: int
1748 @param sha1: SHA1 hash for package file
1749 @type sha1: string
1750 @param sha256: SHA256 hash for package file
1751 @type sha256: string
1752 @param sha512: SHA512 hash for package file
1753 @type sha512: string
1754 """
1755 with self.__write_mutex:
1756 self.cursor.execute("""
1757 UPDATE packagesignatures SET sha1 = (?), sha256 = (?), sha512 = (?)
1758 WHERE idpackage = (?)
1759 """, (sha1, sha256, sha512, idpackage))
1760
1762 """
1763 Set download URL prefix for package.
1764
1765 @param idpackage: package indentifier
1766 @type idpackage: int
1767 @param url: URL prefix to set
1768 @type url: string
1769 """
1770 with self.__write_mutex:
1771 self.cursor.execute("""
1772 UPDATE extrainfo SET download = (?) WHERE idpackage = (?)
1773 """, (url, idpackage,))
1774 self.commitChanges()
1775
1777 """
1778 Set category name for package.
1779
1780 @param idpackage: package indentifier
1781 @type idpackage: int
1782 @param category: category to set
1783 @type category: string
1784 """
1785
1786 catid = self.isCategoryAvailable(category)
1787 if catid == -1:
1788
1789 catid = self.addCategory(category)
1790
1791 with self.__write_mutex:
1792 self.cursor.execute("""
1793 UPDATE baseinfo SET idcategory = (?) WHERE idpackage = (?)
1794 """, (catid, idpackage,))
1795 self.commitChanges()
1796
1798 """
1799 Set description for given category name.
1800
1801 @param category: category name
1802 @type category: string
1803 @param description_data: category description for several locales.
1804 {'en': "This is blah", 'it': "Questo e' blah", ... }
1805 @type description_data: dict
1806 """
1807 with self.__write_mutex:
1808
1809 self.cursor.execute("""
1810 DELETE FROM categoriesdescription WHERE category = (?)
1811 """, (category,))
1812 for locale in description_data:
1813 mydesc = description_data[locale]
1814 self.cursor.execute("""
1815 INSERT INTO categoriesdescription VALUES (?,?,?)
1816 """, (category, locale, mydesc,))
1817
1818 self.commitChanges()
1819
1820 - def setName(self, idpackage, name):
1821 """
1822 Set name for package.
1823
1824 @param idpackage: package indentifier
1825 @type idpackage: int
1826 @param name: package name
1827 @type name: string
1828
1829 """
1830 with self.__write_mutex:
1831 self.cursor.execute("""
1832 UPDATE baseinfo SET name = (?) WHERE idpackage = (?)
1833 """, (name, idpackage,))
1834 self.commitChanges()
1835
1837 """
1838 Set dependency string for iddependency (dependency identifier).
1839
1840 @param iddependency: dependency string identifier
1841 @type iddependency: int
1842 @param dependency: dependency string
1843 @type dependency: string
1844 """
1845 with self.__write_mutex:
1846 self.cursor.execute("""
1847 UPDATE dependenciesreference SET dependency = (?)
1848 WHERE iddependency = (?)
1849 """, (dependency, iddependency,))
1850 self.commitChanges()
1851
1852 - def setAtom(self, idpackage, atom):
1853 """
1854 Set atom string for package. "Atom" is the full, unique name of
1855 a package.
1856
1857 @param idpackage: package indentifier
1858 @type idpackage: int
1859 @param atom: atom string
1860 @type atom: string
1861 """
1862 with self.__write_mutex:
1863 self.cursor.execute("""
1864 UPDATE baseinfo SET atom = (?) WHERE idpackage = (?)
1865 """, (atom, idpackage,))
1866 self.commitChanges()
1867
1868 - def setSlot(self, idpackage, slot):
1869 """
1870 Set slot string for package. Please refer to Portage SLOT documentation
1871 for more info.
1872
1873 @param idpackage: package indentifier
1874 @type idpackage: int
1875 @param slot: slot string
1876 @type slot: string
1877 """
1878 with self.__write_mutex:
1879 self.cursor.execute("""
1880 UPDATE baseinfo SET slot = (?) WHERE idpackage = (?)
1881 """, (slot, idpackage,))
1882 self.commitChanges()
1883
1885 """
1886 Set Entropy revision for package.
1887
1888 @param idpackage: package indentifier
1889 @type idpackage: int
1890 @param revision: new revision
1891 @type revision: int
1892 """
1893 with self.__write_mutex:
1894 self.cursor.execute("""
1895 UPDATE baseinfo SET revision = (?) WHERE idpackage = (?)
1896 """, (revision, idpackage,))
1897 self.commitChanges()
1898
1900 """
1901 Remove license text for given license name identifier.
1902
1903 @param license_name: available license name identifier
1904 @type license_name: string
1905 """
1906 with self.__write_mutex:
1907 self.cursor.execute("""
1908 DELETE FROM licensedata WHERE licensename = (?)
1909 """, (license_name,))
1910
1912 """
1913 Remove all the dependencies of package.
1914
1915 @param idpackage: package indentifier
1916 @type idpackage: int
1917 """
1918 with self.__write_mutex:
1919 self.cursor.execute("""
1920 DELETE FROM dependencies WHERE idpackage = (?)
1921 """, (idpackage,))
1922 self.commitChanges()
1923
1925 """
1926 Insert dependencies for package. "depdata" is a dict() with dependency
1927 strings as keys and dependency type as values.
1928
1929 @param idpackage: package indentifier
1930 @type idpackage: int
1931 @param depdata: dependency dictionary
1932 {'app-foo/foo': dep_type_integer, ...}
1933 @type depdata: dict
1934 """
1935
1936 dcache = set()
1937 add_dep = self.addDependency
1938 is_dep_avail = self.isDependencyAvailable
1939 def mymf(dep):
1940
1941 if dep in dcache:
1942 return 0
1943 iddep = is_dep_avail(dep)
1944 if iddep == -1:
1945 iddep = add_dep(dep)
1946
1947 deptype = 0
1948 if isinstance(depdata, dict):
1949 deptype = depdata[dep]
1950
1951 dcache.add(dep)
1952 return (idpackage, iddep, deptype,)
1953
1954 deps = [x for x in map(mymf, depdata) if not isinstance(x, int)]
1955 with self.__write_mutex:
1956 self.cursor.executemany("""
1957 INSERT into dependencies VALUES (?,?,?)
1958 """, deps)
1959
1961 """
1962 Insert manually added dependencies to dep. list of package.
1963
1964 @param idpackage: package indentifier
1965 @type idpackage: int
1966 @param manual_deps: list of dependency strings
1967 @type manual_deps: list
1968 """
1969 mydict = {}
1970 for manual_dep in manual_deps:
1971 mydict[manual_dep] = etpConst['dependency_type_ids']['mdepend_id']
1972 return self.insertDependencies(idpackage, mydict)
1973
1974 - def removeContent(self, idpackage):
1975 """
1976 Remove content metadata for package.
1977
1978 @param idpackage: package indentifier
1979 @type idpackage: int
1980 """
1981 with self.__write_mutex:
1982 self.cursor.execute("DELETE FROM content WHERE idpackage = (?)", (idpackage,))
1983 self.commitChanges()
1984
1985 - def insertContent(self, idpackage, content, already_formatted = False):
1986 """
1987 Insert content metadata for package. "content" can either be a dict()
1988 or a list of triples (tuples of length 3, (idpackage, path, type,)).
1989
1990 @param idpackage: package indentifier
1991 @type idpackage: int
1992 @param content: content metadata to insert.
1993 {'/path/to/foo': 'obj(content type)',}
1994 or
1995 [(idpackage, path, type,) ...]
1996 @type content: dict, list
1997 @keyword already_formatted: if True, "content" is expected to be
1998 already formatted for insertion, this means that "content" must be
1999 a list of tuples of length 3.
2000 @type already_formatted: bool
2001 """
2002
2003 with self.__write_mutex:
2004
2005 if already_formatted:
2006 self.cursor.executemany("""
2007 INSERT INTO content VALUES (?,?,?)
2008 """, [(idpackage, x, y,) for a, x, y in content])
2009 else:
2010 self.cursor.executemany("""
2011 INSERT INTO content VALUES (?,?,?)
2012 """, [(idpackage, x, content[x],) for x in content])
2013
2015 """
2016 Insert library metadata owned by package.
2017
2018 @param idpackage: package indentifier
2019 @type idpackage: int
2020 @param libs_metadata: provided library metadata composed by list of
2021 tuples of length 3 containing library name, path and ELF class.
2022 @type libs_metadata: list
2023 """
2024
2025 if not self._doesTableExist('provided_libs'):
2026 self._createProvidedLibs()
2027
2028 with self.__write_mutex:
2029 self.cursor.executemany("""
2030 INSERT INTO provided_libs VALUES (?,?,?,?)
2031 """, [(idpackage, x, y, z,) for x, y, z in libs_metadata])
2032
2034 """
2035 Insert configuration files automerge information for package.
2036 "automerge_data" contains configuration files paths and their belonging
2037 md5 hash.
2038 This features allows entropy.client to "auto-merge" or "auto-remove"
2039 configuration files never touched by user.
2040
2041 @param idpackage: package indentifier
2042 @type idpackage: int
2043 @param automerge_data: list of tuples of length 2.
2044 [('/path/to/conf/file', 'md5_checksum_string',) ... ]
2045 @type automerge_data: list
2046 """
2047 with self.__write_mutex:
2048 self.cursor.executemany('INSERT INTO automergefiles VALUES (?,?,?)',
2049 [(idpackage, x, y,) for x, y in automerge_data])
2050
2052 """
2053 Insert package changelog for package (in this case using category +
2054 name as key).
2055
2056 @param category: package category
2057 @type category: string
2058 @param name: package name
2059 @type name: string
2060 @param changelog_txt: changelog text
2061 @type changelog_txt: string
2062 """
2063 with self.__write_mutex:
2064
2065 mytxt = changelog_txt.encode('raw_unicode_escape')
2066
2067 self.cursor.execute("""
2068 DELETE FROM packagechangelogs WHERE category = (?) AND name = (?)
2069 """, (category, name,))
2070
2071 self.cursor.execute("""
2072 INSERT INTO packagechangelogs VALUES (?,?,?)
2073 """, (category, name, const_get_buffer()(mytxt),))
2074
2076 """
2077 insert license data (license names and text) into repository.
2078
2079 @param licenses_data: dictionary containing license names as keys and
2080 text as values
2081 @type licenses_data: dict
2082 """
2083
2084 mylicenses = list(licenses_data.keys())
2085 def my_mf(mylicense):
2086 return not self.isLicensedataKeyAvailable(mylicense)
2087
2088 def my_mm(mylicense):
2089
2090 lic_data = licenses_data.get(mylicense, '')
2091
2092
2093 if const_isunicode(lic_data):
2094 try:
2095 lic_data = lic_data.encode('raw_unicode_escape')
2096 except (UnicodeDecodeError,):
2097 lic_data = lic_data.encode('utf-8')
2098
2099 return (mylicense, const_get_buffer()(lic_data), 0,)
2100
2101 with self.__write_mutex:
2102
2103 self.cursor.executemany("""
2104 INSERT into licensedata VALUES (?,?,?)
2105 """, list(map(my_mm, set(filter(my_mf, mylicenses)))))
2106
2108 """
2109 Insert CONFIG_PROTECT (configuration files protection) entry identifier
2110 for package. This entry is usually a space separated string of directory
2111 and files which are used to handle user-protected configuration files
2112 or directories, those that are going to be stashed in separate paths
2113 waiting for user merge decisions.
2114
2115 @param idpackage: package indentifier
2116 @type idpackage: int
2117 @param idprotect: configuration files protection identifier
2118 @type idprotect: int
2119 @keyword mask: if True, idproctect will be considered a "mask" entry,
2120 meaning that configuration files starting with paths referenced
2121 by idprotect will be forcefully merged.
2122 @type mask: bool
2123 """
2124
2125 mytable = 'configprotect'
2126 if mask:
2127 mytable += 'mask'
2128 with self.__write_mutex:
2129 self.cursor.execute("""
2130 INSERT into %s VALUES (?,?)
2131 """ % (mytable,), (idpackage, idprotect,))
2132
2134 """
2135 Insert list of "mirror name" and "mirror list" into repository.
2136 The term "mirror" in this case references to Source Package Manager
2137 package download mirrors.
2138 Argument format is like this for historical reasons and may change in
2139 future.
2140
2141 @todo: change argument format
2142 @param mirrors: list of tuples of length 2 containing string as first
2143 item and list as second.
2144 [('openoffice', ['http://openoffice1', 'http://..."],), ...]
2145 @type mirrors: list
2146 """
2147
2148 for mirrorname, mirrorlist in mirrors:
2149
2150 self.removeMirrorEntries(mirrorname)
2151
2152 self.addMirrors(mirrorname, mirrorlist)
2153
2155 """
2156 Insert keywords for package. Keywords are strings contained in package
2157 metadata stating what architectures or subarchitectures are supported
2158 by package. It is historically used also for masking packages (making
2159 them not available).
2160
2161 @param idpackage: package indentifier
2162 @type idpackage: int
2163 @param keywords: list of keywords
2164 @type keywords: list
2165 """
2166
2167 def mymf(key):
2168 idkeyword = self.isKeywordAvailable(key)
2169 if idkeyword == -1:
2170
2171 idkeyword = self.addKeyword(key)
2172 return (idpackage, idkeyword,)
2173
2174 with self.__write_mutex:
2175 self.cursor.executemany("""
2176 INSERT into keywords VALUES (?,?)
2177 """, list(map(mymf, keywords)))
2178
2180 """
2181 Insert Source Package Manager USE (components build) flags for package.
2182
2183 @param idpackage: package indentifier
2184 @type idpackage: int
2185 @param useflags: list of use flags strings
2186 @type useflags: list
2187 """
2188
2189 def mymf(flag):
2190 iduseflag = self.isUseflagAvailable(flag)
2191 if iduseflag == -1:
2192
2193 iduseflag = self.addUseflag(flag)
2194 return (idpackage, iduseflag,)
2195
2196 with self.__write_mutex:
2197 self.cursor.executemany("""
2198 INSERT into useflags VALUES (?,?)
2199 """, list(map(mymf, useflags)))
2200
2202 """
2203 Insert package file extra hashes (sha1, sha256, sha512) for package.
2204
2205 @param idpackage: package indentifier
2206 @type idpackage: int
2207 @param sha1: SHA1 hash for package file
2208 @type sha1: string
2209 @param sha256: SHA256 hash for package file
2210 @type sha256: string
2211 @param sha512: SHA512 hash for package file
2212 @type sha512: string
2213 """
2214 with self.__write_mutex:
2215 self.cursor.execute("""
2216 INSERT INTO packagesignatures VALUES (?,?,?,?)
2217 """, (idpackage, sha1, sha256, sha512))
2218
2220 """
2221 Insert Source Package Manager phases for package.
2222 Entropy can call several Source Package Manager (the PM which Entropy
2223 relies on) package installation/removal phases.
2224 Such phase names are listed here.
2225
2226 @param idpackage: package indentifier
2227 @type idpackage: int
2228 @param phases: list of available Source Package Manager phases
2229 @type phases: list
2230 """
2231 with self.__write_mutex:
2232 self.cursor.execute("""
2233 INSERT INTO packagespmphases VALUES (?,?)
2234 """, (idpackage, phases,))
2235
2237 """
2238 Insert Source Package Manager repository for package.
2239 This medatatum describes the source repository where package has
2240 been compiled from.
2241
2242 @param idpackage: package indentifier
2243 @type idpackage: int
2244 @param repository: Source Package Manager repository
2245 @type repository: string
2246 """
2247 with self.__write_mutex:
2248 self.cursor.execute("""
2249 INSERT INTO packagespmrepository VALUES (?,?)
2250 """, (idpackage, repository,))
2251
2253 """
2254 Insert source code package download URLs for idpackage.
2255
2256 @param idpackage: package indentifier
2257 @type idpackage: int
2258 @param sources: list of source URLs
2259 @type sources: list
2260 """
2261 def mymf(source):
2262
2263 if (not source) or \
2264 (not self.entropyTools.is_valid_string(source)):
2265 return 0
2266
2267 idsource = self.isSourceAvailable(source)
2268 if idsource == -1:
2269 idsource = self.addSource(source)
2270
2271 return (idpackage, idsource,)
2272
2273 with self.__write_mutex:
2274 self.cursor.executemany("""
2275 INSERT into sources VALUES (?,?)
2276 """, [x for x in map(mymf, sources) if x != 0])
2277
2279 """
2280 Insert dependency conflicts for package.
2281
2282 @param idpackage: package indentifier
2283 @type idpackage: int
2284 @param conflicts: list of dep. conflicts
2285 @type conflicts: list
2286 """
2287 with self.__write_mutex:
2288 self.cursor.executemany("""
2289 INSERT into conflicts VALUES (?,?)
2290 """, [(idpackage, x,) for x in conflicts])
2291
2293 """
2294 Insert user messages for package.
2295
2296 @param idpackage: package indentifier
2297 @type idpackage: int
2298 @param messages: list of messages
2299 @type messages: list
2300 """
2301 with self.__write_mutex:
2302 self.cursor.executemany("""
2303 INSERT into messages VALUES (?,?)
2304 """, [(idpackage, x,) for x in messages])
2305
2307 """
2308 Insert PROVIDE metadata for idpackage.
2309 This has been added for supporting Portage Source Package Manager
2310 old-style meta-packages support.
2311 Packages can provide extra atoms, you can see it like aliases, where
2312 these can be given by multiple packages. This allowed to make available
2313 multiple applications providing the same functionality which depending
2314 packages can reference, without forcefully being bound to a single
2315 package.
2316
2317 @param idpackage: package indentifier
2318 @type idpackage: int
2319 @param provides: list of atom strings
2320 @type provides: list
2321 """
2322
2323
2324 my_provides = set()
2325 for prov in provides:
2326 if not isinstance(prov, tuple):
2327 my_provides.add((prov, 0,))
2328 else:
2329 my_provides.add(prov)
2330
2331 default_provides = [x for x in my_provides if x[1]]
2332
2333 with self.__write_mutex:
2334
2335 self.cursor.executemany("""
2336 INSERT into provide VALUES (?,?,?)
2337 """, [(idpackage, x, y,) for x, y in my_provides])
2338
2339 if default_provides:
2340
2341 self.cursor.executemany("""
2342 UPDATE provide SET is_default=0 WHERE atom = (?) AND
2343 idpackage != (?)
2344 """, default_provides)
2345
2347 """
2348 Insert package libraries' ELF object NEEDED string for package.
2349 Return its identifier (idneeded).
2350
2351 @param idpackage: package indentifier
2352 @type idpackage: int
2353 @param neededs: list of NEEDED string (as shown in `readelf -d elf.so`)
2354 @type neededs: string
2355 """
2356 def mymf(needed_data):
2357 needed, elfclass = needed_data
2358 idneeded = self.isNeededAvailable(needed)
2359 if idneeded == -1:
2360
2361 idneeded = self.addNeeded(needed)
2362 return (idpackage, idneeded, elfclass,)
2363
2364 with self.__write_mutex:
2365 self.cursor.executemany("""
2366 INSERT into needed VALUES (?,?,?)
2367 """, list(map(mymf, neededs)))
2368
2370 """
2371 Insert Source Package Manager used build specification file classes.
2372 The term "eclasses" is derived from Portage.
2373
2374 @param idpackage: package indentifier
2375 @type idpackage: int
2376 @param eclasses: list of classes
2377 @type eclasses: list
2378 """
2379
2380 def mymf(eclass):
2381 idclass = self.isEclassAvailable(eclass)
2382 if idclass == -1:
2383 idclass = self.addEclass(eclass)
2384 return (idpackage, idclass,)
2385
2386 with self.__write_mutex:
2387 self.cursor.executemany("""
2388 INSERT into eclasses VALUES (?,?)
2389 """, list(map(mymf, eclasses)))
2390
2392 """
2393 Insert on-disk size (bytes) for package.
2394
2395 @param idpackage: package indentifier
2396 @type idpackage: int
2397 @param mysize: package size (bytes)
2398 @type mysize: int
2399 """
2400 with self.__write_mutex:
2401 self.cursor.execute("""
2402 INSERT into sizes VALUES (?,?)
2403 """, (idpackage, mysize,))
2404
2406 """
2407 Insert built-in trigger script for package, containing
2408 pre-install, post-install, pre-remove, post-remove hooks.
2409 This feature should be considered DEPRECATED, and kept for convenience.
2410 Please use Source Package Manager features if possible.
2411
2412 @param idpackage: package indentifier
2413 @type idpackage: int
2414 @param trigger: trigger file dump
2415 @type trigger: string
2416 """
2417 with self.__write_mutex:
2418 self.cursor.execute("""
2419 INSERT into triggers VALUES (?,?)
2420 """, (idpackage, const_get_buffer()(trigger),))
2421
2422 - def insertBranchMigration(self, repository, from_branch, to_branch,
2423 post_migration_md5sum, post_upgrade_md5sum):
2424 """
2425 Insert Entropy Client "branch migration" scripts hash metadata.
2426 When upgrading from a branch to another, it can happen that repositories
2427 ship with scripts aiming to ease the upgrade.
2428 This method stores in the repository information on such scripts.
2429
2430 @param repository: repository identifier
2431 @type repository: string
2432 @param from_branch: original branch
2433 @type from_branch: string
2434 @param to_branch: destination branch
2435 @type to_branch: string
2436 @param post_migration_md5sum: md5 hash related to "post-migration"
2437 branch script file
2438 @type post_migration_md5sum: string
2439 @param post_upgrade_md5sum: md5 hash related to "post-upgrade on new
2440 branch" script file
2441 @type post_upgrade_md5sum: string
2442 """
2443 with self.__write_mutex:
2444 self.cursor.execute("""
2445 INSERT OR REPLACE INTO entropy_branch_migration VALUES (?,?,?,?,?)
2446 """, (
2447 repository, from_branch,
2448 to_branch, post_migration_md5sum,
2449 post_upgrade_md5sum,
2450 )
2451 )
2452
2453 - def setBranchMigrationPostUpgradeMd5sum(self, repository, from_branch,
2454 to_branch, post_upgrade_md5sum):
2455 """
2456 Update "post-upgrade on new branch" script file md5 hash.
2457 When upgrading from a branch to another, it can happen that repositories
2458 ship with scripts aiming to ease the upgrade.
2459 This method stores in the repository information on such scripts.
2460
2461 @param repository: repository identifier
2462 @type repository: string
2463 @param from_branch: original branch
2464 @type from_branch: string
2465 @param to_branch: destination branch
2466 @type to_branch: string
2467 @param post_upgrade_md5sum: md5 hash related to "post-upgrade on new
2468 branch" script file
2469 @type post_upgrade_md5sum: string
2470 """
2471 with self.__write_mutex:
2472 self.cursor.execute("""
2473 UPDATE entropy_branch_migration SET post_upgrade_md5sum = (?) WHERE
2474 repository = (?) AND from_branch = (?) AND to_branch = (?)
2475 """, (post_upgrade_md5sum, repository, from_branch, to_branch,))
2476
2477
2479 """
2480 Bind Source Package Manager package identifier ("COUNTER" metadata
2481 for Portage) to Entropy package.
2482 If uid <= -2, a new negative UID will be allocated and returned.
2483 Negative UIDs are considered auto-allocated by Entropy.
2484 This is mainly used for binary packages not belonging to any SPM
2485 packages which are just "injected" inside the repository.
2486
2487 @param idpackage: package indentifier
2488 @type idpackage: int
2489 @param spm_package_uid: Source package Manager unique package identifier
2490 @type spm_package_uid: int
2491 @param branch: current running Entropy branch
2492 @type branch: string
2493 @return: uid set
2494 @rtype: int
2495 """
2496
2497 my_uid = spm_package_uid
2498
2499 if my_uid <= -2:
2500
2501 my_uid = self.getNewNegativeSpmUid()
2502
2503 with self.__write_mutex:
2504 try:
2505 self.cursor.execute('INSERT into counters VALUES (?,?,?)',
2506 (my_uid, idpackage, branch,))
2507 except self.dbapi2.IntegrityError:
2508
2509 self._migrateCountersTable()
2510 self.cursor.execute('INSERT into counters VALUES (?,?,?)',
2511 (my_uid, idpackage, branch,))
2512
2513 return my_uid
2514
2515 - def insertSpmUid(self, idpackage, spm_package_uid, branch = None):
2516 """
2517 Insert Source Package Manager unique package identifier and bind it
2518 to Entropy package identifier given (idpackage). This method is used
2519 by Entropy Client and differs from "bindSpmPackageUid" because
2520 any other colliding idpackage<->uid binding is overwritten by design.
2521
2522 @param idpackage: package indentifier
2523 @type idpackage: int
2524 @param spm_package_uid: Source package Manager unique package identifier
2525 @type spm_package_uid: int
2526 @param branch: current running Entropy branch
2527 @type branch: string
2528 """
2529 if not branch:
2530 branch = self.db_branch
2531 if not branch:
2532 branch = self.SystemSettings['repositories']['branch']
2533
2534 with self.__write_mutex:
2535
2536 self.cursor.execute("""
2537 DELETE FROM counters WHERE (counter = (?) OR
2538 idpackage = (?)) AND branch = (?);
2539 """, (spm_package_uid, idpackage, branch,))
2540 self.cursor.execute("""
2541 INSERT INTO counters VALUES (?,?,?);
2542 """, (spm_package_uid, idpackage, branch,))
2543
2544 self.commitChanges()
2545
2547 """
2548 Mark given Source Package Manager unique package identifier as
2549 "trashed". This is a trick to allow Entropy Server to support
2550 multiple repositories and parallel handling of them without
2551 make it messing with removed packages from the underlying system.
2552
2553 @param spm_package_uid: Source package Manager unique package identifier
2554 @type spm_package_uid: int
2555 """
2556 with self.__write_mutex:
2557 self.cursor.execute("""
2558 INSERT OR REPLACE INTO trashedcounters VALUES (?)
2559 """, (spm_package_uid,))
2560
2561 - def setSpmUid(self, idpackage, spm_package_uid, branch = None):
2562 """
2563 Update Source Package Manager unique package identifier for given
2564 Entropy package identifier (idpackage).
2565 This method *only* updates a currently available binding setting a new
2566 "spm_package_uid"
2567
2568 @param idpackage: package indentifier
2569 @type idpackage: int
2570 @param spm_package_uid: Source package Manager unique package identifier
2571 @type spm_package_uid: int
2572 @keyword branch: current Entropy repository branch
2573 @type branch: string
2574 """
2575 branchstring = ''
2576 insertdata = [spm_package_uid, idpackage]
2577 if branch:
2578 branchstring = ', branch = (?)'
2579 insertdata.insert(1, branch)
2580
2581 with self.__write_mutex:
2582 try:
2583 self.cursor.execute("""
2584 UPDATE counters SET counter = (?) %s
2585 WHERE idpackage = (?)""" % (branchstring,), insertdata)
2586 except self.dbapi2.Error:
2587 if self.dbname == etpConst['clientdbid']:
2588 raise
2589 self.commitChanges()
2590
2591 - def contentDiff(self, idpackage, dbconn, dbconn_idpackage):
2592 """
2593 Return content metadata difference between two packages.
2594
2595 @param idpackage: package indentifier available in this repository
2596 @type idpackage: int
2597 @param dbconn: other repository class instance
2598 @type dbconn: EntropyRepository
2599 @param dbconn_idpackage: package identifier available in other
2600 repository
2601 @type dbconn_idpackage: int
2602 @return: content difference
2603 @rtype: set
2604 @raise AttributeError: when self instance and dbconn are the same
2605 """
2606
2607 if self is dbconn:
2608 raise AttributeError("cannot diff inside the same db")
2609
2610 self.connection.text_factory = lambda x: const_convert_to_unicode(x)
2611
2612
2613 randomtable = "cdiff%s" % (self.entropyTools.get_random_number(),)
2614 while self._doesTableExist(randomtable):
2615 randomtable = "cdiff%s" % (self.entropyTools.get_random_number(),)
2616
2617
2618 self.cursor.execute("""
2619 CREATE TEMPORARY TABLE %s ( file VARCHAR )""" % (randomtable,)
2620 )
2621
2622 try:
2623 dbconn.connection.text_factory = lambda x: \
2624 const_convert_to_unicode(x)
2625
2626 cur = dbconn.cursor.execute("""
2627 SELECT file FROM content WHERE idpackage = (?)
2628 """, (dbconn_idpackage,))
2629 self.cursor.executemany("""
2630 INSERT INTO %s VALUES (?)""" % (randomtable,), cur)
2631
2632
2633 cur = self.cursor.execute("""
2634 SELECT file FROM content
2635 WHERE content.idpackage = (?) AND
2636 content.file NOT IN (SELECT file from %s)""" % (randomtable,),
2637 (idpackage,))
2638
2639
2640 return self._cur2set(cur)
2641
2642 finally:
2643 self.cursor.execute('DROP TABLE IF EXISTS %s' % (randomtable,))
2644
2655
2657 """
2658 Cleanup "USE flags" metadata unused references to save space.
2659 """
2660 with self.__write_mutex:
2661 self.cursor.execute("""
2662 DELETE FROM useflagsreference
2663 WHERE idflag NOT IN (SELECT idflag FROM useflags)""")
2664
2666 """
2667 Cleanup "sources" metadata unused references to save space.
2668 """
2669 with self.__write_mutex:
2670 self.cursor.execute("""
2671 DELETE FROM sourcesreference
2672 WHERE idsource NOT IN (SELECT idsource FROM sources)""")
2673
2675 """
2676 Cleanup "eclass" metadata unused references to save space.
2677 """
2678 with self.__write_mutex:
2679 self.cursor.execute("""
2680 DELETE FROM eclassesreference
2681 WHERE idclass NOT IN (SELECT idclass FROM eclasses)""")
2682
2684 """
2685 Cleanup "needed" metadata unused references to save space.
2686 """
2687 with self.__write_mutex:
2688 self.cursor.execute("""
2689 DELETE FROM neededreference
2690 WHERE idneeded NOT IN (SELECT idneeded FROM needed)""")
2691
2693 """
2694 Cleanup "dependencies" metadata unused references to save space.
2695 """
2696 with self.__write_mutex:
2697 self.cursor.execute("""
2698 DELETE FROM dependenciesreference
2699 WHERE iddependency NOT IN (SELECT iddependency FROM dependencies)
2700 """)
2701
2703 """
2704 Cleanup "changelog" metadata unused references to save space.
2705 """
2706 with self.__write_mutex:
2707 self.cursor.execute("""
2708 DELETE FROM packagechangelogs
2709 WHERE category || "/" || name NOT IN
2710 (SELECT categories.category || "/" || baseinfo.name
2711 FROM baseinfo, categories
2712 WHERE baseinfo.idcategory = categories.idcategory)
2713 """)
2714
2716 """
2717 Obtain auto-generated available negative Source Package Manager
2718 package identifier.
2719
2720 @return: new negative spm uid
2721 @rtype: int
2722 """
2723 try:
2724 cur = self.cursor.execute('SELECT min(counter) FROM counters')
2725 dbcounter = cur.fetchone()
2726 mycounter = 0
2727 if dbcounter:
2728 mycounter = dbcounter[0]
2729
2730 if mycounter >= -1 or mycounter is None:
2731 counter = -2
2732 else:
2733 counter = mycounter-1
2734
2735 except self.dbapi2.Error:
2736 counter = -2
2737
2738 return counter
2739
2741 """
2742 Get Entropy repository API.
2743
2744 @return: Entropy repository API
2745 @rtype: int
2746 """
2747 cur = self.cursor.execute('SELECT max(etpapi) FROM baseinfo')
2748 api = cur.fetchone()
2749 if api:
2750 return api[0]
2751 return -1
2752
2754 """
2755 Return dependency string for given dependency identifier.
2756
2757 @param iddependency: dependency identifier
2758 @type iddependency: int
2759 @return: dependency string
2760 @rtype: string or None
2761 """
2762 cur = self.cursor.execute("""
2763 SELECT dependency FROM dependenciesreference WHERE iddependency = (?)
2764 LIMIT 1
2765 """, (iddependency,))
2766 dep = cur.fetchone()
2767 if dep:
2768 return dep[0]
2769
2771 """
2772 Get category name from category identifier.
2773
2774 @param idcategory: category identifier
2775 @type idcategory: int
2776 @return: category name
2777 @rtype: string
2778 """
2779 cur = self.cursor.execute("""
2780 SELECT category from categories WHERE idcategory = (?) LIMIT 1
2781 """, (idcategory,))
2782 cat = cur.fetchone()
2783 if cat:
2784 return cat[0]
2785 return cat
2786
2788 """
2789 Obtain a list of system packages on this repository.
2790
2791 @return: list (set) of system package identifiers
2792 @rtype: set
2793 """
2794 cur = self.cursor.execute("SELECT idpackage FROM systempackages")
2795 return self._cur2set(cur)
2796
2798 """
2799 Obtain repository package identifiers from atom string.
2800
2801 @param atom: package atom
2802 @type atom: string
2803 @return: list of matching idpackages found
2804 @rtype: set
2805 """
2806 cur = self.cursor.execute("""
2807 SELECT idpackage FROM baseinfo WHERE atom = (?)
2808 """, (atom,))
2809 return self._cur2set(cur)
2810
2813 """
2814 Obtain repository package identifier from its relative download path
2815 string.
2816
2817 @param download_relative_path: relative download path string returned
2818 by "retrieveDownloadURL" method
2819 @type download_relative_path: string
2820 @keyword endswith: search for idpackage which download metadata ends
2821 with the one provided by download_relative_path
2822 @type endswith: bool
2823 @return: idpackage in repository or -1 if not found
2824 @rtype: int
2825 """
2826 if endswith:
2827 cur = self.cursor.execute("""
2828 SELECT baseinfo.idpackage FROM baseinfo,extrainfo
2829 WHERE extrainfo.download LIKE (?) AND
2830 baseinfo.idpackage = extrainfo.idpackage
2831 LIMIT 1
2832 """, ("%"+download_relative_path,))
2833 else:
2834 cur = self.cursor.execute("""
2835 SELECT baseinfo.idpackage FROM baseinfo,extrainfo
2836 WHERE extrainfo.download = (?) AND
2837 baseinfo.idpackage = extrainfo.idpackage
2838 LIMIT 1
2839 """, (download_relative_path,))
2840
2841 idpackage = cur.fetchone()
2842 if idpackage:
2843 return idpackage[0]
2844 return -1
2845
2847 """
2848 Obtain repository package identifiers for packages owning the provided
2849 path string (file).
2850
2851 @param file: path to file (or directory) to match
2852 @type file: string
2853 @return: list (set) of idpackages found
2854 @rtype: set
2855 """
2856 cur = self.cursor.execute("""
2857 SELECT idpackage FROM content WHERE file = (?)
2858 """, (file,))
2859 return self._cur2list(cur)
2860
2862 """
2863 Obtain category identifier from category name.
2864
2865 @param category: category name
2866 @type category: string
2867 @return: idcategory or -1 if not found
2868 @rtype: int
2869 """
2870 cur = self.cursor.execute("""
2871 SELECT "idcategory" FROM categories WHERE category = (?)
2872 LIMIT 1
2873 """, (category,))
2874 idcat = cur.fetchone()
2875 if idcat:
2876 return idcat[0]
2877 return -1
2878
2880 """
2881 Get package version information for provided package identifier.
2882
2883 @param idpackage: package indentifier
2884 @type idpackage: int
2885 @return: tuple of length 3 composed by (version, tag, revision,)
2886 belonging to idpackage
2887 @rtype: tuple
2888 """
2889 cur = self.cursor.execute("""
2890 SELECT version, versiontag, revision FROM baseinfo WHERE idpackage = (?)
2891 LIMIT 1
2892 """, (idpackage,))
2893 return cur.fetchone()
2894
2896 """
2897 Get a restricted (optimized) set of package metadata for provided
2898 package identifier.
2899
2900 @param idpackage: package indentifier
2901 @type idpackage: int
2902 @return: tuple of length 6 composed by
2903 (package key, slot, version, tag, revision, atom)
2904 belonging to idpackage
2905 @rtype: tuple
2906 """
2907 self.cursor.execute("""
2908 SELECT categories.category || "/" || baseinfo.name,
2909 baseinfo.slot,baseinfo.version,baseinfo.versiontag,
2910 baseinfo.revision,baseinfo.atom FROM baseinfo, categories
2911 WHERE baseinfo.idpackage = (?) AND
2912 baseinfo.idcategory = categories.idcategory""", (idpackage,))
2913 return self.cursor.fetchone()
2914
2916 """
2917 Get a restricted (optimized) set of package metadata for provided
2918 identifier that can be used to determine the scope of package.
2919
2920 @param idpackage: package indentifier
2921 @type idpackage: int
2922 @return: tuple of length 3 composed by (atom, slot, revision,)
2923 belonging to idpackage
2924 @rtype: tuple
2925 """
2926 self.cursor.execute("""
2927 SELECT atom, slot, revision FROM baseinfo
2928 WHERE idpackage = (?)""", (idpackage,))
2929 rslt = self.cursor.fetchone()
2930 return rslt
2931
2933 """
2934 Get a set of package metadata for provided identifier that can be
2935 used to determine the scope of package.
2936
2937 @param idpackage: package indentifier
2938 @type idpackage: int
2939 @return: tuple of length 9 composed by
2940 (atom, category name, name, version,
2941 slot, tag, revision, branch, api,)
2942 belonging to idpackage
2943 @rtype: tuple
2944 """
2945 self.cursor.execute("""
2946 SELECT
2947 baseinfo.atom,
2948 categories.category,
2949 baseinfo.name,
2950 baseinfo.version,
2951 baseinfo.slot,
2952 baseinfo.versiontag,
2953 baseinfo.revision,
2954 baseinfo.branch,
2955 baseinfo.etpapi
2956 FROM
2957 baseinfo,
2958 categories
2959 WHERE
2960 baseinfo.idpackage = (?)
2961 and baseinfo.idcategory = categories.idcategory
2962 """, (idpackage,))
2963 return self.cursor.fetchone()
2964
2966 """
2967 Get a set of basic package metadata for provided package identifier.
2968
2969 @param idpackage: package indentifier
2970 @type idpackage: int
2971 @return: tuple of length 19 composed by
2972 (atom, name, version, tag, description, category name, CHOST,
2973 CFLAGS, CXXFLAGS, homepage, license, branch, download path, digest,
2974 slot, api, creation date, package size, revision,)
2975 belonging to idpackage
2976 @rtype: tuple
2977 """
2978 sql = """
2979 SELECT
2980 baseinfo.atom,
2981 baseinfo.name,
2982 baseinfo.version,
2983 baseinfo.versiontag,
2984 extrainfo.description,
2985 categories.category,
2986 flags.chost,
2987 flags.cflags,
2988 flags.cxxflags,
2989 extrainfo.homepage,
2990 licenses.license,
2991 baseinfo.branch,
2992 extrainfo.download,
2993 extrainfo.digest,
2994 baseinfo.slot,
2995 baseinfo.etpapi,
2996 extrainfo.datecreation,
2997 extrainfo.size,
2998 baseinfo.revision
2999 FROM
3000 baseinfo,
3001 extrainfo,
3002 categories,
3003 flags,
3004 licenses
3005 WHERE
3006 baseinfo.idpackage = (?)
3007 and baseinfo.idpackage = extrainfo.idpackage
3008 and baseinfo.idcategory = categories.idcategory
3009 and extrainfo.idflags = flags.idflags
3010 and baseinfo.idlicense = licenses.idlicense
3011 """
3012 self.cursor.execute(sql, (idpackage,))
3013 return self.cursor.fetchone()
3014
3016 """
3017 Get a set of basic package metadata for provided package identifier.
3018 This method is optimized to work with Entropy Client installation
3019 triggers returning only what is strictly needed.
3020
3021 @param idpackage: package indentifier
3022 @type idpackage: int
3023 @keyword content: if True, grabs the "content" metadata too, othewise
3024 such dict key value will be shown as empty set().
3025 @type content: bool
3026 @return: dictionary containing package metadata
3027
3028 data = {
3029 'atom': atom,
3030 'category': category,
3031 'name': name,
3032 'version': version,
3033 'versiontag': versiontag,
3034 'revision': revision,
3035 'branch': branch,
3036 'chost': chost,
3037 'cflags': cflags,
3038 'cxxflags': cxxflags,
3039 'etpapi': etpapi,
3040 'trigger': self.retrieveTrigger(idpackage),
3041 'eclasses': self.retrieveEclasses(idpackage),
3042 'content': pkg_content,
3043 'spm_phases': self.retrieveSpmPhases(idpackage),
3044 }
3045
3046 @rtype: dict
3047 """
3048
3049 atom, category, name, \
3050 version, slot, versiontag, \
3051 revision, branch, etpapi = self.getScopeData(idpackage)
3052 chost, cflags, cxxflags = self.retrieveCompileFlags(idpackage)
3053
3054 pkg_content = set()
3055 if content:
3056 pkg_content = self.retrieveContent(idpackage)
3057
3058 data = {
3059 'atom': atom,
3060 'category': category,
3061 'name': name,
3062 'version': version,
3063 'versiontag': versiontag,
3064 'revision': revision,
3065 'branch': branch,
3066 'chost': chost,
3067 'cflags': cflags,
3068 'cxxflags': cxxflags,
3069 'etpapi': etpapi,
3070 'trigger': self.retrieveTrigger(idpackage),
3071 'eclasses': self.retrieveEclasses(idpackage),
3072 'content': pkg_content,
3073 'spm_phases': self.retrieveSpmPhases(idpackage),
3074 }
3075 return data
3076
3077 - def getPackageData(self, idpackage, get_content = True,
3078 content_insert_formatted = False, trigger_unicode = False):
3079 """
3080 Reconstruct all the package metadata belonging to provided package
3081 identifier into a dict object.
3082
3083 @param idpackage: package indentifier
3084 @type idpackage: int
3085 @keyword get_content:
3086 @type get_content: bool
3087 @keyword content_insert_formatted:
3088 @type content_insert_formatted: bool
3089 @keyword trigger_unicode:
3090 @type trigger_unicode: bool
3091 @return: package metadata in dict() form
3092
3093 >>> data = {
3094 'atom': atom,
3095 'name': name,
3096 'version': version,
3097 'versiontag':versiontag,
3098 'description': description,
3099 'category': category,
3100 'chost': chost,
3101 'cflags': cflags,
3102 'cxxflags': cxxflags,
3103 'homepage': homepage,
3104 'license': mylicense,
3105 'branch': branch,
3106 'download': download,
3107 'digest': digest,
3108 'slot': slot,
3109 'etpapi': etpapi,
3110 'datecreation': datecreation,
3111 'size': size,
3112 'revision': revision,
3113 'counter': self.retrieveSpmUid(idpackage),
3114 'messages': self.retrieveMessages(idpackage),
3115 'trigger': self.retrieveTrigger(idpackage,
3116 get_unicode = trigger_unicode),
3117 'disksize': self.retrieveOnDiskSize(idpackage),
3118 'changelog': self.retrieveChangelog(idpackage),
3119 'injected': self.isInjected(idpackage),
3120 'systempackage': self.isSystemPackage(idpackage),
3121 'config_protect': self.retrieveProtect(idpackage),
3122 'config_protect_mask': self.retrieveProtectMask(idpackage),
3123 'useflags': self.retrieveUseflags(idpackage),
3124 'keywords': self.retrieveKeywords(idpackage),
3125 'sources': sources,
3126 'eclasses': self.retrieveEclasses(idpackage),
3127 'needed': self.retrieveNeeded(idpackage, extended = True),
3128 'provided_libs': self.retrieveProvidedLibraries(idpackage),
3129 'provide': provide (the old provide metadata version)
3130 'provide_extended': self.retrieveProvide(idpackage),
3131 'conflicts': self.retrieveConflicts(idpackage),
3132 'licensedata': self.retrieveLicensedata(idpackage),
3133 'content': content,
3134 'dependencies': dict((x, y,) for x, y in \
3135 self.retrieveDependencies(idpackage, extended = True)),
3136 'mirrorlinks': [[x,self.retrieveMirrorInfo(x)] for x in mirrornames],
3137 'signatures': signatures,
3138 'spm_phases': self.retrieveSpmPhases(idpackage),
3139 'spm_repository': self.retrieveSpmRepository(idpackage),
3140 }
3141
3142 @rtype: dict
3143 """
3144
3145 data = {}
3146 try:
3147 atom, name, version, versiontag, \
3148 description, category, chost, \
3149 cflags, cxxflags, homepage, \
3150 mylicense, branch, download, \
3151 digest, slot, etpapi, \
3152 datecreation, size, revision = self.getBaseData(idpackage)
3153 except TypeError:
3154 return None
3155
3156 content = {}
3157 if get_content:
3158 content = self.retrieveContent(
3159 idpackage, extended = True,
3160 formatted = True, insert_formatted = content_insert_formatted
3161 )
3162
3163 sources = self.retrieveSources(idpackage)
3164 mirrornames = set()
3165 for x in sources:
3166 if x.startswith("mirror://"):
3167 mirrornames.add(x.split("/")[2])
3168
3169 sha1, sha256, sha512 = self.retrieveSignatures(idpackage)
3170 signatures = {
3171 'sha1': sha1,
3172 'sha256': sha256,
3173 'sha512': sha512,
3174 }
3175
3176 provide_extended = self.retrieveProvide(idpackage)
3177
3178 old_provide = set()
3179 for x in provide_extended:
3180 if isinstance(x, tuple):
3181 old_provide.add(x[0])
3182 else:
3183 old_provide.add(x)
3184
3185 data = {
3186 'atom': atom,
3187 'name': name,
3188 'version': version,
3189 'versiontag': versiontag,
3190 'description': description,
3191 'category': category,
3192 'chost': chost,
3193 'cflags': cflags,
3194 'cxxflags': cxxflags,
3195 'homepage': homepage,
3196 'license': mylicense,
3197 'branch': branch,
3198 'download': download,
3199 'digest': digest,
3200 'slot': slot,
3201 'etpapi': etpapi,
3202 'datecreation': datecreation,
3203 'size': size,
3204 'revision': revision,
3205
3206 'counter': self.retrieveSpmUid(idpackage),
3207 'messages': self.retrieveMessages(idpackage),
3208 'trigger': self.retrieveTrigger(idpackage,
3209 get_unicode = trigger_unicode),
3210 'disksize': self.retrieveOnDiskSize(idpackage),
3211 'changelog': self.retrieveChangelog(idpackage),
3212 'injected': self.isInjected(idpackage),
3213 'systempackage': self.isSystemPackage(idpackage),
3214 'config_protect': self.retrieveProtect(idpackage),
3215 'config_protect_mask': self.retrieveProtectMask(idpackage),
3216 'useflags': self.retrieveUseflags(idpackage),
3217 'keywords': self.retrieveKeywords(idpackage),
3218 'sources': sources,
3219 'eclasses': self.retrieveEclasses(idpackage),
3220 'needed': self.retrieveNeeded(idpackage, extended = True),
3221 'provided_libs': self.retrieveProvidedLibraries(idpackage),
3222 'provide': old_provide,
3223 'provide_extended': provide_extended,
3224 'conflicts': self.retrieveConflicts(idpackage),
3225 'licensedata': self.retrieveLicensedata(idpackage),
3226 'content': content,
3227 'dependencies': dict((x, y,) for x, y in \
3228 self.retrieveDependencies(idpackage, extended = True)),
3229 'mirrorlinks': [[x, self.retrieveMirrorInfo(x)] for x in mirrornames],
3230 'signatures': signatures,
3231 'spm_phases': self.retrieveSpmPhases(idpackage),
3232 'spm_repository': self.retrieveSpmRepository(idpackage),
3233 }
3234
3235 return data
3236
3238 mycontent = set()
3239 for x in cur:
3240 mycontent |= set(x)
3241 return mycontent
3242
3244 mycontent = set()
3245 for x in item:
3246 mycontent |= set(x)
3247 return mycontent
3248
3250 content = []
3251 for x in item:
3252 content += x
3253 return content
3254
3256 content = []
3257 for x in cur:
3258 content += x
3259 return content
3260
3262 """
3263 Clear on-disk repository cache.
3264
3265 @keyword depends: if True, clear reverse dependencies cache
3266 @type depends: bool
3267 """
3268
3269 plugins = self.get_plugins()
3270 for plugin_id in sorted(plugins):
3271 plug_inst = plugins[plugin_id]
3272 exec_rc = plug_inst.clear_cache_hook(self)
3273 if exec_rc:
3274 raise RepositoryPluginError(
3275 "[clear_cache_hook] %s: status: %s" % (
3276 plug_inst.get_id(), exec_rc,))
3277
3278 self.live_cache.clear()
3279 def do_clear(name):
3280 """
3281 docstring_title
3282
3283 @param name:
3284 @type name:
3285 @return:
3286 @rtype:
3287
3288 """
3289 dump_path = os.path.join(etpConst['dumpstoragedir'], name)
3290 dump_dir = os.path.dirname(dump_path)
3291 if os.path.isdir(dump_dir):
3292 for item in os.listdir(dump_dir):
3293 try:
3294 os.remove(os.path.join(dump_dir, item))
3295 except OSError:
3296 pass
3297
3298 do_clear("%s/%s/" % (self.dbMatchCacheKey, self.dbname,))
3299 if depends:
3300 do_clear(etpCache['depends_tree'])
3301 do_clear(etpCache['dep_tree'])
3302 do_clear(etpCache['filter_satisfied_deps'])
3303
3305 """
3306 This method should be considered internal and not suited for general
3307 audience. Return digest (md5 hash) bound to repository package
3308 names/slots updates.
3309
3310 @param repository: repository identifier
3311 @type repository: string
3312 @return: digest string
3313 @rtype: string
3314 """
3315 cur = self.cursor.execute("""
3316 SELECT digest FROM treeupdates WHERE repository = (?) LIMIT 1
3317 """, (repository,))
3318
3319 mydigest = cur.fetchone()
3320 if mydigest:
3321 return mydigest[0]
3322 return -1
3323
3325 """
3326 This method should be considered internal and not suited for general
3327 audience.
3328 List all the available "treeupdates" (package names/slots changes
3329 directives) actions.
3330
3331 @keyword no_ids_repos: if True, it will just return a 3-length tuple
3332 list containing [(command, branch, unix_time,), ...]
3333 @type no_ids_repos: bool
3334 @return: list of tuples
3335 @rtype: list
3336
3337 """
3338 if no_ids_repos:
3339 self.cursor.execute("""
3340 SELECT command, branch, date FROM treeupdatesactions
3341 """)
3342 else:
3343 self.cursor.execute('SELECT * FROM treeupdatesactions')
3344 return self.cursor.fetchall()
3345
3347 """
3348 This method should be considered internal and not suited for general
3349 audience.
3350 Return all the available "treeupdates (package names/slots changes
3351 directives) actions for provided repository.
3352
3353 @param repository: repository identifier
3354 @type repository: string
3355 @keyword forbranch: filter for specific Entropy branch, provide
3356 alternative branch string
3357 @type forbranch: string
3358 @return: list of raw-string commands to run
3359 @rtype: list
3360 """
3361 if forbranch is None:
3362 forbranch = self.db_branch
3363 if not forbranch:
3364 forbranch = self.SystemSettings['repositories']['branch']
3365
3366 params = (repository,)
3367 branch_string = ''
3368 if forbranch:
3369 branch_string = 'and branch = (?)'
3370 params = (repository, forbranch,)
3371
3372 self.cursor.execute("""
3373 SELECT command FROM treeupdatesactions WHERE
3374 repository = (?) %s order by date""" % (branch_string,), params)
3375 return self._fetchall2list(self.cursor.fetchall())
3376
3378
3379
3380 """
3381 This method should be considered internal and not suited for general
3382 audience.
3383 This method rewrites "treeupdates" metadata in repository.
3384
3385 @param updates: new treeupdates metadata
3386 @type updates: list
3387 """
3388 with self.__write_mutex:
3389 self.cursor.execute('DELETE FROM treeupdatesactions')
3390 self.cursor.executemany("""
3391 INSERT INTO treeupdatesactions VALUES (?,?,?,?,?)
3392 """, updates)
3393 self.commitChanges()
3394
3396 """
3397 This method should be considered internal and not suited for general
3398 audience.
3399 This method removes "treeupdates" metadata in repository.
3400
3401 @param repository: remove treeupdates metadata for provided repository
3402 @type repository: string
3403 """
3404 with self.__write_mutex:
3405 self.cursor.execute("""
3406 DELETE FROM treeupdatesactions WHERE repository = (?)
3407 """, (repository,))
3408 self.commitChanges()
3409
3411 """
3412 This method should be considered internal and not suited for general
3413 audience.
3414 This method insert "treeupdates" metadata in repository.
3415
3416 @param updates: new treeupdates metadata
3417 @type updates: list
3418 @param repository: insert treeupdates metadata for provided repository
3419 @type repository: string
3420 """
3421 with self.__write_mutex:
3422 myupdates = [[repository]+list(x) for x in updates]
3423 self.cursor.executemany("""
3424 INSERT INTO treeupdatesactions VALUES (NULL,?,?,?,?)
3425 """, myupdates)
3426 self.commitChanges()
3427
3429 """
3430 This method should be considered internal and not suited for general
3431 audience.
3432 Set "treeupdates" checksum (digest) for provided repository.
3433
3434 @param repository: repository identifier
3435 @type repository: string
3436 @param digest: treeupdates checksum string (md5)
3437 @type digest: string
3438 """
3439 with self.__write_mutex:
3440 self.cursor.execute("""
3441 DELETE FROM treeupdates where repository = (?)
3442 """, (repository,))
3443 self.cursor.execute("""
3444 INSERT INTO treeupdates VALUES (?,?)
3445 """, (repository, digest,))
3446
3448 """
3449 This method should be considered internal and not suited for general
3450 audience.
3451 Add "treeupdates" actions for repository and branch provided.
3452
3453 @param repository: repository identifier
3454 @type repository: string
3455 @param actions: list of raw treeupdates action strings
3456 @type actions: list
3457 @param branch: branch metadata to bind to the provided actions
3458 @type branch: string
3459 """
3460
3461 mytime = str(self.entropyTools.get_current_unix_time())
3462 with self.__write_mutex:
3463 myupdates = [
3464 (repository, x, branch, mytime,) for x in actions \
3465 if not self.doesTreeupdatesActionExist(repository, x, branch)
3466 ]
3467 self.cursor.executemany("""
3468 INSERT INTO treeupdatesactions VALUES (NULL,?,?,?,?)
3469 """, myupdates)
3470
3472 """
3473 This method should be considered internal and not suited for general
3474 audience.
3475 Return whether provided "treeupdates" action in repository with
3476 provided branch exists.
3477
3478 @param repository: repository identifier
3479 @type repository: string
3480 @param command: treeupdates command
3481 @type command: string
3482 @param branch: branch metadata bound to command argument value given
3483 @type branch: string
3484 @return: if True, provided treeupdates action already exists
3485 @rtype: bool
3486 """
3487 self.cursor.execute("""
3488 SELECT * FROM treeupdatesactions
3489 WHERE repository = (?) and command = (?)
3490 and branch = (?)""", (repository, command, branch,))
3491
3492 result = self.cursor.fetchone()
3493 if result:
3494 return True
3495 return False
3496
3498 """
3499 Clear Package sets (group of packages) entries in repository.
3500 """
3501 self.cursor.execute('DELETE FROM packagesets')
3502
3504 """
3505 Insert Package sets metadata into repository.
3506
3507 @param sets_data: dictionary containing package set names as keys and
3508 list (set) of dependencies as value
3509 @type sets_data: dict
3510 """
3511 mysets = []
3512 for setname in sorted(sets_data):
3513 for dependency in sorted(sets_data[setname]):
3514 try:
3515 mysets.append((const_convert_to_unicode(setname),
3516 const_convert_to_unicode(dependency),))
3517 except (UnicodeDecodeError, UnicodeEncodeError,):
3518 continue
3519
3520 with self.__write_mutex:
3521 self.cursor.executemany('INSERT INTO packagesets VALUES (?,?)',
3522 mysets)
3523
3525 """
3526 Return Package sets metadata stored in repository.
3527
3528 @return: dictionary containing package set names as keys and
3529 list (set) of dependencies as value
3530 @rtype: dict
3531 """
3532
3533 if not self._doesTableExist('packagesets'):
3534 return {}
3535
3536 cur = self.cursor.execute("SELECT setname, dependency FROM packagesets")
3537 data = cur.fetchall()
3538
3539 sets = {}
3540 for setname, dependency in data:
3541 obj = sets.setdefault(setname, set())
3542 obj.add(dependency)
3543 return sets
3544
3546 """
3547 Return dependencies belonging to given package set name.
3548 This method does not check if the given package set name is
3549 available and returns an empty list (set) in these cases.
3550
3551 @param setname: Package set name
3552 @type setname: string
3553 @return: list (set) of dependencies belonging to given package set name
3554 @rtype: set
3555 """
3556 cur = self.cursor.execute("""
3557 SELECT dependency FROM packagesets WHERE setname = (?)""",
3558 (setname,))
3559 return self._cur2set(cur)
3560
3562 """
3563 Return a list of package identifiers that are part of the base
3564 system (thus, marked as system packages).
3565
3566 @return: list (set) of system package identifiers
3567 @rtype: set
3568 """
3569 cur = self.cursor.execute('SELECT idpackage FROM systempackages')
3570 return self._cur2set(cur)
3571
3573 """
3574 Return "atom" metadatum for given package identifier.
3575
3576 @param idpackage: package indentifier
3577 @type idpackage: int
3578 @return: atom string
3579 @rtype: string or None
3580 """
3581 cur = self.cursor.execute("""
3582 SELECT atom FROM baseinfo WHERE idpackage = (?) LIMIT 1
3583 """, (idpackage,))
3584 atom = cur.fetchone()
3585 if atom:
3586 return atom[0]
3587
3589 """
3590 Return "branch" metadatum for given package identifier.
3591
3592 @param idpackage: package indentifier
3593 @type idpackage: int
3594 @return: branch metadatum
3595 @rtype: string or None
3596 """
3597 cur = self.cursor.execute("""
3598 SELECT branch FROM baseinfo WHERE idpackage = (?) LIMIT 1
3599 """, (idpackage,))
3600 branch = cur.fetchone()
3601 if branch:
3602 return branch[0]
3603
3605 """
3606 Return "trigger" script content for given package identifier.
3607
3608 @param idpackage: package indentifier
3609 @type idpackage: int
3610 @keyword get_unicode: return in unicode format
3611 @type get_unicode: bool
3612 @return: trigger script content
3613 @rtype: string or None
3614 """
3615 cur = self.cursor.execute("""
3616 SELECT data FROM triggers WHERE idpackage = (?) LIMIT 1
3617 """, (idpackage,))
3618 trigger = cur.fetchone()
3619 if not trigger:
3620
3621 if get_unicode:
3622 return const_convert_to_unicode('')
3623 return const_convert_to_rawstring('')
3624 if not get_unicode:
3625 return const_convert_to_rawstring(trigger[0])
3626
3627 return const_convert_to_unicode(trigger[0])
3628
3630 """
3631 Return "download URL" metadatum for given package identifier.
3632
3633 @param idpackage: package indentifier
3634 @type idpackage: int
3635 @return: download url metadatum
3636 @rtype: string or None
3637 """
3638 cur = self.cursor.execute("""
3639 SELECT download FROM extrainfo WHERE idpackage = (?) LIMIT 1
3640 """, (idpackage,))
3641 download = cur.fetchone()
3642 if download:
3643 return download[0]
3644
3646 """
3647 Return "description" metadatum for given package identifier.
3648
3649 @param idpackage: package indentifier
3650 @type idpackage: int
3651 @return: package description
3652 @rtype: string or None
3653 """
3654 cur = self.cursor.execute("""
3655 SELECT description FROM extrainfo WHERE idpackage = (?) LIMIT 1
3656 """, (idpackage,))
3657 description = cur.fetchone()
3658 if description:
3659 return description[0]
3660
3661 - def retrieveHomepage(self, idpackage):
3662 """
3663 Return "homepage" metadatum for given package identifier.
3664
3665 @param idpackage: package indentifier
3666 @type idpackage: int
3667 @return: package homepage
3668 @rtype: string or None
3669 """
3670 cur = self.cursor.execute("""
3671 SELECT homepage FROM extrainfo WHERE idpackage = (?) LIMIT 1
3672 """, (idpackage,))
3673 home = cur.fetchone()
3674 if home:
3675 return home[0]
3676
3678 """
3679 Return Source Package Manager unique identifier bound to Entropy
3680 package identifier.
3681
3682 @param idpackage: package indentifier
3683 @type idpackage: int
3684 @return: Spm UID or -1 (if not bound, valid for injected packages)
3685 @rtype: int
3686 """
3687 cur = self.cursor.execute("""
3688 SELECT counters.counter FROM counters,baseinfo
3689 WHERE counters.idpackage = (?) AND
3690 baseinfo.idpackage = counters.idpackage AND
3691 baseinfo.branch = counters.branch LIMIT 1
3692 """, (idpackage,))
3693 mycounter = cur.fetchone()
3694 if mycounter:
3695 return mycounter[0]
3696 return -1
3697
3699 """
3700 Return "messages" metadatum for given package identifier.
3701
3702 @param idpackage: package indentifier
3703 @type idpackage: int
3704 @return: list of package messages (for making user aware of stuff)
3705 @rtype: list
3706 """
3707 cur = self.cursor.execute("""
3708 SELECT message FROM messages WHERE idpackage = (?)""", (idpackage,))
3709 return self._cur2list(cur)
3710
3712 """
3713 Return "size" metadatum for given package identifier.
3714 "size" refers to Entropy package file size in bytes.
3715
3716 @param idpackage: package indentifier
3717 @type idpackage: int
3718 @return: size of Entropy package for given package identifier
3719 @rtype: int or None
3720 """
3721 cur = self.cursor.execute("""
3722 SELECT size FROM extrainfo WHERE idpackage = (?) LIMIT 1
3723 """, (idpackage,))
3724 size = cur.fetchone()
3725 if size:
3726 try:
3727 return int(size[0])
3728 except ValueError:
3729 return 0
3730
3731
3733 """
3734 Return "on disk size" metadatum for given package identifier.
3735 "on disk size" refers to unpacked Entropy package file size in bytes,
3736 which is in other words, the amount of space required on live system
3737 to have it installed (simplified explanation).
3738
3739 @param idpackage: package indentifier
3740 @type idpackage: int
3741 @return: on disk size metadatum
3742 @rtype: int
3743
3744 """
3745 cur = self.cursor.execute("""
3746 SELECT size FROM sizes WHERE idpackage = (?) LIMIT 1
3747 """, (idpackage,))
3748 size = cur.fetchone()
3749 if size:
3750 return size[0]
3751 return 0
3752
3754 """
3755 Return "digest" metadatum for given package identifier.
3756 "digest" refers to Entropy package file md5 checksum bound to given
3757 package identifier.
3758
3759 @param idpackage: package indentifier
3760 @type idpackage: int
3761 @return: md5 checksum for given package identifier
3762 @rtype: string or None
3763 """
3764 cur = self.cursor.execute("""
3765 SELECT digest FROM extrainfo WHERE idpackage = (?) LIMIT 1
3766 """, (idpackage,))
3767 digest = cur.fetchone()
3768 if digest:
3769 return digest[0]
3770
3772 """
3773 Return package file extra hashes (sha1, sha256, sha512) for given
3774 package identifier.
3775
3776 @param idpackage: package indentifier
3777 @type idpackage: int
3778 @return: tuple of length 3, sha1, sha256, sha512 package extra
3779 hashes if available, otherwise the same but with None as values.
3780 @rtype: tuple
3781 """
3782
3783 if not self._doesTableExist('packagesignatures'):
3784 return None, None, None
3785
3786 cur = self.cursor.execute("""
3787 SELECT sha1, sha256, sha512 FROM packagesignatures
3788 WHERE idpackage = (?) LIMIT 1
3789 """, (idpackage,))
3790 data = cur.fetchone()
3791
3792 if data:
3793 return data
3794 return None, None, None
3795
3797 """
3798 Return "name" metadatum for given package identifier.
3799 Attention: package name != atom, the former is just a subset of the
3800 latter.
3801
3802 @param idpackage: package indentifier
3803 @type idpackage: int
3804 @return: "name" metadatum for given package identifier
3805 @rtype: string or None
3806
3807 """
3808 self.cursor.execute("""
3809 SELECT name FROM baseinfo WHERE idpackage = (?) LIMIT 1
3810 """, (idpackage,))
3811 name = self.cursor.fetchone()
3812 if name:
3813 return name[0]
3814
3816 """
3817 Return a tuple composed by package key and slot for given package
3818 identifier.
3819
3820 @param idpackage: package indentifier
3821 @type idpackage: int
3822 @return: tuple of length 2 composed by (package_key, package_slot,)
3823 @rtupe: tuple or None
3824 """
3825 cur = self.cursor.execute("""
3826 SELECT categories.category || "/" || baseinfo.name,baseinfo.slot
3827 FROM baseinfo,categories
3828 WHERE baseinfo.idpackage = (?) AND
3829 baseinfo.idcategory = categories.idcategory LIMIT 1
3830 """, (idpackage,))
3831 return cur.fetchone()
3832
3834 """
3835 Return package key and package slot string (aggregated form through
3836 ":", for eg.: app-foo/foo:2).
3837 This method has been implemented for performance reasons.
3838
3839 @param idpackage: package indentifier
3840 @type idpackage: int
3841 @return: package key + ":" + slot string
3842 @rtype: string or None
3843 """
3844 cur = self.cursor.execute("""
3845 SELECT categories.category || "/" || baseinfo.name || ":" ||
3846 baseinfo.slot FROM baseinfo,categories
3847 WHERE baseinfo.idpackage = (?) AND
3848 baseinfo.idcategory = categories.idcategory LIMIT 1
3849 """, (idpackage,))
3850 data = cur.fetchone()
3851 if data:
3852 return data[0]
3853
3855 """
3856 Return package key, slot and tag tuple for given package identifier.
3857
3858 @param idpackage: package indentifier
3859 @type idpackage: int
3860 @return: tuple of length 3 providing (package_key, slot, package_tag,)
3861 @rtype: tuple
3862 """
3863 cur = self.cursor.execute("""
3864 SELECT categories.category || "/" || baseinfo.name, baseinfo.slot,
3865 baseinfo.versiontag FROM baseinfo, categories WHERE
3866 baseinfo.idpackage = (?) AND
3867 baseinfo.idcategory = categories.idcategory LIMIT 1
3868 """, (idpackage,))
3869 return cur.fetchone()
3870
3872 """
3873 Return package version for given package identifier.
3874
3875 @param idpackage: package indentifier
3876 @type idpackage: int
3877 @return: package version
3878 @rtype: string or None
3879 """
3880 cur = self.cursor.execute("""
3881 SELECT version FROM baseinfo WHERE idpackage = (?) LIMIT 1
3882 """, (idpackage,))
3883 ver = cur.fetchone()
3884 if ver:
3885 return ver[0]
3886
3888 """
3889 Return package Entropy-revision for given package identifier.
3890
3891 @param idpackage: package indentifier
3892 @type idpackage: int
3893 @return: Entropy-revision for given package indentifier
3894 @rtype: int or None
3895
3896 """
3897 cur = self.cursor.execute("""
3898 SELECT revision FROM baseinfo WHERE idpackage = (?) LIMIT 1
3899 """, (idpackage,))
3900 rev = cur.fetchone()
3901 if rev:
3902 return rev[0]
3903
3905 """
3906 Return creation date for given package identifier.
3907 Creation date returned is a string representation of UNIX time format.
3908
3909 @param idpackage: package indentifier
3910 @type idpackage: int
3911 @return: creation date for given package identifier
3912 @rtype: string or None
3913
3914 """
3915 cur = self.cursor.execute("""
3916 SELECT datecreation FROM extrainfo WHERE idpackage = (?) LIMIT 1
3917 """, (idpackage,))
3918 date = cur.fetchone()
3919 if date:
3920 return date[0]
3921
3923 """
3924 Return Entropy API in use when given package identifier was added.
3925
3926 @param idpackage: package indentifier
3927 @type idpackage: int
3928 @return: Entropy API for given package identifier
3929 @rtype: int or None
3930 """
3931 cur = self.cursor.execute("""
3932 SELECT etpapi FROM baseinfo WHERE idpackage = (?) LIMIT 1
3933 """, (idpackage,))
3934 api = cur.fetchone()
3935 if api:
3936 return api[0]
3937
3939 """
3940 Return "USE flags" metadatum for given package identifier.
3941
3942 @param idpackage: package indentifier
3943 @type idpackage: int
3944 @return: list (set) of USE flags for given package identifier.
3945 @rtype: set
3946 """
3947 cur = self.cursor.execute("""
3948 SELECT flagname FROM useflags,useflagsreference
3949 WHERE useflags.idpackage = (?) AND
3950 useflags.idflag = useflagsreference.idflag
3951 """, (idpackage,))
3952 return self._cur2set(cur)
3953
3955 """
3956 Return "eclass" metadatum for given package identifier.
3957
3958 @param idpackage: package indentifier
3959 @type idpackage: int
3960 @return: list (set) of eclasses for given package identifier
3961 @rtype: set
3962 """
3963 cur = self.cursor.execute("""
3964 SELECT classname FROM eclasses,eclassesreference
3965 WHERE eclasses.idpackage = (?) AND
3966 eclasses.idclass = eclassesreference.idclass""", (idpackage,))
3967 return self._cur2set(cur)
3968
3970 """
3971 Return "Source Package Manager install phases" for given package
3972 identifier.
3973
3974 @param idpackage: package indentifier
3975 @type idpackage: int
3976 @return: "Source Package Manager available install phases" string
3977 @rtype: string or None
3978 """
3979
3980 if not self._doesTableExist('packagespmphases'):
3981 return None
3982
3983 cur = self.cursor.execute("""
3984 SELECT phases FROM packagespmphases WHERE idpackage = (?) LIMIT 1
3985 """, (idpackage,))
3986 spm_phases = cur.fetchone()
3987
3988 if spm_phases:
3989 return spm_phases[0]
3990
3992 """
3993 Return Source Package Manager source repository used at compile time.
3994
3995 @param idpackage: package indentifier
3996 @type idpackage: int
3997 @return: Source Package Manager source repository
3998 @rtype: string or None
3999 """
4000
4001 if not self._doesTableExist('packagespmrepository'):
4002 return None
4003 cur = self.cursor.execute("""
4004 SELECT repository FROM packagespmrepository
4005 WHERE idpackage = (?) LIMIT 1
4006 """, (idpackage,))
4007 spm_repo = cur.fetchone()
4008
4009 if spm_repo:
4010 return spm_repo[0]
4011
4013 """
4014 Return (raw format) "NEEDED" ELF metadata for libraries contained
4015 in given package.
4016
4017 @param idpackage: package indentifier
4018 @type idpackage: int
4019 @return: list (set) of "NEEDED" entries contained in ELF objects
4020 packed into package file
4021 @rtype: set
4022 """
4023 cur = self.cursor.execute("""
4024 SELECT library FROM needed,neededreference
4025 WHERE needed.idpackage = (?) AND
4026 needed.idneeded = neededreference.idneeded""", (idpackage,))
4027 return self._cur2set(cur)
4028
4029 - def retrieveNeeded(self, idpackage, extended = False, format = False):
4030 """
4031 Return "NEEDED" elf metadata for libraries contained in given package.
4032
4033 @param idpackage: package indentifier
4034 @type idpackage: int
4035 @keyword extended: also return ELF class information for every
4036 library name
4037 @type extended: bool
4038 @keyword format: properly format output, returning a dictionary with
4039 library name as key and ELF class as value
4040 @type format: bool
4041 @return: "NEEDED" metadata for libraries contained in given package.
4042 @rtype: list or set
4043 """
4044 if extended:
4045
4046 cur = self.cursor.execute("""
4047 SELECT library,elfclass FROM needed,neededreference
4048 WHERE needed.idpackage = (?) AND
4049 needed.idneeded = neededreference.idneeded order by library
4050 """, (idpackage,))
4051 needed = cur.fetchall()
4052
4053 else:
4054
4055 cur = self.cursor.execute("""
4056 SELECT library FROM needed,neededreference
4057 WHERE needed.idpackage = (?) AND
4058 needed.idneeded = neededreference.idneeded ORDER BY library
4059 """, (idpackage,))
4060 needed = self._cur2list(cur)
4061
4062 if extended and format:
4063 return dict((lib, elfclass,) for lib, elfclass in needed)
4064 return needed
4065
4067 """
4068 Return list of library names (from NEEDED ELF metadata) provided by
4069 given package identifier.
4070
4071 @param idpackage: package indentifier
4072 @type idpackage: int
4073 @return: list of tuples of length 2 composed by library name and ELF
4074 class
4075 @rtype: list
4076 """
4077
4078 if not self._doesTableExist('provided_libs'):
4079 return set()
4080
4081 cur = self.cursor.execute("""
4082 SELECT library, path, elfclass FROM provided_libs
4083 WHERE idpackage = (?)
4084 """, (idpackage,))
4085 return set(cur.fetchall())
4086
4088 """
4089 Return list of conflicting dependencies for given package identifier.
4090
4091 @param idpackage: package indentifier
4092 @type idpackage: int
4093 @return: list (set) of conflicting package dependencies
4094 @rtype: set
4095
4096 """
4097 cur = self.cursor.execute("""
4098 SELECT conflict FROM conflicts WHERE idpackage = (?)
4099 """, (idpackage,))
4100 return self._cur2set(cur)
4101
4103 """
4104 Return list of dependencies/atoms are provided by the given package
4105 identifier (see Portage documentation about old-style PROVIDEs).
4106
4107 @param idpackage: package indentifier
4108 @type idpackage: int
4109 @return: list (set) of atoms provided by package
4110 @rtype: set
4111 """
4112
4113 is_default_str = ',0'
4114 if self._doesColumnInTableExist("provide", "is_default"):
4115 is_default_str = ',is_default '
4116
4117 cur = self.cursor.execute("""
4118 SELECT atom%s FROM provide WHERE idpackage = (?)
4119 """ % (is_default_str,), (idpackage,))
4120 if is_default_str:
4121 return set(cur.fetchall())
4122 return self._cur2set(cur)
4123
4125 """
4126 Return list of dependencies, including conflicts for given package
4127 identifier.
4128
4129 @param idpackage: package indentifier
4130 @type idpackage: int
4131 @return: list (set) of dependencies of package
4132 @rtype: set
4133 """
4134 cur = self.cursor.execute("""
4135 SELECT dependenciesreference.dependency
4136 FROM dependencies, dependenciesreference
4137 WHERE dependencies.idpackage = (?) AND
4138 dependencies.iddependency = dependenciesreference.iddependency
4139 UNION SELECT "!" || conflict FROM conflicts
4140 WHERE idpackage = (?)""", (idpackage, idpackage,))
4141 return self._cur2set(cur)
4142
4143 - def retrievePostDependencies(self, idpackage, extended = False):
4144 """
4145 Return list of post-merge package dependencies for given package
4146 identifier.
4147 Note: this function is just a wrapper of retrieveDependencies()
4148 providing deptype (dependency type) = post-dependencies.
4149
4150 @param idpackage: package indentifier
4151 @type idpackage: int
4152 @keyword extended: return in extended format
4153 @type extended: bool
4154 """
4155 return self.retrieveDependencies(idpackage, extended = extended,
4156 deptype = etpConst['dependency_type_ids']['pdepend_id'])
4157
4159 """
4160 Return manually added dependencies for given package identifier.
4161 Note: this function is just a wrapper of retrieveDependencies()
4162 providing deptype (dependency type) = manual-dependencies.
4163
4164 @param idpackage: package indentifier
4165 @type idpackage: int
4166 @keyword extended: return in extended format
4167 @type extended: bool
4168 """
4169 return self.retrieveDependencies(idpackage, extended = extended,
4170 deptype = etpConst['dependency_type_ids']['mdepend_id'])
4171
4172 - def retrieveDependencies(self, idpackage, extended = False, deptype = None,
4173 exclude_deptypes = None):
4174 """
4175 Return dependencies for given package identifier.
4176
4177 @param idpackage: package indentifier
4178 @type idpackage: int
4179 @keyword extended: return in extended format (list of tuples of length 2
4180 composed by dependency name and dependency type)
4181 @type extended: bool
4182 @keyword deptype: return only given type of dependencies
4183 see etpConst['dependency_type_ids']['*depend_id'] for dependency type
4184 identifiers
4185 @type deptype: bool
4186 @keyword exclude_deptypes: list of dependency types to exclude
4187 @type exclude_deptypes: list
4188 @return: dependencies of given package
4189 @rtype: list or set
4190 """
4191 searchdata = [idpackage]
4192
4193 depstring = ''
4194 if deptype is not None:
4195 depstring = ' and dependencies.type = (?)'
4196 searchdata.append(deptype)
4197
4198 excluded_deptypes_query = ""
4199 if exclude_deptypes is not None:
4200 for dep_type in exclude_deptypes:
4201 if not isinstance(dep_type, int):
4202
4203 continue
4204 excluded_deptypes_query += " AND dependencies.type != %s" % (
4205 dep_type,)
4206
4207 if extended:
4208 cur = self.cursor.execute("""
4209 SELECT dependenciesreference.dependency,dependencies.type
4210 FROM dependencies,dependenciesreference
4211 WHERE dependencies.idpackage = (?) AND
4212 dependencies.iddependency =
4213 dependenciesreference.iddependency %s %s""" % (
4214 depstring, excluded_deptypes_query,), searchdata)
4215 return cur.fetchall()
4216 else:
4217 cur = self.cursor.execute("""
4218 SELECT dependenciesreference.dependency
4219 FROM dependencies,dependenciesreference
4220 WHERE dependencies.idpackage = (?) AND
4221 dependencies.iddependency =
4222 dependenciesreference.iddependency %s %s""" % (
4223 depstring, excluded_deptypes_query,), searchdata)
4224 return self._cur2set(cur)
4225
4227 """
4228 Return list of dependency identifiers for given package identifier.
4229
4230 @param idpackage: package indentifier
4231 @type idpackage: int
4232 @return: list (set) of dependency identifiers
4233 @rtype: set
4234 """
4235 cur = self.cursor.execute("""
4236 SELECT iddependency FROM dependencies WHERE idpackage = (?)
4237 """, (idpackage,))
4238 return self._cur2set(cur)
4239
4241 """
4242 Return package SPM keyword list for given package identifier.
4243
4244 @param idpackage: package indentifier
4245 @type idpackage: int
4246 @return: list (set) of keywords for given package identifier
4247 @rtype: set
4248 """
4249 cur = self.cursor.execute("""
4250 SELECT keywordname FROM keywords,keywordsreference
4251 WHERE keywords.idpackage = (?) AND
4252 keywords.idkeyword = keywordsreference.idkeyword""", (idpackage,))
4253 return self._cur2set(cur)
4254
4256 """
4257 Return CONFIG_PROTECT (configuration file protection) string
4258 (containing a list of space reparated paths) metadata for given
4259 package identifier.
4260
4261 @param idpackage: package indentifier
4262 @type idpackage: int
4263 @return: CONFIG_PROTECT string
4264 @rtype: string
4265 """
4266 cur = self.cursor.execute("""
4267 SELECT protect FROM configprotect,configprotectreference
4268 WHERE configprotect.idpackage = (?) AND
4269 configprotect.idprotect = configprotectreference.idprotect
4270 LIMIT 1
4271 """, (idpackage,))
4272
4273 protect = cur.fetchone()
4274 if protect:
4275 return protect[0]
4276 return ''
4277
4279 """
4280 Return CONFIG_PROTECT_MASK (mask for configuration file protection)
4281 string (containing a list of space reparated paths) metadata for given
4282 package identifier.
4283
4284 @param idpackage: package indentifier
4285 @type idpackage: int
4286 @return: CONFIG_PROTECT_MASK string
4287 @rtype: string
4288 """
4289 self.cursor.execute("""
4290 SELECT protect FROM configprotectmask,configprotectreference
4291 WHERE idpackage = (?) AND
4292 configprotectmask.idprotect = configprotectreference.idprotect
4293 """, (idpackage,))
4294
4295 protect = self.cursor.fetchone()
4296 if protect:
4297 return protect[0]
4298 return ''
4299
4301 """
4302 Return source package URLs for given package identifier.
4303 "source" as in source code.
4304
4305 @param idpackage: package indentifier
4306 @type idpackage: int
4307 @keyword extended:
4308 @type extended: bool
4309 @return: if extended is True, dict composed by source URLs as key
4310 and list of mirrors as value, otherwise just a list (set) of
4311 source package URLs.
4312 @rtype: dict or set
4313 """
4314 cur = self.cursor.execute("""
4315 SELECT sourcesreference.source FROM sources, sourcesreference
4316 WHERE idpackage = (?) AND
4317 sources.idsource = sourcesreference.idsource
4318 """, (idpackage,))
4319 sources = self._cur2set(cur)
4320 if not extended:
4321 return sources
4322
4323 source_data = {}
4324 mirror_str = "mirror://"
4325 for source in sources:
4326
4327 source_data[source] = set()
4328 if source.startswith(mirror_str):
4329
4330 mirrorname = source.split("/")[2]
4331 mirror_url = source.split("/", 3)[3:][0]
4332 source_data[source] |= set(
4333 [os.path.join(url, mirror_url) for url in \
4334 self.retrieveMirrorInfo(mirrorname)])
4335
4336 else:
4337 source_data[source].add(source)
4338
4339 return source_data
4340
4342 """
4343 Return previously merged protected configuration files list and
4344 their md5 hashes for given package identifier.
4345 This is part of the "automerge" feature which uses file md5 checksum
4346 to determine if a protected configuration file can be merged auto-
4347 matically.
4348
4349 @param idpackage: package indentifier
4350 @type idpackage: int
4351 @keyword get_dict: return a dictionary with configuration file as key
4352 and md5 hash as value
4353 @type get_dict: bool
4354 @return: automerge metadata for given package identifier
4355 @rtype: list or set
4356 """
4357
4358 if not self._doesTableExist('automergefiles'):
4359 self._createAutomergefilesTable()
4360
4361
4362 self.connection.text_factory = lambda x: const_convert_to_unicode(x)
4363
4364 cur = self.cursor.execute("""
4365 SELECT configfile, md5 FROM automergefiles WHERE idpackage = (?)
4366 """, (idpackage,))
4367 data = cur.fetchall()
4368
4369 if get_dict:
4370 data = dict(((x, y,) for x, y in data))
4371 return data
4372
4373 - def retrieveContent(self, idpackage, extended = False, contentType = None,
4374 formatted = False, insert_formatted = False, order_by = ''):
4375 """
4376 Return files contained in given package.
4377
4378 @param idpackage: package indentifier
4379 @type idpackage: int
4380 @keyword extended: return in extended format
4381 @type extended: bool
4382 @keyword contentType: only return given entry type, which can be:
4383 "obj", "sym" or "dir"
4384 @type contentType: int
4385 @keyword formatted: return in dict() form
4386 @type formatted: bool
4387 @keyword insert_formatted: return in list of tuples form, ready to
4388 be added with insertContent()
4389 @keyword order_by: order by string, valid values are:
4390 "type" (if extended is True), "file" or "idpackage"
4391 @type order_by: string
4392 @return: content metadata
4393 @rtype: dict or list or set
4394 """
4395 extstring = ''
4396 if extended:
4397 extstring = ",type"
4398 extstring_idpackage = ''
4399 if insert_formatted:
4400 extstring_idpackage = 'idpackage,'
4401
4402 searchkeywords = [idpackage]
4403 contentstring = ''
4404 if contentType:
4405 searchkeywords.append(contentType)
4406 contentstring = ' and type = (?)'
4407
4408 order_by_string = ''
4409 if order_by:
4410 order_by_string = ' order by %s' % (order_by,)
4411
4412 did_try = False
4413 while True:
4414 try:
4415
4416 cur = self.cursor.execute("""
4417 SELECT %s file%s FROM content WHERE idpackage = (?) %s%s""" % (
4418 extstring_idpackage, extstring,
4419 contentstring, order_by_string,),
4420 searchkeywords)
4421
4422 if extended and insert_formatted:
4423 fl = cur.fetchall()
4424
4425 elif extended and formatted:
4426 fl = {}
4427 items = cur.fetchone()
4428 while items:
4429 fl[items[0]] = items[1]
4430 items = cur.fetchone()
4431
4432 elif extended:
4433 fl = cur.fetchall()
4434
4435 else:
4436 if order_by:
4437 fl = self._cur2list(cur)
4438 else:
4439 fl = self._cur2set(cur)
4440
4441 break
4442
4443 except self.dbapi2.OperationalError:
4444
4445 if did_try:
4446 raise
4447 did_try = True
4448
4449
4450
4451 self.connection.text_factory = lambda x: \
4452 const_convert_to_unicode(x)
4453 continue
4454
4455 return fl
4456
4458 """
4459 Return Source Package Manager ChangeLog for given package identifier.
4460
4461 @param idpackage: package indentifier
4462 @type idpackage: int
4463 @return: ChangeLog content
4464 @rtype: string or None
4465 """
4466
4467 if not self._doesTableExist('packagechangelogs'):
4468 return None
4469
4470 cur = self.cursor.execute("""
4471 SELECT packagechangelogs.changelog
4472 FROM packagechangelogs, baseinfo, categories
4473 WHERE baseinfo.idpackage = (?) AND
4474 baseinfo.idcategory = categories.idcategory AND
4475 packagechangelogs.name = baseinfo.name AND
4476 packagechangelogs.category = categories.category
4477 LIMIT 1
4478 """, (idpackage,))
4479 changelog = cur.fetchone()
4480 if changelog:
4481 changelog = changelog[0]
4482 try:
4483 return const_convert_to_unicode(changelog)
4484 except UnicodeDecodeError:
4485 return const_convert_to_unicode(changelog, enctype = 'utf-8')
4486
4488 """
4489 Return Source Package Manager ChangeLog content for given package
4490 category and name.
4491
4492 @param category: package category
4493 @type category: string
4494 @param name: package name
4495 @type name: string
4496 @return: ChangeLog content
4497 @rtype: string or None
4498 """
4499
4500 if not self._doesTableExist('packagechangelogs'):
4501 return None
4502
4503 self.connection.text_factory = lambda x: const_convert_to_unicode(x)
4504
4505 cur = self.cursor.execute("""
4506 SELECT changelog FROM packagechangelogs WHERE category = (?) AND
4507 name = (?) LIMIT 1
4508 """, (category, name,))
4509
4510 changelog = cur.fetchone()
4511 if changelog:
4512 return const_convert_to_unicode(changelog[0])
4513
4515 """
4516 Return "slot" metadatum for given package identifier.
4517
4518 @param idpackage: package indentifier
4519 @type idpackage: int
4520 @return: package slot
4521 @rtype: string or None
4522 """
4523 cur = self.cursor.execute("""
4524 SELECT slot FROM baseinfo WHERE idpackage = (?) LIMIT 1
4525 """, (idpackage,))
4526 slot = cur.fetchone()
4527 if slot:
4528 return slot[0]
4529
4531 """
4532 Return "tag" metadatum for given package identifier.
4533 Tagging packages allows, for example, to support multiple
4534 different, colliding atoms in the same repository and still being
4535 able to exactly reference them. It's actually used to provide
4536 versions of external kernel modules for different kernels.
4537
4538 @param idpackage: package indentifier
4539 @type idpackage: int
4540 @return: tag string
4541 @rtype: string or None
4542 """
4543 cur = self.cursor.execute("""
4544 SELECT versiontag FROM baseinfo WHERE idpackage = (?) LIMIT 1
4545 """, (idpackage,))
4546 vtag = cur.fetchone()
4547 if vtag:
4548 return vtag[0]
4549
4551 """
4552 Return available mirror URls for given mirror name.
4553
4554 @param mirrorname: mirror name (for eg. "openoffice")
4555 @type mirrorname: string
4556 @return: list (set) of URLs providing the "openoffice" mirroring service
4557 @rtype: set
4558 """
4559 cur = self.cursor.execute("""
4560 SELECT mirrorlink FROM mirrorlinks WHERE mirrorname = (?)
4561 """, (mirrorname,))
4562 return self._cur2set(cur)
4563
4565 """
4566 Return category name for given package identifier.
4567
4568 @param idpackage: package indentifier
4569 @type idpackage: int
4570 @return: category where package is in
4571 @rtype: string or None
4572 """
4573 cur = self.cursor.execute("""
4574 SELECT category FROM baseinfo,categories
4575 WHERE baseinfo.idpackage = (?) AND
4576 baseinfo.idcategory = categories.idcategory LIMIT 1
4577 """, (idpackage,))
4578
4579 cat = cur.fetchone()
4580 if cat:
4581 return cat[0]
4582
4584 """
4585 Return description text for given category.
4586
4587 @param category: category name
4588 @type category: string
4589 @return: category description dict, locale as key, description as value
4590 @rtype: dict
4591 """
4592 cur = self.cursor.execute("""
4593 SELECT description, locale FROM categoriesdescription
4594 WHERE category = (?)
4595 """, (category,))
4596
4597 return dict((locale, desc,) for desc, locale in cur.fetchall())
4598
4600 """
4601 Return license metadata for given package identifier.
4602
4603 @param idpackage: package indentifier
4604 @type idpackage: int
4605 @return: dictionary composed by license name as key and license text
4606 as value
4607 @rtype: dict
4608 """
4609
4610 licenses = self.retrieveLicense(idpackage)
4611 if licenses is None:
4612 return {}
4613
4614 licdata = {}
4615 for licname in licenses.split():
4616
4617 if not licname.strip():
4618 continue
4619
4620 if not self.entropyTools.is_valid_string(licname):
4621 continue
4622
4623 cur = self.cursor.execute("""
4624 SELECT text FROM licensedata WHERE licensename = (?) LIMIT 1
4625 """, (licname,))
4626 lictext = cur.fetchone()
4627 if lictext is not None:
4628 lictext = lictext[0]
4629 try:
4630 licdata[licname] = const_convert_to_unicode(lictext)
4631 except UnicodeDecodeError:
4632 licdata[licname] = \
4633 const_convert_to_unicode(lictext, enctype = 'utf-8')
4634
4635 return licdata
4636
4638 """
4639 Return license names available for given package identifier.
4640
4641 @param idpackage: package indentifier
4642 @type idpackage: int
4643 @return: list (set) of license names which text is available in
4644 repository
4645 @rtype: set
4646 """
4647
4648 licenses = self.retrieveLicense(idpackage)
4649 if licenses is None:
4650 return set()
4651
4652 licdata = set()
4653 for licname in licenses.split():
4654
4655 if not licname.strip():
4656 continue
4657
4658 if not self.entropyTools.is_valid_string(licname):
4659 continue
4660
4661 cur = self.cursor.execute("""
4662 SELECT licensename FROM licensedata WHERE licensename = (?) LIMIT 1
4663 """, (licname,))
4664 lic_id = cur.fetchone()
4665 if lic_id:
4666 licdata.add(lic_id[0])
4667
4668 return licdata
4669
4670 - def retrieveLicenseText(self, license_name):
4671 """
4672 Return license text for given license name.
4673
4674 @param license_name: license name (for eg. GPL-2)
4675 @type license_name: string
4676 @return: license text
4677 @rtype: string (raw format) or None
4678 """
4679
4680 self.connection.text_factory = lambda x: const_convert_to_unicode(x)
4681
4682 cur = self.cursor.execute("""
4683 SELECT text FROM licensedata WHERE licensename = (?) LIMIT 1
4684 """, (license_name,))
4685
4686 text = cur.fetchone()
4687 if text:
4688 return const_convert_to_rawstring(text[0])
4689
4691 """
4692 Return "license" metadatum for given package identifier.
4693
4694 @param idpackage: package indentifier
4695 @type idpackage: int
4696 @return: license string
4697 @rtype: string or None
4698 """
4699 cur = self.cursor.execute("""
4700 SELECT license FROM baseinfo,licenses
4701 WHERE baseinfo.idpackage = (?) AND
4702 baseinfo.idlicense = licenses.idlicense LIMIT 1
4703 """, (idpackage,))
4704
4705 licname = cur.fetchone()
4706 if licname:
4707 return licname[0]
4708
4710 """
4711 Return Compiler flags during building of package.
4712 (CHOST, CXXFLAGS, LDFLAGS)
4713
4714 @param idpackage: package indentifier
4715 @type idpackage: int
4716 @return: tuple of length 3 composed by (CHOST, CFLAGS, CXXFLAGS)
4717 @rtype: tuple
4718 """
4719 self.cursor.execute("""
4720 SELECT chost,cflags,cxxflags FROM flags,extrainfo
4721 WHERE extrainfo.idpackage = (?) AND
4722 extrainfo.idflags = flags.idflags""", (idpackage,))
4723 flags = self.cursor.fetchone()
4724 if not flags:
4725 flags = ("N/A", "N/A", "N/A",)
4726 return flags
4727
4730 """
4731 Return reverse (or inverse) dependencies for given package.
4732
4733 @param idpackage: package indentifier
4734 @type idpackage: int
4735 @keyword atoms: if True, method returns list of atoms
4736 @type atoms: bool
4737 @keyword key_slot: if True, method returns list of dependencies in
4738 key:slot form, example: [('app-foo/bar','2',), ...]
4739 @type key_slot: bool
4740 @keyword exclude_deptypes: exclude given dependency types from returned
4741 data
4742 @type exclude_deptypes: iterable
4743 @return: reverse dependency list
4744 @rtype: list or set
4745
4746 """
4747
4748
4749
4750
4751 c_tup = ("retrieveReverseDependencies_check",)
4752 if not self.live_cache.get(c_tup):
4753 self.live_cache[c_tup] = True
4754 if not self._isDependsTableSane():
4755 self.generateReverseDependenciesMetadata(verbose = False)
4756
4757 excluded_deptypes_query = ""
4758 if exclude_deptypes is not None:
4759 for dep_type in exclude_deptypes:
4760 excluded_deptypes_query += " AND dependencies.type != %s" % (
4761 dep_type,)
4762
4763 if atoms:
4764 cur = self.cursor.execute("""
4765 SELECT baseinfo.atom FROM dependstable,dependencies,baseinfo
4766 WHERE dependstable.idpackage = (?) AND
4767 dependstable.iddependency = dependencies.iddependency AND
4768 baseinfo.idpackage = dependencies.idpackage %s""" % (
4769 excluded_deptypes_query,), (idpackage,))
4770 result = self._cur2set(cur)
4771 elif key_slot:
4772 cur = self.cursor.execute("""
4773 SELECT categories.category || "/" || baseinfo.name,baseinfo.slot
4774 FROM baseinfo,categories,dependstable,dependencies
4775 WHERE dependstable.idpackage = (?) AND
4776 dependstable.iddependency = dependencies.iddependency AND
4777 baseinfo.idpackage = dependencies.idpackage AND
4778 categories.idcategory = baseinfo.idcategory %s""" % (
4779 excluded_deptypes_query,), (idpackage,))
4780 result = cur.fetchall()
4781 else:
4782 cur = self.cursor.execute("""
4783 SELECT dependencies.idpackage FROM dependstable,dependencies
4784 WHERE dependstable.idpackage = (?) AND
4785 dependstable.iddependency = dependencies.iddependency %s""" % (
4786 excluded_deptypes_query,), (idpackage,))
4787 result = self._cur2set(cur)
4788
4789 return result
4790
4792 """
4793 Return packages (through their identifiers) not referenced by any
4794 other as dependency (unused packages).
4795
4796 @return: unused idpackages ordered by atom
4797 @rtype: list
4798 """
4799
4800
4801
4802
4803 c_tup = ("retrieveUnusedIdpackages_check",)
4804 if not self.live_cache.get(c_tup):
4805 self.live_cache[c_tup] = True
4806 if not self._isDependsTableSane():
4807 self.generateReverseDependenciesMetadata(verbose = False)
4808
4809 cur = self.cursor.execute("""
4810 SELECT idpackage FROM baseinfo
4811 WHERE idpackage NOT IN (SELECT idpackage FROM dependstable)
4812 ORDER BY atom
4813 """)
4814 return self._cur2list(cur)
4815
4817 """
4818 Return whether given atom is available in repository.
4819
4820 @param atom: package atom
4821 @type atom: string
4822 @return: idpackage or -1 if not found
4823 @rtype: int
4824 """
4825 cur = self.cursor.execute("""
4826 SELECT idpackage FROM baseinfo WHERE atom = (?) LIMIT 1
4827 """, (atom,))
4828 result = cur.fetchone()
4829 if result:
4830 return result[0]
4831 return -1
4832
4834 """
4835 Return whether list of package identifiers are available.
4836 They must be all available to return True
4837
4838 @param idpackages: list of package indentifiers
4839 @type idpackages: iterable
4840 @return: availability (True if all are available)
4841 @rtype: bool
4842 """
4843 sql = """SELECT count(idpackage) FROM baseinfo
4844 WHERE idpackage IN (%s)""" % (','.join(
4845 [str(x) for x in set(idpackages)]),
4846 )
4847 cur = self.cursor.execute(sql)
4848 count = cur.fetchone()[0]
4849 if count != len(idpackages):
4850 return False
4851 return True
4852
4854 """
4855 Return whether given package identifier is available in repository.
4856
4857 @param idpackage: package indentifier
4858 @type idpackage: int
4859 @return: availability (True if available)
4860 @rtype: bool
4861 """
4862 cur = self.cursor.execute("""
4863 SELECT idpackage FROM baseinfo WHERE idpackage = (?) LIMIT 1
4864 """, (idpackage,))
4865 result = cur.fetchone()
4866 if not result:
4867 return False
4868 return True
4869
4871 """
4872 Return whether given category is available in repository.
4873
4874 @param category: category name
4875 @type category: string
4876 @return: availability (True if available)
4877 @rtype: bool
4878 """
4879 cur = self.cursor.execute("""
4880 SELECT idcategory FROM categories WHERE category = (?) LIMIT 1
4881 """, (category,))
4882 result = cur.fetchone()
4883 if result:
4884 return result[0]
4885 return -1
4886
4888 """
4889 Return whether given CONFIG_PROTECT* entry is available in repository.
4890
4891 @param protect: CONFIG_PROTECT* entry (path to a protected directory
4892 or file that won't be overwritten by Entropy Client during
4893 package merge)
4894 @type protect: string
4895 @return: availability (True if available)
4896 @rtype: bool
4897 """
4898 cur = self.cursor.execute("""
4899 SELECT idprotect FROM configprotectreference WHERE protect = (?)
4900 LIMIT 1
4901 """, (protect,))
4902 result = cur.fetchone()
4903 if result:
4904 return result[0]
4905 return -1
4906
4908 """
4909 Return whether given file path is available in repository (owned by
4910 one or more packages).
4911
4912 @param myfile: path to file or directory
4913 @type myfile: string
4914 @keyword get_id: return list (set) of idpackages owning myfile
4915 @type get_id: bool
4916 @return: availability (True if available), when get_id is True,
4917 it returns a list (set) of idpackages owning myfile
4918 @rtype: bool or set
4919 """
4920 cur = self.cursor.execute("""
4921 SELECT idpackage FROM content WHERE file = (?)""", (myfile,))
4922 result = cur.fetchall()
4923 if get_id:
4924 return self._fetchall2set(result)
4925 elif result:
4926 return True
4927 return False
4928
4929 - def resolveNeeded(self, needed, elfclass = -1, extended = False):
4930 """
4931 Resolve NEEDED ELF entry (a library name) to idpackages owning given
4932 needed (stressing, needed = library name)
4933
4934 @param needed: library name
4935 @type needed: string
4936 @keyword elfclass: look for library name matching given ELF class
4937 @type elfclass: int
4938 @keyword extended: return a list of tuple of length 2, first element
4939 is idpackage, second is actual library path
4940 @type extended: bool
4941 @return: list of packages owning given library
4942 @rtype: list or set
4943 """
4944
4945 if not self._doesTableExist('provided_libs'):
4946 self._createProvidedLibs()
4947
4948 args = (needed,)
4949 elfclass_txt = ''
4950 if elfclass != -1:
4951 elfclass_txt = ' AND provided_libs.elfclass = (?)'
4952 args = (needed, elfclass,)
4953
4954 if extended:
4955 cur = self.cursor.execute("""
4956 SELECT idpackage, path FROM provided_libs
4957 WHERE library = (?)""" + elfclass_txt, args)
4958 return cur.fetchall()
4959
4960 cur = self.cursor.execute("""
4961 SELECT idpackage FROM provided_libs
4962 WHERE library = (?)""" + elfclass_txt, args)
4963 return self._cur2set(cur)
4964
4966 """
4967 Return whether given source package URL is available in repository.
4968 Returns source package URL identifier (idsource).
4969
4970 @param source: source package URL
4971 @type source: string
4972 @return: source package URL identifier (idsource) or -1 if not found
4973 @rtype: int
4974
4975 """
4976 cur = self.cursor.execute("""
4977 SELECT idsource FROM sourcesreference WHERE source = (?) LIMIT 1
4978 """, (source,))
4979 result = cur.fetchone()
4980 if result:
4981 return result[0]
4982 return -1
4983
4985 """
4986 Return whether given dependency string is available in repository.
4987 Returns dependency identifier (iddependency).
4988
4989 @param dependency: dependency string
4990 @type dependency: string
4991 @return: dependency identifier (iddependency) or -1 if not found
4992 @rtype: int
4993 """
4994 cur = self.cursor.execute("""
4995 SELECT iddependency FROM dependenciesreference WHERE dependency = (?)
4996 LIMIT 1""", (dependency,))
4997 result = cur.fetchone()
4998 if result:
4999 return result[0]
5000 return -1
5001
5003 """
5004 Return whether keyword string is available in repository.
5005 Returns keyword identifier (idkeyword)
5006
5007 @param keyword: keyword string
5008 @type keyword: string
5009 @return: keyword identifier (idkeyword) or -1 if not found
5010 @rtype: int
5011 """
5012 cur = self.cursor.execute("""
5013 SELECT idkeyword FROM keywordsreference WHERE keywordname = (?) LIMIT 1
5014 """, (keyword,))
5015 result = cur.fetchone()
5016 if result:
5017 return result[0]
5018 return -1
5019
5021 """
5022 Return whether USE flag name is available in repository.
5023 Returns USE flag identifier (idflag).
5024
5025 @param useflag: USE flag name
5026 @type useflag: string
5027 @return: USE flag identifier or -1 if not found
5028 @rtype: int
5029 """
5030 cur = self.cursor.execute("""
5031 SELECT idflag FROM useflagsreference WHERE flagname = (?) LIMIT 1
5032 """, (useflag,))
5033 result = cur.fetchone()
5034 if result:
5035 return result[0]
5036 return -1
5037
5039 """
5040 Return whether eclass name is available in repository.
5041 Returns Eclass identifier (idclass)
5042
5043 @param eclass: eclass name
5044 @type eclass: string
5045 @return: Eclass identifier or -1 if not found
5046 @rtype: int
5047 """
5048 cur = self.cursor.execute("""
5049 SELECT idclass FROM eclassesreference WHERE classname = (?) LIMIT 1
5050 """, (eclass,))
5051 result = cur.fetchone()
5052 if result:
5053 return result[0]
5054 return -1
5055
5057 """
5058 Return whether NEEDED ELF entry (library name) is available in
5059 repository.
5060 Returns NEEDED entry identifier
5061
5062 @param needed: NEEDED ELF entry (library name)
5063 @type needed: string
5064 @return: NEEDED entry identifier or -1 if not found
5065 @rtype: int
5066 """
5067 cur = self.cursor.execute("""
5068 SELECT idneeded FROM neededreference WHERE library = (?) LIMIT 1
5069 """, (needed,))
5070 result = cur.fetchone()
5071 if result:
5072 return result[0]
5073 return -1
5074
5076 """
5077 Return whether Source Package Manager package identifier is available
5078 in repository.
5079
5080 @param spm_uid: Source Package Manager package identifier
5081 @type spm_uid: int
5082 @return: availability (True, if available)
5083 @rtype: bool
5084 """
5085 cur = self.cursor.execute("""
5086 SELECT counter FROM counters WHERE counter = (?) LIMIT 1
5087 """, (spm_uid,))
5088 result = cur.fetchone()
5089 if result:
5090 return True
5091 return False
5092
5094 """
5095 Return whether Source Package Manager package identifier has been
5096 trashed. One is trashed when it gets removed from a repository while
5097 still sitting there in place on live system. This is a trick to allow
5098 multiple-repositories management to work fine when shitting around.
5099
5100 @param spm_uid: Source Package Manager package identifier
5101 @type spm_uid: int
5102 @return: availability (True, if available)
5103 @rtype: bool
5104 """
5105 cur = self.cursor.execute("""
5106 SELECT counter FROM trashedcounters WHERE counter = (?) LIMIT 1
5107 """, (spm_uid,))
5108 result = cur.fetchone()
5109 if result:
5110 return True
5111 return False
5112
5114 """
5115 Return whether license name is available in License database, which is
5116 the one containing actual license texts.
5117
5118 @param license_name: license name which license text is available
5119 @type license_name: string
5120 @return: availability (True, if available)
5121 @rtype: bool
5122 """
5123 cur = self.cursor.execute("""
5124 SELECT licensename FROM licensedata WHERE licensename = (?) LIMIT 1
5125 """, (license_name,))
5126 result = cur.fetchone()
5127 if not result:
5128 return False
5129 return True
5130
5132 """
5133 Return whether given license (through its name) has been accepted by
5134 user.
5135
5136 @param license_name: license name
5137 @type license_name: string
5138 @return: if license name has been accepted by user
5139 @rtype: bool
5140 """
5141 cur = self.cursor.execute("""
5142 SELECT licensename FROM licenses_accepted WHERE licensename = (?)
5143 LIMIT 1
5144 """, (license_name,))
5145 result = cur.fetchone()
5146 if not result:
5147 return False
5148 return True
5149
5151 """
5152 Mark license name as accepted by user.
5153 Only and only if user is allowed to accept them:
5154 - in entropy group
5155 - db not open in read only mode
5156
5157 @param license_name: license name
5158 @type license_name: string
5159 @todo: check if readOnly is really required
5160 @todo: check if is_user_in_entropy_group is really required
5161 """
5162 if self.readOnly:
5163 return
5164 if not self.entropyTools.is_user_in_entropy_group():
5165 return
5166
5167 plugins = self.get_plugins()
5168 for plugin_id in sorted(plugins):
5169 plug_inst = plugins[plugin_id]
5170 exec_rc = plug_inst.accept_license_hook(self)
5171 if exec_rc:
5172 raise RepositoryPluginError(
5173 "[accept_license_hook] %s: status: %s" % (
5174 plug_inst.get_id(), exec_rc,))
5175
5176 with self.__write_mutex:
5177 self.cursor.execute("""
5178 INSERT OR IGNORE INTO licenses_accepted VALUES (?)
5179 """, (license_name,))
5180 self.commitChanges()
5181
5183 """
5184 Return whether license metdatatum (NOT license name) is available
5185 in repository.
5186
5187 @param pkglicense: "license" package metadatum (returned by
5188 retrieveLicense)
5189 @type pkglicense: string
5190 @return: "license" metadatum identifier (idlicense)
5191 @rtype: int
5192 """
5193 if not self.entropyTools.is_valid_string(pkglicense):
5194 pkglicense = ' '
5195
5196 cur = self.cursor.execute("""
5197 SELECT idlicense FROM licenses WHERE license = (?) LIMIT 1
5198 """, (pkglicense,))
5199 result = cur.fetchone()
5200
5201 if result:
5202 return result[0]
5203 return -1
5204
5206 """
5207 Return whether package is part of core system (though, a system
5208 package).
5209
5210 @param idpackage: package indentifier
5211 @type idpackage: int
5212 @return: if True, package is part of core system
5213 @rtype: bool
5214 """
5215 cur = self.cursor.execute("""
5216 SELECT idpackage FROM systempackages WHERE idpackage = (?) LIMIT 1
5217 """, (idpackage,))
5218 result = cur.fetchone()
5219 if result:
5220 return True
5221 return False
5222
5224 """
5225 Return whether package has been injected into repository (means that
5226 will be never ever removed due to colliding scope when other
5227 packages will be added).
5228
5229 @param idpackage: package indentifier
5230 @type idpackage: int
5231 @return: injection status (True if injected)
5232 @rtype: bool
5233 """
5234 cur = self.cursor.execute("""
5235 SELECT idpackage FROM injected WHERE idpackage = (?) LIMIT 1
5236 """, (idpackage,))
5237 result = cur.fetchone()
5238 if result:
5239 return True
5240 return False
5241
5243 """
5244 Return whether given Compiler FLAGS are available in repository.
5245
5246 @param chost: CHOST flag
5247 @type chost: string
5248 @param cflags: CFLAGS flag
5249 @type cflags: string
5250 @param cxxflags: CXXFLAGS flag
5251 @type cxxflags: string
5252 @return: availability (True if available)
5253 @rtype: bool
5254 """
5255 cur = self.cursor.execute("""
5256 SELECT idflags FROM flags WHERE chost = (?)
5257 AND cflags = (?) AND cxxflags = (?) LIMIT 1
5258 """,
5259 (chost, cflags, cxxflags,)
5260 )
5261 result = cur.fetchone()
5262 if result:
5263 return result[0]
5264 return -1
5265
5267 """
5268 Search packages which given file path belongs to.
5269
5270 @param file: file path to search
5271 @type file: string
5272 @keyword like: do not match exact case
5273 @type like: bool
5274 @return: list (set) of package identifiers owning given file
5275 @rtype: set
5276 """
5277 if like:
5278 cur = self.cursor.execute("""
5279 SELECT content.idpackage FROM content,baseinfo
5280 WHERE file LIKE (?) AND
5281 content.idpackage = baseinfo.idpackage""", (file,))
5282 else:
5283 cur = self.cursor.execute("""SELECT content.idpackage
5284 FROM content, baseinfo WHERE file = (?)
5285 AND content.idpackage = baseinfo.idpackage""", (file,))
5286
5287 return self._cur2set(cur)
5288
5290 """
5291 Search packages which their Source Package Manager counterpar are using
5292 given eclass.
5293
5294 @param eclass: eclass name to search
5295 @type eclass: string
5296 @keyword atoms: return list of atoms instead of package identifiers
5297 @type atoms: bool
5298 @return: list of packages using given eclass
5299 @rtype: set or list
5300 """
5301 if atoms:
5302 cur = self.cursor.execute("""
5303 SELECT baseinfo.atom,eclasses.idpackage
5304 FROM baseinfo, eclasses, eclassesreference
5305 WHERE eclassesreference.classname = (?) AND
5306 eclassesreference.idclass = eclasses.idclass AND
5307 eclasses.idpackage = baseinfo.idpackage""", (eclass,))
5308 return cur.fetchall()
5309
5310 cur = self.cursor.execute("""
5311 SELECT idpackage FROM baseinfo WHERE versiontag = (?)""", (eclass,))
5312 return self._cur2set(cur)
5313
5315 """
5316 Search packages which "tag" metadatum matches the given one.
5317
5318 @param tag: tag name to search
5319 @type tag: string
5320 @keyword atoms: return list of atoms instead of package identifiers
5321 @type atoms: bool
5322 @return: list of packages using given tag
5323 @rtype: set or list
5324 """
5325 if atoms:
5326 cur = self.cursor.execute("""
5327 SELECT atom, idpackage FROM baseinfo WHERE versiontag = (?)
5328 """, (tag,))
5329 return cur.fetchall()
5330
5331 cur = self.cursor.execute("""
5332 SELECT idpackage FROM baseinfo WHERE versiontag = (?)
5333 """, (tag,))
5334 return self._cur2set(cur)
5335
5336 - def searchLicenses(self, mylicense, caseSensitive = False, atoms = False):
5337 """
5338 Search packages using given license (mylicense).
5339
5340 @param mylicense: license name to search
5341 @type mylicense: string
5342 @keyword caseSensitive: search in case sensitive mode (default off)
5343 @type caseSensitive: bool
5344 @keyword atoms: return list of atoms instead of package identifiers
5345 @type atoms: bool
5346 @return: list of packages using given license
5347 @rtype: set or list
5348 @todo: check if is_valid_string is really required
5349 """
5350 if not self.entropyTools.is_valid_string(mylicense):
5351 return []
5352
5353 request = "baseinfo.idpackage"
5354 if atoms:
5355 request = "baseinfo.atom,baseinfo.idpackage"
5356
5357 if caseSensitive:
5358 cur = self.cursor.execute("""
5359 SELECT %s FROM baseinfo,licenses
5360 WHERE licenses.license LIKE (?) AND
5361 licenses.idlicense = baseinfo.idlicense
5362 """ % (request,), ("%"+mylicense+"%",))
5363 else:
5364 cur = self.cursor.execute("""
5365 SELECT %s FROM baseinfo,licenses
5366 WHERE LOWER(licenses.license) LIKE (?) AND
5367 licenses.idlicense = baseinfo.idlicense
5368 """ % (request,), ("%"+mylicense+"%".lower(),))
5369
5370 if atoms:
5371 return cur.fetchall()
5372 return self._cur2set(cur)
5373
5375 """
5376 Search packages with given slot string.
5377
5378 @param slot: slot to search
5379 @type slot: string
5380 @keyword atoms: return list of atoms instead of package identifiers
5381 @type atoms: bool
5382 @return: list of packages using given slot
5383 @rtype: set or list
5384 """
5385 if atoms:
5386 cur = self.cursor.execute("""
5387 SELECT atom,idpackage FROM baseinfo WHERE slot = (?)
5388 """, (slot,))
5389 return cur.fetchall()
5390
5391 cur = self.cursor.execute("""
5392 SELECT idpackage FROM baseinfo WHERE slot = (?)""", (slot,))
5393 return self._cur2set(cur)
5394
5396 """
5397 Search package with given key and slot
5398
5399 @param key: package key
5400 @type key: string
5401 @param slot: package slot
5402 @type slot: string
5403 @return: list (set) of package identifiers
5404 @rtype: set
5405 """
5406 cat, name = key.split("/")
5407 cur = self.cursor.execute("""
5408 SELECT idpackage FROM baseinfo, categories
5409 WHERE baseinfo.idcategory = categories.idcategory AND
5410 categories.category = (?) AND
5411 baseinfo.name = (?) AND
5412 baseinfo.slot = (?)""", (cat, name, slot,))
5413
5414 return cur.fetchall()
5415
5416 - def searchNeeded(self, needed, elfclass = -1, like = False):
5417 """
5418 Search packages that need given NEEDED ELF entry (library name).
5419
5420 @param needed: NEEDED ELF entry (shared object library name)
5421 @type needed: string
5422 @param elfclass: search NEEDEDs only with given ELF class
5423 @type elfclass: int
5424 @keyword like: do not match exact case
5425 @type like: bool
5426 @return: list (set) of package identifiers
5427 @rtype: set
5428 """
5429 elfsearch = ''
5430 search_args = (needed,)
5431 if elfclass != -1:
5432 elfsearch = ' AND needed.elfclass = (?)'
5433 search_args = (needed, elfclass,)
5434
5435 if like:
5436 cur = self.cursor.execute("""
5437 SELECT needed.idpackage FROM needed,neededreference
5438 WHERE library LIKE (?) %s AND
5439 needed.idneeded = neededreference.idneeded
5440 """ % (elfsearch,), search_args)
5441 else:
5442 cur = self.cursor.execute("""
5443 SELECT needed.idpackage FROM needed,neededreference
5444 WHERE library = (?) %s AND
5445 needed.idneeded = neededreference.idneeded
5446 """ % (elfsearch,), search_args)
5447
5448 return self._cur2set(cur)
5449
5450 - def searchDependency(self, dep, like = False, multi = False,
5451 strings = False):
5452 """
5453 Search dependency name in repository.
5454 Returns dependency identifier (iddependency) or dependency strings
5455 (if strings argument is True).
5456
5457 @param dep: dependency name
5458 @type dep: string
5459 @keyword like: do not match exact case
5460 @type like: bool
5461 @keyword multi: return all the matching dependency names
5462 @type multi: bool
5463 @keyword strings: return dependency names rather than dependency
5464 identifiers
5465 @type strings: bool
5466 @return: list of dependency identifiers (if multi is True) or
5467 strings (if strings is True) or dependency identifier
5468 @rtype: int or set
5469 """
5470 sign = "="
5471 if like:
5472 sign = "LIKE"
5473 dep = "%"+dep+"%"
5474 item = 'iddependency'
5475 if strings:
5476 item = 'dependency'
5477
5478 cur = self.cursor.execute("""
5479 SELECT %s FROM dependenciesreference WHERE dependency %s (?)
5480 """ % (item, sign,), (dep,))
5481
5482 if multi:
5483 return self._cur2set(cur)
5484 iddep = cur.fetchone()
5485
5486 if iddep:
5487 return iddep[0]
5488 return -1
5489
5491 """
5492 Search package identifiers owning dependency given (in form of
5493 dependency identifier).
5494
5495 @param iddep: dependency identifier
5496 @type iddep: int
5497 @return: list (set) of package identifiers owning given dependency
5498 identifier
5499 @rtype: set
5500 """
5501 cur = self.cursor.execute("""
5502 SELECT idpackage FROM dependencies WHERE iddependency = (?)
5503 """, (iddep,))
5504 return self._cur2set(cur)
5505
5507 """
5508 Search package sets in repository using given search keyword.
5509
5510 @param keyword: package set name to search
5511 @type keyword: string
5512 @return: list (set) of package sets available matching given keyword
5513 @rtype: set
5514
5515 """
5516 cur = self.cursor.execute("""
5517 SELECT DISTINCT(setname) FROM packagesets WHERE setname LIKE (?)
5518 """, ("%"+keyword+"%",))
5519
5520 return self._cur2set(cur)
5521
5523 """
5524 Search similar packages (basing on package string given by mystring
5525 argument) using SOUNDEX algorithm (ahhh Google...).
5526
5527 @param mystring: package string to search
5528 @type mystring: string
5529 @keyword atom: return full atoms instead of package names
5530 @type atom: bool
5531 @return: list of similar package names
5532 @rtype: set
5533 """
5534 s_item = 'name'
5535 if atom:
5536 s_item = 'atom'
5537 cur = self.cursor.execute("""
5538 SELECT idpackage FROM baseinfo
5539 WHERE soundex(%s) = soundex((?)) ORDER BY %s
5540 """ % (s_item, s_item,), (mystring,))
5541
5542 return self._cur2list(cur)
5543
5544 - def searchPackages(self, keyword, sensitive = False, slot = None,
5545 tag = None, order_by = 'atom', just_id = False):
5546 """
5547 Search packages using given package name "keyword" argument.
5548
5549 @param keyword: package string
5550 @type keyword: string
5551 @keyword sensitive: case sensitive?
5552 @type sensitive: bool
5553 @keyword slot: search matching given slot
5554 @type slot: string
5555 @keyword tag: search matching given package tag
5556 @type tag: string
5557 @keyword order_by: order results by "atom", "name" or "version"
5558 @type order_by: string
5559 @keyword just_id: just return package identifiers (returning set())
5560 @type just_id: bool
5561 @return: packages found matching given search criterias
5562 @rtype: set or list
5563 """
5564 searchkeywords = ["%"+keyword+"%"]
5565
5566 slotstring = ''
5567 if slot:
5568 searchkeywords.append(slot)
5569 slotstring = ' and slot = (?)'
5570
5571 tagstring = ''
5572 if tag:
5573 searchkeywords.append(tag)
5574 tagstring = ' and versiontag = (?)'
5575
5576 order_by_string = ''
5577 if order_by in ("atom", "idpackage", "branch",):
5578 order_by_string = ' order by %s' % (order_by,)
5579
5580 search_elements = 'atom,idpackage,branch'
5581 if just_id:
5582 search_elements = 'idpackage'
5583
5584 if sensitive:
5585 cur = self.cursor.execute("""
5586 SELECT %s FROM baseinfo WHERE atom LIKE (?) %s %s %s""" % (
5587 search_elements, slotstring, tagstring, order_by_string,),
5588 searchkeywords
5589 )
5590 else:
5591 cur = self.cursor.execute("""
5592 SELECT %s FROM baseinfo WHERE
5593 LOWER(atom) LIKE (?) %s %s %s""" % (
5594 search_elements, slotstring, tagstring, order_by_string,),
5595 searchkeywords
5596 )
5597
5598 if just_id:
5599 return self._cur2list(cur)
5600 return cur.fetchall()
5601
5602 - def searchProvide(self, keyword, slot = None, tag = None, justid = False,
5603 get_extended = False):
5604 """
5605 Search in old-style Portage PROVIDE metadata.
5606 WARNING: this method is deprecated and will be removed someday.
5607
5608 @param keyword: search term
5609 @type keyword: string
5610 @keyword slot: match given package slot
5611 @type slot: string
5612 @keyword tag: match given package tag
5613 @type tag: string
5614 @keyword justid: return list of package identifiers (set())
5615 @type justid: bool
5616 @keyword get_extended: return data in extended format
5617 @type get_extended: bool
5618 @return: found PROVIDE metadata
5619 @rtype: list or set
5620 """
5621 searchkeywords = [keyword]
5622
5623 slotstring = ''
5624 if slot:
5625 searchkeywords.append(slot)
5626 slotstring = ' and baseinfo.slot = (?)'
5627
5628 tagstring = ''
5629 if tag:
5630 searchkeywords.append(tag)
5631 tagstring = ' and baseinfo.versiontag = (?)'
5632
5633 atomstring = ''
5634 if not justid:
5635 atomstring = 'baseinfo.atom,'
5636
5637 get_def_string = ''
5638 if get_extended:
5639
5640 if self._doesColumnInTableExist("provide", "is_default"):
5641 get_def_string = ",provide.is_default"
5642 else:
5643 get_def_string = ",0"
5644
5645 cur = self.cursor.execute("""
5646 SELECT %s baseinfo.idpackage%s FROM baseinfo,provide
5647 WHERE provide.atom = (?) AND
5648 provide.idpackage = baseinfo.idpackage %s %s""" % (
5649 atomstring, get_def_string, slotstring, tagstring,),
5650 searchkeywords
5651 )
5652
5653 if justid and not get_extended:
5654 return self._cur2list(cur)
5655 return cur.fetchall()
5656
5658 """
5659 Search packages using given description string as keyword.
5660
5661 @param keyword: description sub-string to search
5662 @type keyword: string
5663 @return: list of tuples of length 2 containing atom and idpackage
5664 values
5665 @rtype: list
5666 """
5667 cur = self.cursor.execute("""
5668 SELECT baseinfo.atom, baseinfo.idpackage FROM extrainfo, baseinfo
5669 WHERE LOWER(extrainfo.description) LIKE (?) AND
5670 baseinfo.idpackage = extrainfo.idpackage
5671 """, ("%"+keyword.lower()+"%",))
5672 return cur.fetchall()
5673
5675 """
5676 Search packages by package name.
5677
5678 @param keyword: package name to search
5679 @type keyword: string
5680 @keyword sensitive: case sensitive?
5681 @type sensitive: bool
5682 @keyword justid: return list of package identifiers (set()) otherwise
5683 return a list of tuples of length 2 containing atom and idpackage
5684 values
5685 @type justid: bool
5686 @return: list of packages found
5687 @rtype: list or set
5688 """
5689
5690 atomstring = ''
5691 if not justid:
5692 atomstring = 'atom,'
5693
5694 if sensitive:
5695 cur = self.cursor.execute("""
5696 SELECT %s idpackage FROM baseinfo
5697 WHERE name = (?)
5698 """ % (atomstring,), (keyword,))
5699 else:
5700 cur = self.cursor.execute("""
5701 SELECT %s idpackage FROM baseinfo
5702 WHERE LOWER(name) = (?)
5703 """ % (atomstring,), (keyword.lower(),))
5704
5705 if justid:
5706 return self._cur2list(cur)
5707 return cur.fetchall()
5708
5709
5711 """
5712 Search packages by category name.
5713
5714 @param keyword: category name
5715 @type keyword: string
5716 @keyword like: do not match exact case
5717 @type like: bool
5718 @keyword branch: search in given package branch
5719 @type branch: string
5720 @return: list of tuples of length 2 containing atom and idpackage
5721 values
5722 @rtype: list
5723 """
5724 searchkeywords = [keyword]
5725 branchstring = ''
5726 if branch:
5727 searchkeywords.append(branch)
5728 branchstring = 'and branch = (?)'
5729
5730 if like:
5731 cur = self.cursor.execute("""
5732 SELECT baseinfo.atom,baseinfo.idpackage FROM baseinfo,categories
5733 WHERE categories.category LIKE (?) AND
5734 baseinfo.idcategory = categories.idcategory %s
5735 """ % (branchstring,), searchkeywords)
5736 else:
5737 cur = self.cursor.execute("""
5738 SELECT baseinfo.atom,baseinfo.idpackage FROM baseinfo,categories
5739 WHERE categories.category = (?) AND
5740 baseinfo.idcategory = categories.idcategory %s
5741 """ % (branchstring,), searchkeywords)
5742
5743 return cur.fetchall()
5744
5747 """
5748 Search packages matching given name and category strings.
5749
5750 @param name: package name to search
5751 @type name: string
5752 @param category: package category to search
5753 @type category: string
5754 @keyword sensitive: case sensitive?
5755 @type sensitive: bool
5756 @keyword justid: return list of package identifiers (set()) otherwise
5757 return a list of tuples of length 2 containing atom and idpackage
5758 values
5759 @type justid: bool
5760 @return: list of packages found
5761 @rtype: list or set
5762 """
5763
5764 atomstring = ''
5765 if not justid:
5766 atomstring = 'atom,'
5767
5768 if sensitive:
5769 cur = self.cursor.execute("""
5770 SELECT %s idpackage FROM baseinfo
5771 WHERE name = (?) AND
5772 idcategory IN (
5773 SELECT idcategory FROM categories
5774 WHERE category = (?)
5775 )""" % (atomstring,), (name, category,))
5776 else:
5777 cur = self.cursor.execute("""
5778 SELECT %s idpackage FROM baseinfo
5779 WHERE LOWER(name) = (?) AND
5780 idcategory IN (
5781 SELECT idcategory FROM categories
5782 WHERE LOWER(category) = (?)
5783 )""" % (atomstring,), (name.lower(), category.lower(),))
5784
5785 if justid:
5786 return self._cur2list(cur)
5787 return cur.fetchall()
5788
5790 """
5791 Return whether given package scope is available.
5792 Also check if package found is masked and return masking reason
5793 identifier.
5794
5795 @param atom: package atom string
5796 @type atom: string
5797 @param slot: package slot string
5798 @type slot: string
5799 @param revision: entropy package revision
5800 @type revision: int
5801 @return: tuple composed by (idpackage or -1, idreason or 0,)
5802 @rtype: tuple
5803
5804 """
5805 searchdata = (atom, slot, revision,)
5806 cur = self.cursor.execute("""
5807 SELECT idpackage FROM baseinfo
5808 where atom = (?) AND slot = (?) AND revision = (?) LIMIT 1
5809 """, searchdata)
5810 rslt = cur.fetchone()
5811
5812 if rslt:
5813 return self.idpackageValidator(rslt[0])
5814 return -1, 0
5815
5817 """
5818 Returns whether branch migration metadata given by the provided key
5819 (repository, from_branch, to_branch,) is available.
5820
5821 @param repository: repository identifier
5822 @type repository: string
5823 @param from_branch: original branch
5824 @type from_branch: string
5825 @param to_branch: destination branch
5826 @type to_branch: string
5827 @return: tuple composed by (1)post migration script md5sum and
5828 (2)post upgrade script md5sum
5829 @rtype: tuple
5830 """
5831 cur = self.cursor.execute("""
5832 SELECT post_migration_md5sum, post_upgrade_md5sum
5833 FROM entropy_branch_migration
5834 WHERE repository = (?) AND from_branch = (?) AND to_branch = (?)
5835 LIMIT 1
5836 """, (repository, from_branch, to_branch,))
5837 return cur.fetchone()
5838
5840 """
5841 List all packages in repository.
5842
5843 @keyword get_scope: return also entropy package revision
5844 @type get_scope: bool
5845 @keyword order_by: order by given metadatum, "atom", "slot", "revision"
5846 or "idpackage"
5847 @type order_by: string
5848 @return: list of tuples of length 3 (or 4 if get_scope is True),
5849 containing (atom, idpackage, branch,) if get_scope is False and
5850 (idpackage, atom, slot, revision,) if get_scope is True
5851 @rtype: list
5852 """
5853 order_txt = ''
5854 if order_by:
5855 order_txt = ' ORDER BY %s' % (order_by,)
5856
5857 if get_scope:
5858 cur = self.cursor.execute("""
5859 SELECT idpackage,atom,slot,revision FROM baseinfo""" + order_txt)
5860 else:
5861 cur = self.cursor.execute("""
5862 SELECT atom,idpackage,branch FROM baseinfo""" + order_txt)
5863
5864 return cur.fetchall()
5865
5867 """
5868 List all the "injected" package download URLs in repository.
5869
5870 @keyword just_files: just return download URLs
5871 @type just_files: bool
5872 @return: list (set) of download URLs (if just_files) otherwise list
5873 of tuples of length 2 composed by (download URL, idpackage,)
5874 @rtype: set
5875 """
5876 cur = self.cursor.execute('SELECT idpackage FROM injected')
5877 injecteds = self._cur2set(cur)
5878 results = set()
5879
5880 for injected in injecteds:
5881 download = self.retrieveDownloadURL(injected)
5882 if just_files:
5883 results.add(download)
5884 else:
5885 results.add((download, injected))
5886
5887 return results
5888
5890 """
5891 List all Source Package Manager unique package identifiers bindings
5892 with packages in repository.
5893 @return: list of tuples of length 2 composed by (spm_uid, idpackage,)
5894 @rtype: list
5895 """
5896 cur = self.cursor.execute('SELECT counter, idpackage FROM counters')
5897 return cur.fetchall()
5898
5900 """
5901 List all package identifiers available in repository.
5902
5903 @keyword order_by: order by "atom", "idpackage", "version", "name",
5904 "idcategory"
5905 @type order_by: string
5906 @return: list (if order_by) or set of package identifiers
5907 @rtype: list or set
5908 """
5909 orderbystring = ''
5910 if order_by:
5911 orderbystring = ' ORDER BY '+order_by
5912
5913 cur = self.cursor.execute("""
5914 SELECT idpackage FROM baseinfo""" + orderbystring)
5915
5916 try:
5917 if order_by:
5918 return self._cur2list(cur)
5919 return self._cur2set(cur)
5920 except self.dbapi2.OperationalError:
5921 if order_by:
5922 return []
5923 return set()
5924
5926 """
5927 List all dependencies available in repository.
5928
5929 @return: list of tuples of length 2 containing (iddependency, dependency
5930 name,)
5931 @rtype: list
5932 """
5933 cur = self.cursor.execute("""
5934 SELECT iddependency, dependency FROM dependenciesreference""")
5935 return cur.fetchall()
5936
5938 """
5939 List package identifiers available in given category identifier.
5940
5941 @param idcategory: cateogory identifier
5942 @type idcategory: int
5943 @keyword order_by: order by "atom", "name", "version"
5944 @type order_by: string
5945 @return: list (set) of available package identifiers in category.
5946 @rtype: set
5947 """
5948 order_by_string = ''
5949 if order_by in ("atom", "name", "version",):
5950 order_by_string = ' ORDER BY %s' % (order_by,)
5951
5952 cur = self.cursor.execute("""
5953 SELECT idpackage FROM baseinfo where idcategory = (?)
5954 """ + order_by_string, (idcategory,))
5955
5956 return self._cur2set(cur)
5957
5959 """
5960 List all package download URLs stored in repository.
5961
5962 @keyword do_sort: sort by name
5963 @type do_sort: bool
5964 @keyword full_path: return full URL (not just package file name)
5965 @type full_path: bool
5966 @return: list (or set if do_sort is True) of package download URLs
5967 @rtype: list or set
5968 """
5969
5970 order_string = ''
5971 if do_sort:
5972 order_string = 'ORDER BY extrainfo.download'
5973
5974 cur = self.cursor.execute("""
5975 SELECT extrainfo.download FROM baseinfo, extrainfo
5976 WHERE baseinfo.idpackage = extrainfo.idpackage %s
5977 """ % (order_string,))
5978
5979 if do_sort:
5980 results = self._cur2list(cur)
5981 else:
5982 results = self._cur2set(cur)
5983
5984 if not full_path:
5985 results = [os.path.basename(x) for x in results]
5986
5987 return results
5988
5990 """
5991 List all file paths owned by packaged stored in repository.
5992
5993 @keyword clean: return a clean list (not duplicates)
5994 @type clean: bool
5995 @keyword count: count elements and return number
5996 @type count: bool
5997 @return: list of files available or their count
5998 @rtype: int or list or set
5999 """
6000 self.connection.text_factory = lambda x: const_convert_to_unicode(x)
6001
6002 if count:
6003 cur = self.cursor.execute('SELECT count(file) FROM content')
6004 else:
6005 cur = self.cursor.execute('SELECT file FROM content')
6006
6007 if count:
6008 return cur.fetchone()[0]
6009 if clean:
6010 return self._cur2set(cur)
6011 return self._cur2list(cur)
6012
6014 """
6015 List all categories available in repository.
6016
6017 @keyword order_by: order by "category", "idcategory"
6018 @type order_by: string
6019 @return: list of tuples of length 2 composed by (idcategory, category,)
6020 @rtype: list
6021 """
6022 order_by_string = ''
6023 if order_by: order_by_string = ' order by %s' % (order_by,)
6024 self.cursor.execute('SELECT idcategory,category FROM categories %s' % (
6025 order_by_string,))
6026 return self.cursor.fetchall()
6027
6029 """
6030 List CONFIG_PROTECT* entries (configuration file/directories
6031 protection).
6032
6033 @keyword mask: return CONFIG_PROTECT_MASK metadata instead of
6034 CONFIG_PROTECT
6035 @type mask: bool
6036 @return: list of protected/masked directories
6037 @rtype: list
6038 """
6039 mask_t = ''
6040 if mask:
6041 mask_t = 'mask'
6042 cur = self.cursor.execute("""
6043 SELECT protect FROM configprotectreference WHERE idprotect IN
6044 (SELECT distinct(idprotect) FROM configprotect%s)
6045 ORDER BY protect""" % (mask_t,))
6046
6047 results = self._cur2set(cur)
6048 dirs = set()
6049 for mystr in results:
6050 dirs.update(mystr.split())
6051
6052 return sorted(dirs)
6053
6055 """
6056 Switch branch string in repository to new value.
6057
6058 @param idpackage: package identifier
6059 @type idpackage: int
6060 @param tobranch: new branch value
6061 @type tobranch: string
6062 """
6063 with self.__write_mutex:
6064 self.cursor.execute("""
6065 UPDATE baseinfo SET branch = (?)
6066 WHERE idpackage = (?)""", (tobranch, idpackage,))
6067 self.commitChanges()
6068 self.clearCache()
6069
6071 """
6072 Return stored Repository setting.
6073 For currently supported setting_name values look at
6074 EntropyRepository.SETTING_KEYS.
6075
6076 @param setting_name: name of repository setting
6077 @type setting_name: string
6078 @return: setting value
6079 @rtype: string
6080 @raise KeyError: if setting_name is not valid or available
6081 """
6082 if setting_name not in EntropyRepository.SETTING_KEYS:
6083 raise KeyError
6084 try:
6085 self.cursor.execute("""
6086 SELECT setting_value FROM settings WHERE setting_name = (?)
6087 """, (setting_name,))
6088 except self.dbapi2.Error:
6089 raise KeyError
6090
6091 setting = self.cursor.fetchone()
6092 if setting is None:
6093 raise KeyError
6094 return setting[0]
6095
6097 """
6098 Setup initial repository settings
6099 """
6100 self.cursor.executescript("""
6101 INSERT OR REPLACE INTO settings VALUES ("arch", "%s");
6102 INSERT OR REPLACE INTO settings VALUES ("on_delete_cascade", "%s");
6103 """ % (etpConst['currentarch'], "1",)
6104 )
6105
6107
6108 old_readonly = self.readOnly
6109 self.readOnly = False
6110
6111 if not self._doesTableExist("licenses_accepted"):
6112 self._createLicensesAcceptedTable()
6113
6114 if not self._doesColumnInTableExist("installedtable", "source"):
6115 self._createInstalledTableSource()
6116
6117 if not self._doesColumnInTableExist("provide", "is_default"):
6118 self._createProvideDefault()
6119
6120 if not self._doesTableExist('packagesets'):
6121 self._createPackagesetsTable()
6122
6123 if not self._doesTableExist('packagechangelogs'):
6124 self._createPackagechangelogsTable()
6125
6126 if not self._doesTableExist('automergefiles'):
6127 self._createAutomergefilesTable()
6128
6129 if not self._doesTableExist('packagesignatures'):
6130 self._createPackagesignaturesTable()
6131
6132 if not self._doesTableExist('packagespmphases'):
6133 self._createPackagespmphases()
6134
6135 if not self._doesTableExist('packagespmrepository'):
6136 self._createPackagespmrepository()
6137
6138 if not self._doesTableExist('entropy_branch_migration'):
6139 self._createEntropyBranchMigrationTable()
6140
6141 if not self._doesTableExist('dependstable'):
6142 self._createDependsTable()
6143
6144 if not self._doesTableExist('settings'):
6145 self._createSettingsTable()
6146
6147 self._foreignKeySupport()
6148
6149 self.readOnly = old_readonly
6150 self.connection.commit()
6151
6153 """
6154 Validates Entropy repository by doing basic integrity checks.
6155
6156 @raise SystemDatabaseError: when repository is not reliable
6157 """
6158 self.cursor.execute("""
6159 SELECT name FROM SQLITE_MASTER WHERE type = (?) AND name = (?)
6160 """, ("table", "baseinfo"))
6161 rslt = self.cursor.fetchone()
6162 if rslt is None:
6163 mytxt = _("baseinfo error. Either does not exist or corrupted.")
6164 raise SystemDatabaseError("SystemDatabaseError: %s" % (mytxt,))
6165
6166 self.cursor.execute("""
6167 SELECT name FROM SQLITE_MASTER WHERE type = (?) AND name = (?)
6168 """, ("table", "extrainfo"))
6169 rslt = self.cursor.fetchone()
6170 if rslt is None:
6171 mytxt = _("extrainfo error. Either does not exist or corrupted.")
6172 raise SystemDatabaseError("SystemDatabaseError: %s" % (mytxt,))
6173
6175 """
6176 Return differences between in-repository package identifiers and
6177 list provided.
6178
6179 @param foreign_idpackages: list of foreign idpackages
6180 @type foreign_idpackages: iterable
6181 @return: tuple composed by idpackages that would be added and idpackages
6182 that would be removed
6183 @rtype: tuple
6184 """
6185 myids = self.listAllIdpackages()
6186 if isinstance(foreign_idpackages, (list, tuple)):
6187 outids = set(foreign_idpackages)
6188 else:
6189 outids = foreign_idpackages
6190 added_ids = outids - myids
6191 removed_ids = myids - outids
6192 return added_ids, removed_ids
6193
6205
6206 - def alignDatabases(self, dbconn, force = False, output_header = " ",
6207 align_limit = 300):
6208 """
6209 Align packages contained in foreign repository "dbconn" and this
6210 instance.
6211
6212 @param dbconn: foreign repository instance
6213 @type dbconn: entropy.db.EntropyRepository
6214 @keyword force: force alignment even if align_limit threshold is
6215 exceeded
6216 @type force: bool
6217 @keyword output_header: output header for printing purposes
6218 @type output_header: string
6219 @keyword align_limit: threshold within alignment is done if force is
6220 False
6221 @type align_limit: int
6222 @return: alignment status (0 = all good; 1 = dbs checksum not matching;
6223 -1 = nothing to do)
6224 @rtype: int
6225 """
6226 added_ids, removed_ids = self.getIdpackagesDifferences(
6227 dbconn.listAllIdpackages())
6228
6229 if not force:
6230 if len(added_ids) > align_limit:
6231 return 0
6232 if len(removed_ids) > align_limit:
6233 return 0
6234
6235 if not added_ids and not removed_ids:
6236 return -1
6237
6238 mytxt = red("%s, %s ...") % (
6239 _("Syncing current database"),
6240 _("please wait"),
6241 )
6242 self.updateProgress(
6243 mytxt,
6244 importance = 1,
6245 type = "info",
6246 header = output_header,
6247 back = True
6248 )
6249
6250 maxcount = len(removed_ids)
6251 mycount = 0
6252 for idpackage in removed_ids:
6253 mycount += 1
6254 mytxt = "%s: %s" % (
6255 red(_("Removing entry")),
6256 blue(str(self.retrieveAtom(idpackage))),
6257 )
6258 self.updateProgress(
6259 mytxt,
6260 importance = 0,
6261 type = "info",
6262 header = output_header,
6263 back = True,
6264 count = (mycount, maxcount)
6265 )
6266
6267 self.removePackage(idpackage, do_cleanup = False, do_commit = False)
6268
6269 maxcount = len(added_ids)
6270 mycount = 0
6271 for idpackage in added_ids:
6272 mycount += 1
6273 mytxt = "%s: %s" % (
6274 red(_("Adding entry")),
6275 blue(str(dbconn.retrieveAtom(idpackage))),
6276 )
6277 self.updateProgress(
6278 mytxt,
6279 importance = 0,
6280 type = "info",
6281 header = output_header,
6282 back = True,
6283 count = (mycount, maxcount)
6284 )
6285 mydata = dbconn.getPackageData(idpackage, get_content = True,
6286 content_insert_formatted = True)
6287 self.addPackage(
6288 mydata,
6289 revision = mydata['revision'],
6290 idpackage = idpackage,
6291 do_commit = False,
6292 formatted_content = True
6293 )
6294
6295
6296 self.doCleanups()
6297
6298 self.clearCache()
6299 self.commitChanges()
6300 self.generateReverseDependenciesMetadata(verbose = False)
6301 dbconn.clearCache()
6302
6303
6304 mycheck = self.checksum(do_order = True, strict = False)
6305 outcheck = dbconn.checksum(do_order = True, strict = False)
6306 if mycheck == outcheck:
6307 return 1
6308 return 0
6309
6311 """
6312 Check if repository EAPI (Entropy API) is not greater than the one
6313 that entropy.const ships.
6314 """
6315
6316 dbapi = self.getApi()
6317 if int(dbapi) > int(etpConst['etpapi']):
6318 self.updateProgress(
6319 red(_("Repository EAPI > Entropy EAPI.")),
6320 importance = 1,
6321 type = "warning",
6322 header = " * ! * ! * ! * "
6323 )
6324 self.updateProgress(
6325 red(_("Please update Equo/Entropy as soon as possible !")),
6326 importance = 1,
6327 type = "warning",
6328 header = " * ! * ! * ! * "
6329 )
6330
6332 """
6333 Import SQLite3 dump file to this database.
6334
6335 @param dumpfile: SQLite3 dump file to read
6336 @type dumpfile: string
6337 @param dbfile: database file to write to
6338 @type dbfile: string
6339 @return: sqlite3 import return code
6340 @rtype: int
6341 @todo: remove /usr/bin/sqlite3 dependency
6342 """
6343 import subprocess
6344 sqlite3_exec = "/usr/bin/sqlite3 %s < %s" % (dbfile, dumpfile,)
6345 retcode = subprocess.call(sqlite3_exec, shell = True)
6346 return retcode
6347
6348 - def doDatabaseExport(self, dumpfile, gentle_with_tables = True,
6349 exclude_tables = None):
6350 """
6351 Export running SQLite3 database to file.
6352
6353 @param dumpfile: dump file object to write to
6354 @type dumpfile: file object (hint: open())
6355 @keyword gentle_with_tables: append "IF NOT EXISTS" to "CREATE TABLE"
6356 statements
6357 @type gentle_with_tables: bool
6358 @todo: when Python 2.6, look ad Connection.iterdump and replace this :)
6359 """
6360 if not exclude_tables:
6361 exclude_tables = []
6362
6363 toraw = const_convert_to_rawstring
6364
6365 dumpfile.write(toraw("BEGIN TRANSACTION;\n"))
6366 self.cursor.execute("""
6367 SELECT name, type, sql FROM sqlite_master
6368 WHERE sql NOT NULL AND type=='table'
6369 """)
6370 for name, x, sql in self.cursor.fetchall():
6371
6372 self.updateProgress(
6373 red("%s " % (
6374 _("Exporting database table"),
6375 ) ) + "["+blue(str(name))+"]",
6376 importance = 0,
6377 type = "info",
6378 back = True,
6379 header = " "
6380 )
6381
6382 if name == "sqlite_sequence":
6383 dumpfile.write(toraw("DELETE FROM sqlite_sequence;\n"))
6384 elif name == "sqlite_stat1":
6385 dumpfile.write(toraw("ANALYZE sqlite_master;\n"))
6386 elif name.startswith("sqlite_"):
6387 continue
6388 else:
6389 t_cmd = "CREATE TABLE"
6390 if sql.startswith(t_cmd) and gentle_with_tables:
6391 sql = "CREATE TABLE IF NOT EXISTS"+sql[len(t_cmd):]
6392 dumpfile.write(toraw("%s;\n" % sql))
6393
6394 if name in exclude_tables:
6395 continue
6396
6397 self.cursor.execute("PRAGMA table_info('%s')" % name)
6398 cols = [r[1] for r in self.cursor.fetchall()]
6399 q = "SELECT 'INSERT INTO \"%(tbl_name)s\" VALUES("
6400 q += ", ".join(["'||quote(" + x + ")||'" for x in cols])
6401 q += ")' FROM '%(tbl_name)s'"
6402 self.cursor.execute(q % {'tbl_name': name})
6403 self.connection.text_factory = lambda x: \
6404 const_convert_to_unicode(x)
6405 for row in self.cursor:
6406 dumpfile.write(toraw("%s;\n" % (row[0],)))
6407
6408 self.cursor.execute("""
6409 SELECT name, type, sql FROM sqlite_master
6410 WHERE sql NOT NULL AND type!='table' AND type!='meta'
6411 """)
6412 for name, x, sql in self.cursor.fetchall():
6413 dumpfile.write(toraw("%s;\n" % sql))
6414
6415 dumpfile.write(toraw("COMMIT;\n"))
6416 try:
6417 dumpfile.flush()
6418 except:
6419 pass
6420 self.updateProgress(
6421 red(_("Database Export complete.")),
6422 importance = 0,
6423 type = "info",
6424 header = " "
6425 )
6426
6427
6429 """
6430 List all available tables in this repository database.
6431
6432 @return: available tables
6433 @rtype: list
6434 """
6435 cur = self.cursor.execute("""
6436 SELECT name FROM SQLITE_MASTER WHERE type = "table"
6437 """)
6438 return self._cur2list(cur)
6439
6441
6442
6443 c_tup = ("_doesTableExist", table,)
6444 cached = self.live_cache.get(c_tup)
6445 if cached is not None:
6446 return cached
6447
6448 cur = self.cursor.execute("""
6449 select name from SQLITE_MASTER where type = "table" and name = (?)
6450 LIMIT 1
6451 """, (table,))
6452 rslt = cur.fetchone()
6453 exists = rslt is not None
6454 if exists:
6455 self.live_cache[c_tup] = True
6456 return exists
6457
6459
6460
6461 c_tup = ("_doesColumnInTableExist", table, column,)
6462 cached = self.live_cache.get(c_tup)
6463 if cached is not None:
6464 return cached
6465
6466 cur = self.cursor.execute('PRAGMA table_info( %s )' % (table,))
6467 rslt = (x[1] for x in cur.fetchall())
6468 if column in rslt:
6469 self.live_cache[c_tup] = True
6470 return True
6471 return False
6472
6473 - def checksum(self, do_order = False, strict = True,
6474 strings = False):
6475 """
6476 Get Repository metadata checksum, useful for integrity verification.
6477 Note: result is cached in EntropyRepository.live_cache (dict).
6478
6479 @keyword do_order: order metadata collection alphabetically
6480 @type do_order: bool
6481 @keyword strict: improve checksum accuracy
6482 @type strict: bool
6483 @keyword strings: return checksum in md5 hex form
6484 @type strings: bool
6485 @return: repository checksum
6486 @rtype: string
6487 """
6488
6489 c_tup = ("checksum", do_order, strict, strings,)
6490 cache = self.live_cache.get(c_tup)
6491 if cache is not None:
6492 return cache
6493
6494 idpackage_order = ''
6495 category_order = ''
6496 license_order = ''
6497 flags_order = ''
6498 if do_order:
6499 idpackage_order = 'order by idpackage'
6500 category_order = 'order by category'
6501 license_order = 'order by license'
6502 flags_order = 'order by chost'
6503
6504 def do_update_md5(m, cursor):
6505 mydata = cursor.fetchall()
6506 for record in mydata:
6507 for item in record:
6508 m.update(const_convert_to_rawstring(item))
6509
6510 if strings:
6511 import hashlib
6512 m = hashlib.md5()
6513
6514
6515 cur = self.cursor.execute("""
6516 SELECT idpackage,atom,name,version,versiontag,
6517 revision,branch,slot,etpapi,trigger FROM
6518 baseinfo %s""" % (idpackage_order,))
6519 if strings:
6520 do_update_md5(m, cur)
6521 else:
6522 a_hash = hash(tuple(cur.fetchall()))
6523
6524
6525 cur = self.cursor.execute("""
6526 SELECT idpackage, description, homepage,
6527 download, size, digest, datecreation FROM
6528 extrainfo %s""" % (idpackage_order,))
6529 if strings:
6530 do_update_md5(m, cur)
6531 else:
6532 b_hash = hash(tuple(cur.fetchall()))
6533
6534
6535 cur = self.cursor.execute("""
6536 SELECT category FROM categories %s
6537 """ % (category_order,))
6538 if strings:
6539 do_update_md5(m, cur)
6540 else:
6541 c_hash = hash(tuple(cur.fetchall()))
6542
6543
6544 d_hash = '0'
6545 e_hash = '0'
6546 if strict:
6547 cur = self.cursor.execute("""
6548 SELECT * FROM licenses %s""" % (license_order,))
6549 if strings:
6550 do_update_md5(m, cur)
6551 else:
6552 d_hash = hash(tuple(cur.fetchall()))
6553
6554 cur = self.cursor.execute('select * from flags %s' % (flags_order,))
6555 if strings:
6556 do_update_md5(m, cur)
6557 else:
6558 e_hash = hash(tuple(cur.fetchall()))
6559
6560 if strings:
6561 result = m.hexdigest()
6562 else:
6563 result = "%s:%s:%s:%s:%s" % (a_hash, b_hash, c_hash, d_hash,
6564 e_hash,)
6565
6566 self.live_cache[c_tup] = result[:]
6567 return result
6568
6569
6571 """
6572 Note: this is used by installed packages repository (also known as
6573 client db).
6574 Add package identifier to the "installed packages table",
6575 which contains repository identifier from where package has been
6576 installed and its install request source (user, pulled in
6577 dependency, etc).
6578
6579 @param idpackage: package indentifier
6580 @type idpackage: int
6581 @param repoid: repository identifier
6582 @type repoid: string
6583 @param source: source identifier (pleas see:
6584 etpConst['install_sources'])
6585 @type source: int
6586 """
6587 with self.__write_mutex:
6588 self.cursor.execute('INSERT into installedtable VALUES (?,?,?)',
6589 (idpackage, repoid, source,))
6590
6592 """
6593 Note: this is used by installed packages repository (also known as
6594 client db).
6595 Return repository identifier stored inside the "installed packages
6596 table".
6597
6598 @param idpackage: package indentifier
6599 @type idpackage: int
6600 @return: repository identifier
6601 @rtype: string or None
6602 """
6603 with self.__write_mutex:
6604 try:
6605 cur = self.cursor.execute("""
6606 SELECT repositoryname FROM installedtable
6607 WHERE idpackage = (?) LIMIT 1""", (idpackage,))
6608 return cur.fetchone()[0]
6609 except (self.dbapi2.OperationalError, TypeError,):
6610 return None
6611
6613 """
6614 Note: this is used by installed packages repository (also known as
6615 client db).
6616 Remove installed package metadata from "installed packages table".
6617 Note: this just removes extra metadata information such as repository
6618 identifier from where package has been installed and its install
6619 request source (user, pulled in dependency, etc).
6620 This method DOES NOT remove package from repository (see
6621 removePackage() instead).
6622
6623 @param idpackage: package indentifier
6624 @type idpackage: int
6625 """
6626 with self.__write_mutex:
6627 self.cursor.execute("""
6628 DELETE FROM installedtable
6629 WHERE idpackage = (?)""", (idpackage,))
6630
6632 with self.__write_mutex:
6633 try:
6634 self.cursor.execute("""
6635 DELETE FROM dependstable WHERE idpackage = (?)
6636 """, (idpackage,))
6637 return 0
6638 except (self.dbapi2.OperationalError,):
6639 return 1
6640
6642 with self.__write_mutex:
6643 self.cursor.executescript("""
6644 CREATE TABLE IF NOT EXISTS dependstable
6645 ( iddependency INTEGER PRIMARY KEY, idpackage INTEGER,
6646 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE );
6647 INSERT INTO dependstable VALUES (-1,NULL);
6648 """)
6649 if self.indexing:
6650 self.cursor.execute("""
6651 CREATE INDEX IF NOT EXISTS dependsindex_idpackage
6652 ON dependstable ( idpackage )
6653 """)
6654 self.commitChanges()
6655
6657 with self.__write_mutex:
6658 self.cursor.execute("""
6659 DELETE FROM dependstable where iddependency = -1
6660 """)
6661 self.commitChanges()
6662
6664 try:
6665 cur = self.cursor.execute("""
6666 SELECT iddependency FROM dependstable WHERE iddependency = -1
6667 """)
6668 except (self.dbapi2.OperationalError,):
6669 return False
6670
6671 status = cur.fetchone()
6672 if status:
6673 return False
6674
6675 cur = self.cursor.execute("SELECT count(*) FROM dependstable")
6676 try:
6677 dependstable_count = cur.fetchone()[0]
6678 except IndexError:
6679 dependstable_count = 0
6680 if dependstable_count < 2:
6681 return False
6682 return True
6683
6699
6720
6722 """
6723 This method returns branch migration metadata stored in Entropy
6724 Client database (installed packages database). It is used to
6725 determine whether to run per-repository branch migration scripts.
6726
6727 @param to_branch: usually the current branch string
6728 @type to_branch: string
6729 @return: branch migration metadata contained in database
6730 @rtype: dict
6731 """
6732 if not self._doesTableExist('entropy_branch_migration'):
6733 return {}
6734
6735 cur = self.cursor.execute("""
6736 SELECT repository, from_branch, post_migration_md5sum,
6737 post_upgrade_md5sum FROM entropy_branch_migration WHERE to_branch = (?)
6738 """, (to_branch,))
6739
6740 data = cur.fetchall()
6741 meta = {}
6742 for repo, from_branch, post_migration_md5, post_upgrade_md5 in data:
6743 obj = meta.setdefault(repo, {})
6744 obj[from_branch] = (post_migration_md5, post_upgrade_md5,)
6745 return meta
6746
6747 - def dropContent(self):
6748 """
6749 Drop all "content" metadata from repository, usually a memory hog.
6750 Content metadata contains files and directories owned by packages.
6751 """
6752 with self.__write_mutex:
6753 self.cursor.execute('DELETE FROM content')
6754
6756 """
6757 Drop all repository metadata indexes.
6758 """
6759 cur = self.cursor.execute("""
6760 SELECT name FROM SQLITE_MASTER WHERE type = "index"
6761 """)
6762 indexes = self._cur2set(cur)
6763 with self.__write_mutex:
6764 for index in indexes:
6765 try:
6766 self.cursor.execute('DROP INDEX IF EXISTS %s' % (index,))
6767 except self.dbapi2.Error:
6768 continue
6769
6771 """
6772 List all the available repository metadata index names.
6773
6774 @keyword only_entropy: if True, return only entropy related indexes
6775 @type only_entropy: bool
6776 @return: list (set) of index names
6777 @rtype: set
6778 """
6779 cur = self.cursor.execute("""
6780 SELECT name FROM SQLITE_MASTER WHERE type = "index"
6781 """)
6782 indexes = self._cur2set(cur)
6783
6784 if not only_entropy:
6785 return indexes
6786 return set([x for x in indexes if not x.startswith("sqlite")])
6787
6789 """
6790 Create all the repository metadata indexes internally available.
6791 """
6792 self._createMirrorlinksIndex()
6793 self._createContentIndex()
6794 self._createBaseinfoIndex()
6795 self._createKeywordsIndex()
6796 self._createDependenciesIndex()
6797 self._createProvideIndex()
6798 self._createConflictsIndex()
6799 self._createExtrainfoIndex()
6800 self._createNeededIndex()
6801 self._createUseflagsIndex()
6802 self._createLicensedataIndex()
6803 self._createLicensesIndex()
6804 self._createConfigProtectReferenceIndex()
6805 self._createMessagesIndex()
6806 self._createSourcesIndex()
6807 self._createCountersIndex()
6808 self._createEclassesIndex()
6809 self._createCategoriesIndex()
6810 self._createCompileFlagsIndex()
6811 self._createPackagesetsIndex()
6812 self._createAutomergefilesIndex()
6813 self._createProvidedLibsIndex()
6814
6816 if self.indexing:
6817 with self.__write_mutex:
6818 self.cursor.execute("""
6819 CREATE INDEX IF NOT EXISTS mirrorlinks_mirrorname
6820 ON mirrorlinks ( mirrorname )""")
6821
6823 if self.indexing:
6824 with self.__write_mutex:
6825 try:
6826 self.cursor.execute("""
6827 CREATE INDEX IF NOT EXISTS packagesetsindex
6828 ON packagesets ( setname )""")
6829 except self.dbapi2.OperationalError:
6830 pass
6831
6833 if self.indexing:
6834 with self.__write_mutex:
6835 try:
6836 self.cursor.executescript("""
6837 CREATE INDEX IF NOT EXISTS provided_libs_library
6838 ON provided_libs ( library );
6839 CREATE INDEX IF NOT EXISTS provided_libs_idpackage
6840 ON provided_libs ( idpackage );
6841 CREATE INDEX IF NOT EXISTS provided_libs_lib_elf
6842 ON provided_libs ( library, elfclass );
6843 """)
6844 except self.dbapi2.OperationalError:
6845 pass
6846
6848 if self.indexing:
6849 with self.__write_mutex:
6850 try:
6851 self.cursor.executescript("""
6852 CREATE INDEX IF NOT EXISTS automergefiles_idpackage
6853 ON automergefiles ( idpackage );
6854 CREATE INDEX IF NOT EXISTS automergefiles_file_md5
6855 ON automergefiles ( configfile, md5 );
6856 """)
6857 except self.dbapi2.OperationalError:
6858 pass
6859
6861 if self.indexing:
6862 with self.__write_mutex:
6863 self.cursor.executescript("""
6864 CREATE INDEX IF NOT EXISTS neededindex ON neededreference
6865 ( library );
6866 CREATE INDEX IF NOT EXISTS neededindex_idneeded ON needed
6867 ( idneeded );
6868 CREATE INDEX IF NOT EXISTS neededindex_idpackage ON needed
6869 ( idpackage );
6870 CREATE INDEX IF NOT EXISTS neededindex_elfclass ON needed
6871 ( elfclass );
6872 """)
6873
6875 if self.indexing:
6876 with self.__write_mutex:
6877 self.cursor.execute("""
6878 CREATE INDEX IF NOT EXISTS messagesindex ON messages
6879 ( idpackage )
6880 """)
6881
6883 if self.indexing:
6884 with self.__write_mutex:
6885 self.cursor.execute("""
6886 CREATE INDEX IF NOT EXISTS flagsindex ON flags
6887 ( chost, cflags, cxxflags )
6888 """)
6889
6891 if self.indexing:
6892 with self.__write_mutex:
6893 self.cursor.executescript("""
6894 CREATE INDEX IF NOT EXISTS useflagsindex_useflags_idpackage
6895 ON useflags ( idpackage );
6896 CREATE INDEX IF NOT EXISTS useflagsindex_useflags_idflag
6897 ON useflags ( idflag );
6898 CREATE INDEX IF NOT EXISTS useflagsindex
6899 ON useflagsreference ( flagname );
6900 """)
6901
6903 if self.indexing:
6904 with self.__write_mutex:
6905 if self._doesTableExist("content"):
6906 self.cursor.executescript("""
6907 CREATE INDEX IF NOT EXISTS contentindex_couple
6908 ON content ( idpackage );
6909 CREATE INDEX IF NOT EXISTS contentindex_file
6910 ON content ( file );
6911 """)
6912
6914 if self.indexing:
6915 with self.__write_mutex:
6916 self.cursor.execute("""
6917 CREATE INDEX IF NOT EXISTS configprotectreferenceindex
6918 ON configprotectreference ( protect )
6919 """)
6920
6922 if self.indexing:
6923 with self.__write_mutex:
6924 self.cursor.executescript("""
6925 CREATE INDEX IF NOT EXISTS baseindex_atom
6926 ON baseinfo ( atom );
6927 CREATE INDEX IF NOT EXISTS baseindex_branch_name
6928 ON baseinfo ( name,branch );
6929 CREATE INDEX IF NOT EXISTS baseindex_branch_name_idcategory
6930 ON baseinfo ( name,idcategory,branch );
6931 CREATE INDEX IF NOT EXISTS baseindex_idcategory
6932 ON baseinfo ( idcategory );
6933 """)
6934
6936 if self.indexing:
6937 with self.__write_mutex:
6938 self.cursor.execute("""
6939 CREATE INDEX IF NOT EXISTS licensedataindex
6940 ON licensedata ( licensename )
6941 """)
6942
6944 if self.indexing:
6945 with self.__write_mutex:
6946 self.cursor.execute("""
6947 CREATE INDEX IF NOT EXISTS licensesindex ON licenses ( license )
6948 """)
6949
6951 if self.indexing:
6952 with self.__write_mutex:
6953 self.cursor.execute("""
6954 CREATE INDEX IF NOT EXISTS categoriesindex_category
6955 ON categories ( category )
6956 """)
6957
6959 if self.indexing:
6960 with self.__write_mutex:
6961 self.cursor.executescript("""
6962 CREATE INDEX IF NOT EXISTS keywordsreferenceindex
6963 ON keywordsreference ( keywordname );
6964 CREATE INDEX IF NOT EXISTS keywordsindex_idpackage
6965 ON keywords ( idpackage );
6966 CREATE INDEX IF NOT EXISTS keywordsindex_idkeyword
6967 ON keywords ( idkeyword );
6968 """)
6969
6971 if self.indexing:
6972 with self.__write_mutex:
6973 self.cursor.executescript("""
6974 CREATE INDEX IF NOT EXISTS dependenciesindex_idpackage
6975 ON dependencies ( idpackage );
6976 CREATE INDEX IF NOT EXISTS dependenciesindex_iddependency
6977 ON dependencies ( iddependency );
6978 CREATE INDEX IF NOT EXISTS dependenciesreferenceindex_dependency
6979 ON dependenciesreference ( dependency );
6980 """)
6981
6983 if self.indexing:
6984 with self.__write_mutex:
6985 self.cursor.executescript("""
6986 CREATE INDEX IF NOT EXISTS countersindex_idpackage
6987 ON counters ( idpackage );
6988 CREATE INDEX IF NOT EXISTS countersindex_counter
6989 ON counters ( counter );
6990 """)
6991
6993 if self.indexing:
6994 with self.__write_mutex:
6995 self.cursor.executescript("""
6996 CREATE INDEX IF NOT EXISTS sourcesindex_idpackage
6997 ON sources ( idpackage );
6998 CREATE INDEX IF NOT EXISTS sourcesindex_idsource
6999 ON sources ( idsource );
7000 CREATE INDEX IF NOT EXISTS sourcesreferenceindex_source
7001 ON sourcesreference ( source );
7002 """)
7003
7005 if self.indexing:
7006 with self.__write_mutex:
7007 self.cursor.executescript("""
7008 CREATE INDEX IF NOT EXISTS provideindex_idpackage
7009 ON provide ( idpackage );
7010 CREATE INDEX IF NOT EXISTS provideindex_atom
7011 ON provide ( atom );
7012 """)
7013
7015 if self.indexing:
7016 with self.__write_mutex:
7017 self.cursor.executescript("""
7018 CREATE INDEX IF NOT EXISTS conflictsindex_idpackage
7019 ON conflicts ( idpackage );
7020 CREATE INDEX IF NOT EXISTS conflictsindex_atom
7021 ON conflicts ( conflict );
7022 """)
7023
7025 if self.indexing:
7026 with self.__write_mutex:
7027 self.cursor.executescript("""
7028 CREATE INDEX IF NOT EXISTS extrainfoindex
7029 ON extrainfo ( description );
7030 CREATE INDEX IF NOT EXISTS extrainfoindex_pkgindex
7031 ON extrainfo ( idpackage );
7032 """)
7033
7035 if self.indexing:
7036 with self.__write_mutex:
7037 self.cursor.executescript("""
7038 CREATE INDEX IF NOT EXISTS eclassesindex_idpackage
7039 ON eclasses ( idpackage );
7040 CREATE INDEX IF NOT EXISTS eclassesindex_idclass
7041 ON eclasses ( idclass );
7042 CREATE INDEX IF NOT EXISTS eclassesreferenceindex_classname
7043 ON eclassesreference ( classname );
7044 """)
7045
7046 - def dropContentIndex(self, only_file = False):
7047 """
7048 Drop "content" metadata index.
7049
7050 @keyword only_file: drop only "file" index
7051 @type only_file: bool
7052 """
7053 with self.__write_mutex:
7054 self.cursor.execute("DROP INDEX IF EXISTS contentindex_file")
7055 if not only_file:
7056 self.cursor.executescript("""
7057 DROP INDEX IF EXISTS contentindex_couple;
7058 """)
7059
7061 """
7062 Regenerate Source Package Manager package identifiers table.
7063 This method will use the Source Package Manger interface.
7064
7065 @keyword verbose: run in verbose mode
7066 @type verbose: bool
7067 """
7068
7069
7070 spm = get_spm(self)
7071
7072
7073 with self.__write_mutex:
7074
7075 self.cursor.executescript("""
7076 DROP TABLE IF EXISTS counters_regen;
7077 CREATE TEMPORARY TABLE counters_regen (
7078 counter INTEGER,
7079 idpackage INTEGER,
7080 branch VARCHAR,
7081 PRIMARY KEY(idpackage, branch)
7082 );
7083 """)
7084 insert_data = []
7085 for myid in self.listAllIdpackages():
7086
7087 try:
7088 spm_uid = spm.resolve_package_uid(self, myid)
7089 except SPMError as err:
7090 if verbose:
7091 mytxt = "%s: %s: %s" % (
7092 bold(_("ATTENTION")),
7093 red(_("Spm error occured")),
7094 str(err),
7095 )
7096 self.updateProgress(
7097 mytxt,
7098 importance = 1,
7099 type = "warning"
7100 )
7101 continue
7102
7103 if spm_uid is None:
7104 if verbose:
7105 mytxt = "%s: %s: %s" % (
7106 bold(_("ATTENTION")),
7107 red(_("Spm Unique Identifier not found for")),
7108 self.retrieveAtom(myid),
7109 )
7110 self.updateProgress(
7111 mytxt,
7112 importance = 1,
7113 type = "warning"
7114 )
7115 continue
7116
7117 mybranch = self.retrieveBranch(myid)
7118 insert_data.append((spm_uid, myid, mybranch))
7119
7120 self.cursor.executemany("""
7121 INSERT OR REPLACE into counters_regen VALUES (?,?,?)
7122 """, insert_data)
7123
7124 self.cursor.executescript("""
7125 DELETE FROM counters;
7126 INSERT INTO counters (counter, idpackage, branch)
7127 SELECT counter, idpackage, branch FROM counters_regen;
7128 """)
7129
7130 self.commitChanges()
7131
7133 """
7134 This method should be considered internal and not suited for general
7135 audience. Clear "treeupdates" metadata for given repository identifier.
7136
7137 @param repository: repository identifier
7138 @type repository: string
7139 """
7140 with self.__write_mutex:
7141 self.cursor.execute("""
7142 DELETE FROM treeupdates WHERE repository = (?)
7143 """, (repository,))
7144 self.commitChanges()
7145
7147 """
7148 This method should be considered internal and not suited for general
7149 audience. Reset "treeupdates" digest metadata.
7150 """
7151 with self.__write_mutex:
7152 self.cursor.execute('UPDATE treeupdates SET digest = "-1"')
7153 self.commitChanges()
7154
7156
7157
7158
7159 tables = ("extrainfo", "dependencies" ,"provide",
7160 "conflicts", "configprotect", "configprotectmask", "sources",
7161 "useflags", "keywords", "content", "messages", "counters", "sizes",
7162 "eclasses", "needed", "triggers", "systempackages", "injected",
7163 "installedtable", "automergefiles", "packagesignatures",
7164 "packagespmphases", "provided_libs", "dependstable"
7165 )
7166
7167 done_something = False
7168 for table in tables:
7169 if not self._doesTableExist(table):
7170 continue
7171
7172 cur = self.cursor.execute("PRAGMA foreign_key_list(%s)" % (table,))
7173 foreign_keys = cur.fetchone()
7174
7175
7176 if foreign_keys is not None:
7177 continue
7178
7179 done_something = True
7180
7181 cur = self.cursor.execute("""SELECT sql FROM sqlite_master
7182 WHERE type='table' and name = (?)""", (table,))
7183 cur_sql = cur.fetchone()[0]
7184
7185
7186 tmp_table = table+"_fk_sup"
7187 self.cursor.execute("DROP TABLE IF EXISTS %s" % (tmp_table,))
7188
7189 bracket_idx = cur_sql.find("(")
7190 cur_sql = cur_sql[bracket_idx:]
7191 cur_sql = "CREATE TABLE %s %s" % (tmp_table, cur_sql)
7192
7193
7194 cur_sql = cur_sql[:-1].strip()
7195
7196 cur_sql += """,
7197 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE );"""
7198 self.cursor.executescript(cur_sql)
7199 self._moveContent(table, tmp_table)
7200 self._atomicRename(tmp_table, table)
7201
7202 if done_something:
7203 self.cursor.execute("""
7204 INSERT OR REPLACE INTO settings
7205 VALUES ("on_delete_cascade", "1")
7206 """)
7207
7208 - def _moveContent(self, from_table, to_table):
7209 self.cursor.execute("""
7210 INSERT INTO %s SELECT * FROM %s
7211 """ % (to_table, from_table,))
7212
7214 self.cursor.executescript("""
7215 BEGIN TRANSACTION;
7216 DROP TABLE IF EXISTS %s;
7217 ALTER TABLE %s RENAME TO %s;
7218 COMMIT;
7219 """ % (to_table, from_table, to_table,))
7220
7222 with self.__write_mutex:
7223 self.cursor.executescript("""
7224 DROP TABLE IF EXISTS counterstemp;
7225 CREATE TABLE counterstemp (
7226 counter INTEGER, idpackage INTEGER, branch VARCHAR,
7227 PRIMARY KEY(idpackage,branch),
7228 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
7229 );
7230 INSERT INTO counterstemp (counter, idpackage, branch)
7231 SELECT counter, idpackage, branch FROM counters;
7232 DROP TABLE counters;
7233 ALTER TABLE counterstemp RENAME TO counters;
7234 """)
7235 self.commitChanges()
7236
7238 with self.__write_mutex:
7239 self.cursor.executescript("""
7240 CREATE TABLE settings (
7241 setting_name VARCHAR,
7242 setting_value VARCHAR,
7243 PRIMARY KEY(setting_name)
7244 );
7245 """)
7246 self._setupInitialSettings()
7247
7249
7250 def do_create():
7251 self.cursor.executescript("""
7252 CREATE TABLE provided_libs (
7253 idpackage INTEGER,
7254 library VARCHAR,
7255 path VARCHAR,
7256 elfclass INTEGER,
7257 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
7258 );
7259 """)
7260
7261
7262 client_repo = self.get_plugins_metadata().get('client_repo')
7263 with self.__write_mutex:
7264
7265 if client_repo and (self.dbname != etpConst['clientdbid']):
7266 return do_create()
7267
7268 mytxt = "%s: %s" % (
7269 bold(_("ATTENTION")),
7270 red(_("generating provided_libs metadata, please wait!")),
7271 )
7272 self.updateProgress(
7273 mytxt,
7274 importance = 1,
7275 type = "warning"
7276 )
7277
7278 try:
7279 self._generateProvidedLibsMetadata()
7280 except (IOError, OSError, self.dbapi2.Error) as err:
7281 mytxt = "%s: %s: [%s]" % (
7282 bold(_("ATTENTION")),
7283 red("cannot generate provided_libs metadata"),
7284 err,
7285 )
7286 self.updateProgress(
7287 mytxt,
7288 importance = 1,
7289 type = "warning"
7290 )
7291 do_create()
7292
7293
7325
7326 self.cursor.executescript("""
7327 DROP TABLE IF EXISTS provided_libs_tmp;
7328 CREATE TABLE provided_libs_tmp (
7329 idpackage INTEGER,
7330 library VARCHAR,
7331 path VARCHAR,
7332 elfclass INTEGER,
7333 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
7334 );
7335 """)
7336
7337 pkgs = self.listAllIdpackages()
7338 for idpackage in pkgs:
7339
7340 content = self.retrieveContent(idpackage, extended = True,
7341 formatted = True)
7342 provided_libs = collect_provided(etpConst['systemroot'], content)
7343
7344 self.cursor.executemany("""
7345 INSERT INTO provided_libs_tmp VALUES (?,?,?,?)
7346 """, [(idpackage, x, y, z,) for x, y, z in provided_libs])
7347
7348
7349 self.cursor.execute("""
7350 ALTER TABLE provided_libs_tmp RENAME TO provided_libs;
7351 """)
7352
7354 self.cursor.execute("""
7355 ALTER TABLE provide ADD COLUMN is_default INTEGER DEFAULT 0
7356 """)
7357
7359 with self.__write_mutex:
7360 self.cursor.execute("""
7361 ALTER TABLE installedtable ADD source INTEGER;
7362 """)
7363 self.cursor.execute("""
7364 UPDATE installedtable SET source = (?)
7365 """, (etpConst['install_sources']['unknown'],))
7366
7368 with self.__write_mutex:
7369 self.cursor.execute("""
7370 CREATE TABLE packagechangelogs ( category VARCHAR,
7371 name VARCHAR, changelog BLOB, PRIMARY KEY (category, name));
7372 """)
7373
7375 with self.__write_mutex:
7376 self.cursor.execute("""
7377 CREATE TABLE automergefiles ( idpackage INTEGER,
7378 configfile VARCHAR, md5 VARCHAR,
7379 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE );
7380 """)
7381
7383 with self.__write_mutex:
7384 self.cursor.execute("""
7385 CREATE TABLE packagesignatures (
7386 idpackage INTEGER PRIMARY KEY,
7387 sha1 VARCHAR,
7388 sha256 VARCHAR,
7389 sha512 VARCHAR,
7390 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE );
7391 """)
7392
7394 with self.__write_mutex:
7395 self.cursor.execute("""
7396 CREATE TABLE packagespmphases (
7397 idpackage INTEGER PRIMARY KEY,
7398 phases VARCHAR,
7399 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
7400 );
7401 """)
7402
7404 with self.__write_mutex:
7405 self.cursor.execute("""
7406 CREATE TABLE packagespmrepository (
7407 idpackage INTEGER PRIMARY KEY,
7408 repository VARCHAR,
7409 FOREIGN KEY(idpackage) REFERENCES baseinfo(idpackage) ON DELETE CASCADE
7410 );
7411 """)
7412
7414 with self.__write_mutex:
7415 self.cursor.execute("""
7416 CREATE TABLE entropy_branch_migration (
7417 repository VARCHAR,
7418 from_branch VARCHAR,
7419 to_branch VARCHAR,
7420 post_migration_md5sum VARCHAR,
7421 post_upgrade_md5sum VARCHAR,
7422 PRIMARY KEY (repository, from_branch, to_branch)
7423 );
7424 """)
7425
7427 with self.__write_mutex:
7428 self.cursor.execute("""
7429 CREATE TABLE packagesets ( setname VARCHAR, dependency VARCHAR );
7430 """)
7431
7433 with self.__write_mutex:
7434 self.cursor.execute("""
7435 CREATE TABLE categoriesdescription ( category VARCHAR,
7436 locale VARCHAR, description VARCHAR );
7437 """)
7438
7440 with self.__write_mutex:
7441 self.cursor.execute("""
7442 CREATE TABLE licensedata ( licensename VARCHAR UNIQUE,
7443 text BLOB, compressed INTEGER );
7444 """)
7445
7447 with self.__write_mutex:
7448 self.cursor.execute("""
7449 CREATE TABLE licenses_accepted ( licensename VARCHAR UNIQUE );
7450 """)
7451
7453 with self.__write_mutex:
7454 self.cursor.executemany('INSERT into dependstable VALUES (?,?)',
7455 iterable)
7456
7469
7521
7523 """
7524 Note: this is not intended for general audience.
7525 Move "branch" metadata contained in Source Package Manager package
7526 identifiers binding metadata to new value given by "from_branch"
7527 argument.
7528
7529 @param to_branch:
7530 @type to_branch:
7531 @keyword from_branch:
7532 @type from_branch:
7533 @return:
7534 @rtype:
7535
7536 """
7537 with self.__write_mutex:
7538 if from_branch is not None:
7539 self.cursor.execute("""
7540 UPDATE counters SET branch = (?) WHERE branch = (?)
7541 """, (to_branch, from_branch,))
7542 else:
7543 self.cursor.execute("""
7544 UPDATE counters SET branch = (?)
7545 """, (to_branch,))
7546 self.commitChanges()
7547 self.clearCache()
7548
7550 if self.xcache:
7551 ck_sum = hash(self.checksum())
7552 cached = self.dumpTools.loadobj("%s/%s/%s_%s" % (
7553 self.dbMatchCacheKey, self.dbname, ck_sum, hash(tuple(args)),))
7554 if cached is not None:
7555 return cached
7556
7558 if self.xcache:
7559 ck_sum = hash(self.checksum(strict = False))
7560 self.Cacher.push("%s/%s/%s_%s" % (
7561 self.dbMatchCacheKey, self.dbname, ck_sum, hash(tuple(args)),),
7562 kwargs.get('result')
7563 )
7564
7566
7567
7568 data, rc = cached_obj
7569 if rc != 0:
7570 return cached_obj
7571
7572
7573 if not self.entropyTools.isnumber(data):
7574 return None
7575
7576 if (not extendedResults) and (not multiMatch):
7577 if not self.isIdpackageAvailable(data):
7578 return None
7579
7580 elif extendedResults and (not multiMatch):
7581 if not self.isIdpackageAvailable(data[0]):
7582 return None
7583
7584 elif extendedResults and multiMatch:
7585 idpackages = set([x[0] for x in data])
7586 if not self.areIdpackagesAvailable(idpackages):
7587 return None
7588
7589 elif (not extendedResults) and multiMatch:
7590
7591 idpackages = set(data)
7592 if not self.areIdpackagesAvailable(idpackages):
7593 return None
7594
7595 return cached_obj
7596
7598
7599 ref = self.SystemSettings['pkg_masking_reference']
7600 if (idpackage, reponame) in \
7601 self.SystemSettings['live_packagemasking']['mask_matches']:
7602
7603
7604 return -1, ref['user_live_mask']
7605
7606 elif (idpackage, reponame) in \
7607 self.SystemSettings['live_packagemasking']['unmask_matches']:
7608
7609 return idpackage, ref['user_live_unmask']
7610
7612
7613 mykw = "%smask_ids" % (reponame,)
7614 user_package_mask_ids = self.SystemSettings.get(mykw)
7615
7616 if not isinstance(user_package_mask_ids, (list, set)):
7617 user_package_mask_ids = set()
7618
7619 for atom in self.SystemSettings['mask']:
7620 matches, r = self.atomMatch(atom, multiMatch = True,
7621 packagesFilter = False)
7622 if r != 0:
7623 continue
7624 user_package_mask_ids |= set(matches)
7625
7626 self.SystemSettings[mykw] = user_package_mask_ids
7627
7628 if idpackage in user_package_mask_ids:
7629
7630 ref = self.SystemSettings['pkg_masking_reference']
7631 myr = ref['user_package_mask']
7632
7633 try:
7634
7635 cl_data = self.SystemSettings[self.client_settings_plugin_id]
7636 validator_cache = cl_data['masking_validation']['cache']
7637 validator_cache[(idpackage, reponame, live)] = -1, myr
7638
7639 except KeyError:
7640 pass
7641
7642 return -1, myr
7643
7646
7647
7648
7649 mykw = "%sunmask_ids" % (reponame,)
7650 user_package_unmask_ids = self.SystemSettings.get(mykw)
7651
7652 if not isinstance(user_package_unmask_ids, (list, set)):
7653
7654 user_package_unmask_ids = set()
7655 for atom in self.SystemSettings['unmask']:
7656 matches, r = self.atomMatch(atom, multiMatch = True,
7657 packagesFilter = False)
7658 if r != 0:
7659 continue
7660 user_package_unmask_ids |= set(matches)
7661
7662 self.SystemSettings[mykw] = user_package_unmask_ids
7663
7664 if idpackage in user_package_unmask_ids:
7665
7666 ref = self.SystemSettings['pkg_masking_reference']
7667 myr = ref['user_package_unmask']
7668 try:
7669
7670 cl_data = self.SystemSettings[self.client_settings_plugin_id]
7671 validator_cache = cl_data['masking_validation']['cache']
7672 validator_cache[(idpackage, reponame, live)] = idpackage, myr
7673
7674 except KeyError:
7675 pass
7676
7677 return idpackage, myr
7678
7680
7681
7682 repos_mask = {}
7683 client_plg_id = etpConst['system_settings_plugins_ids']['client_plugin']
7684 client_settings = self.SystemSettings.get(client_plg_id, {})
7685 if client_settings:
7686 repos_mask = client_settings['repositories']['mask']
7687
7688 repomask = repos_mask.get(reponame)
7689 if isinstance(repomask, (list, set)):
7690
7691
7692
7693 mask_repo_id = "%s_ids@@:of:%s" % (reponame, reponame,)
7694 repomask_ids = repos_mask.get(mask_repo_id)
7695
7696 if not isinstance(repomask_ids, set):
7697 repomask_ids = set()
7698 for atom in repomask:
7699 matches, r = self.atomMatch(atom, multiMatch = True,
7700 packagesFilter = False)
7701 if r != 0:
7702 continue
7703 repomask_ids |= set(matches)
7704 repos_mask[mask_repo_id] = repomask_ids
7705
7706 if idpackage in repomask_ids:
7707
7708 ref = self.SystemSettings['pkg_masking_reference']
7709 myr = ref['repository_packages_db_mask']
7710
7711 try:
7712
7713 plg_id = self.client_settings_plugin_id
7714 cl_data = self.SystemSettings[plg_id]
7715 validator_cache = cl_data['masking_validation']['cache']
7716 validator_cache[(idpackage, reponame, live)] = -1, myr
7717
7718 except KeyError:
7719 pass
7720
7721 return -1, myr
7722
7725
7726 if not self.SystemSettings['license_mask']:
7727 return
7728
7729 mylicenses = self.retrieveLicense(idpackage)
7730 mylicenses = mylicenses.strip().split()
7731 lic_mask = self.SystemSettings['license_mask']
7732 for mylicense in mylicenses:
7733
7734 if mylicense not in lic_mask:
7735 continue
7736
7737 ref = self.SystemSettings['pkg_masking_reference']
7738 myr = ref['user_license_mask']
7739 try:
7740
7741 cl_data = self.SystemSettings[self.client_settings_plugin_id]
7742 validator_cache = cl_data['masking_validation']['cache']
7743 validator_cache[(idpackage, reponame, live)] = -1, myr
7744
7745 except KeyError:
7746 pass
7747
7748 return -1, myr
7749
7751
7752
7753
7754 mykeywords = self.retrieveKeywords(idpackage) or set([''])
7755
7756 mask_ref = self.SystemSettings['pkg_masking_reference']
7757
7758
7759
7760 same_keywords = etpConst['keywords'] & mykeywords
7761 if same_keywords:
7762 myr = mask_ref['system_keyword']
7763 try:
7764
7765 cl_data = self.SystemSettings[self.client_settings_plugin_id]
7766 validator_cache = cl_data['masking_validation']['cache']
7767 validator_cache[(idpackage, reponame, live)] = idpackage, myr
7768
7769 except KeyError:
7770 pass
7771
7772 return idpackage, myr
7773
7774
7775
7776
7777
7778 keyword_repo = self.SystemSettings['keywords']['repositories']
7779
7780 for keyword in list(keyword_repo.get(reponame, {}).keys()):
7781
7782 if keyword not in mykeywords:
7783 continue
7784
7785 keyword_data = keyword_repo[reponame].get(keyword)
7786 if not keyword_data:
7787 continue
7788
7789 if "*" in keyword_data:
7790
7791 myr = mask_ref['user_repo_package_keywords_all']
7792 try:
7793
7794 plg_id = self.client_settings_plugin_id
7795 cl_data = self.SystemSettings[plg_id]
7796 validator_cache = cl_data['masking_validation']['cache']
7797 validator_cache[(idpackage, reponame, live)] = \
7798 idpackage, myr
7799
7800 except KeyError:
7801 pass
7802
7803 return idpackage, myr
7804
7805 kwd_key = "%s_ids" % (keyword,)
7806 keyword_data_ids = keyword_repo[reponame].get(kwd_key)
7807 if not isinstance(keyword_data_ids, set):
7808
7809 keyword_data_ids = set()
7810 for atom in keyword_data:
7811 matches, r = self.atomMatch(atom, multiMatch = True,
7812 packagesFilter = False)
7813 if r != 0:
7814 continue
7815 keyword_data_ids |= matches
7816
7817 keyword_repo[reponame][kwd_key] = keyword_data_ids
7818
7819 if idpackage in keyword_data_ids:
7820
7821 myr = mask_ref['user_repo_package_keywords']
7822 try:
7823
7824 plg_id = self.client_settings_plugin_id
7825 cl_data = self.SystemSettings[plg_id]
7826 validator_cache = cl_data['masking_validation']['cache']
7827 validator_cache[(idpackage, reponame, live)] = \
7828 idpackage, myr
7829
7830 except KeyError:
7831 pass
7832 return idpackage, myr
7833
7834 keyword_pkg = self.SystemSettings['keywords']['packages']
7835
7836
7837
7838 for keyword in list(keyword_pkg.keys()):
7839
7840
7841
7842 if keyword not in mykeywords:
7843 continue
7844
7845 keyword_data = keyword_pkg.get(keyword)
7846 if not keyword_data:
7847 continue
7848
7849 kwd_key = "%s_ids" % (keyword,)
7850 keyword_data_ids = keyword_pkg.get(reponame+kwd_key)
7851
7852 if not isinstance(keyword_data_ids, (list, set)):
7853 keyword_data_ids = set()
7854 for atom in keyword_data:
7855
7856 matches, r = self.atomMatch(atom, multiMatch = True,
7857 packagesFilter = False)
7858 if r != 0:
7859 continue
7860 keyword_data_ids |= matches
7861
7862 keyword_pkg[reponame+kwd_key] = keyword_data_ids
7863
7864 if idpackage in keyword_data_ids:
7865
7866
7867 myr = mask_ref['user_package_keywords']
7868 try:
7869
7870 plg_id = self.client_settings_plugin_id
7871 cl_data = self.SystemSettings[plg_id]
7872 validator_cache = cl_data['masking_validation']['cache']
7873 validator_cache[(idpackage, reponame, live)] = \
7874 idpackage, myr
7875
7876 except KeyError:
7877 pass
7878
7879 return idpackage, myr
7880
7881
7882
7883
7884
7885
7886
7887 plg_id = self.client_settings_plugin_id
7888 cl_data = self.SystemSettings.get(plg_id)
7889 if cl_data is None:
7890
7891 return
7892
7893 repo_keywords = cl_data['repositories']['repos_keywords'].get(reponame)
7894 if repo_keywords is None:
7895
7896 return
7897
7898
7899 same_keywords = repo_keywords.get('universal') & mykeywords
7900 if same_keywords:
7901
7902 myr = mask_ref['repository_packages_db_keywords']
7903 validator_cache = cl_data['masking_validation']['cache']
7904 validator_cache[(idpackage, reponame, live)] = \
7905 idpackage, myr
7906 return idpackage, myr
7907
7908
7909
7910 repo_settings = repo_keywords.get('packages')
7911 if not repo_settings:
7912
7913 return
7914
7915 cached_key = "packages_ids"
7916 keyword_data_ids = repo_keywords.get(cached_key)
7917 if not isinstance(keyword_data_ids, dict):
7918
7919
7920 keyword_data_ids = {}
7921 for atom, values in list(repo_settings.items()):
7922 matches, r = self.atomMatch(atom, multiMatch = True,
7923 packagesFilter = False)
7924 if r != 0:
7925 continue
7926 for match in matches:
7927 obj = keyword_data_ids.setdefault(match, set())
7928 obj.update(values)
7929
7930 repo_keywords[cached_key] = keyword_data_ids
7931
7932 same_keywords = keyword_data_ids.get(idpackage, set()) & \
7933 etpConst['keywords']
7934 if same_keywords:
7935
7936 myr = mask_ref['repository_packages_db_keywords']
7937 validator_cache = cl_data['masking_validation']['cache']
7938 validator_cache[(idpackage, reponame, live)] = \
7939 idpackage, myr
7940 return idpackage, myr
7941
7942
7944 """
7945 Return whether given package identifier is available to user or not,
7946 reading package masking metadata stored in SystemSettings.
7947
7948 @param idpackage: package indentifier
7949 @type idpackage: int
7950 @keyword live: use live masking feature
7951 @type live: bool
7952 @return: tuple composed by idpackage and masking reason. If idpackage
7953 returned idpackage value == -1, it means that package is masked
7954 and a valid masking reason identifier is returned as second
7955 value of the tuple (see SystemSettings['pkg_masking_reasons'])
7956 @rtype: tuple
7957 """
7958
7959 if self.dbname == etpConst['clientdbid']:
7960 return idpackage, 0
7961
7962
7963
7964
7965
7966 client_repo = self.get_plugins_metadata().get('client_repo')
7967 if not client_repo:
7968
7969 return idpackage, 0
7970
7971 reponame = self.dbname[len(etpConst['dbnamerepoprefix']):]
7972 try:
7973 cl_data = self.SystemSettings[self.client_settings_plugin_id]
7974 validator_cache = cl_data['masking_validation']['cache']
7975
7976 cached = validator_cache.get((idpackage, reponame, live))
7977 if cached is not None:
7978 return cached
7979
7980
7981 if len(validator_cache) > 10000:
7982 validator_cache.clear()
7983
7984 except KeyError:
7985 pass
7986
7987 if live:
7988 data = self._idpackageValidator_live(idpackage, reponame)
7989 if data:
7990 return data
7991
7992 data = self._idpackageValidator_user_package_mask(idpackage,
7993 reponame, live)
7994 if data:
7995 return data
7996
7997 data = self._idpackageValidator_user_package_unmask(idpackage,
7998 reponame, live)
7999 if data:
8000 return data
8001
8002 data = self._idpackageValidator_packages_db_mask(idpackage, reponame,
8003 live)
8004 if data:
8005 return data
8006
8007 data = self._idpackageValidator_package_license_mask(idpackage,
8008 reponame, live)
8009 if data:
8010 return data
8011
8012 data = self._idpackageValidator_keyword_mask(idpackage, reponame, live)
8013 if data:
8014 return data
8015
8016
8017 myr = self.SystemSettings['pkg_masking_reference']['completely_masked']
8018 validator_cache[(idpackage, reponame, live)] = -1, myr
8019 return -1, myr
8020
8021
8023 """
8024 Packages filter used by atomMatch, input must me foundIDs,
8025 a list like this: [608, 1867].
8026
8027 """
8028
8029
8030
8031
8032 if not self.dbname.startswith(etpConst['dbnamerepoprefix']):
8033 return results
8034
8035 newresults = set()
8036 for idpackage in results:
8037 idpackage, reason = self.idpackageValidator(idpackage)
8038 if idpackage == -1:
8039 continue
8040 newresults.add(idpackage)
8041 return newresults
8042
8044 if slot is None:
8045 return idpackage
8046 dbslot = self.retrieveSlot(idpackage)
8047 if dbslot == slot:
8048 return idpackage
8049
8051 if tag is None:
8052 return idpackage
8053 dbtag = self.retrieveVersionTag(idpackage)
8054 compare = const_cmp(tag, dbtag)
8055 if not operators or operators == "=":
8056 if compare == 0:
8057 return idpackage
8058 else:
8059 return self.__do_operator_compare(idpackage, operators, compare)
8060
8062 if not use:
8063 return idpackage
8064 pkguse = self.retrieveUseflags(idpackage)
8065 disabled = set([x[1:] for x in use if x.startswith("-")])
8066 enabled = set([x for x in use if not x.startswith("-")])
8067 enabled_not_satisfied = enabled - pkguse
8068
8069 if enabled_not_satisfied:
8070 return None
8071
8072 disabled_not_satisfied = disabled - pkguse
8073 if len(disabled_not_satisfied) != len(disabled):
8074 return None
8075 return idpackage
8076
8078 if operators == ">" and compare == -1:
8079 return token
8080 elif operators == ">=" and compare < 1:
8081 return token
8082 elif operators == "<" and compare == 1:
8083 return token
8084 elif operators == "<=" and compare > -1:
8085 return token
8086
8088
8089 def myfilter(idpackage):
8090
8091 idpackage = self.__filterSlot(idpackage, slot)
8092 if not idpackage:
8093 return False
8094
8095 idpackage = self.__filterUse(idpackage, use)
8096 if not idpackage:
8097 return False
8098
8099 idpackage = self.__filterTag(idpackage, tag, operators)
8100 if not idpackage:
8101 return False
8102
8103 return True
8104
8105 return set(filter(myfilter, foundIDs))
8106
8107 - def atomMatch(self, atom, caseSensitive = True, matchSlot = None,
8108 multiMatch = False, matchTag = None, matchUse = (),
8109 packagesFilter = True, matchRevision = None, extendedResults = False,
8110 useCache = True):
8111
8112 """
8113 Match given atom (or dependency) in repository and return its package
8114 identifer and execution status.
8115
8116 @param atom: atom or dependency to match in repository
8117 @type atom: unicode string
8118 @keyword caseSensitive: match in case sensitive mode
8119 @type caseSensitive: bool
8120 @keyword matchSlot: match packages with given slot
8121 @type matchSlot: string
8122 @keyword multiMatch: match all the available packages, not just the
8123 best one
8124 @type multiMatch: bool
8125 @keyword matchTag: match packages with given tag
8126 @type matchTag: string
8127 @keyword matchUse: match packages with given use flags
8128 @type matchUse: list or tuple or set
8129 @keyword packagesFilter: enable package masking filter
8130 @type packagesFilter: bool
8131 @keyword matchRevision: match packages with given entropy revision
8132 @type matchRevision: int
8133 @keyword extendedResults: return extended results
8134 @type extendedResults: bool
8135 @keyword useCache: use on-disk cache
8136 @type useCache: bool
8137 @return: tuple of length 2 composed by (idpackage or -1, command status
8138 (0 means found, 1 means error)) or, if extendedResults is True,
8139 also add versioning information to tuple.
8140 If multiMatch is True, a tuple composed by a set (containing package
8141 identifiers) and command status is returned.
8142 @rtype: tuple or set
8143 @todo: improve documentation here
8144 """
8145
8146 if not atom:
8147 return -1, 1
8148
8149 if useCache:
8150 cached = self.__atomMatchFetchCache(
8151 atom, caseSensitive, matchSlot,
8152 multiMatch, matchTag,
8153 matchUse, packagesFilter, matchRevision,
8154 extendedResults
8155 )
8156 if isinstance(cached, tuple):
8157
8158 try:
8159 cached = self.__atomMatchValidateCache(cached,
8160 multiMatch, extendedResults)
8161 except (TypeError, ValueError, IndexError, KeyError,):
8162 cached = None
8163
8164 if isinstance(cached, tuple):
8165 return cached
8166
8167 atomTag = self.entropyTools.dep_gettag(atom)
8168 try:
8169 atomUse = self.entropyTools.dep_getusedeps(atom)
8170 except InvalidAtom:
8171 atomUse = ()
8172 atomSlot = self.entropyTools.dep_getslot(atom)
8173 atomRev = self.entropyTools.dep_get_entropy_revision(atom)
8174 if isinstance(atomRev, int):
8175 if atomRev < 0: atomRev = None
8176
8177
8178 scan_atom = self.entropyTools.remove_usedeps(atom)
8179 if (not matchUse) and (atomUse):
8180 matchUse = atomUse
8181
8182
8183 scan_atom = self.entropyTools.remove_tag(scan_atom)
8184 if (matchTag is None) and (atomTag is not None):
8185 matchTag = atomTag
8186
8187
8188 scan_atom = self.entropyTools.remove_slot(scan_atom)
8189 if (matchSlot is None) and (atomSlot is not None):
8190 matchSlot = atomSlot
8191
8192
8193 scan_atom = self.entropyTools.remove_entropy_revision(scan_atom)
8194 if (matchRevision is None) and (atomRev is not None):
8195 matchRevision = atomRev
8196
8197 direction = ''
8198 justname = True
8199 pkgkey = ''
8200 pkgname = ''
8201 pkgcat = ''
8202 pkgversion = ''
8203 strippedAtom = ''
8204 foundIDs = []
8205 dbpkginfo = set()
8206
8207 if scan_atom:
8208
8209 while True:
8210
8211 strippedAtom = self.entropyTools.dep_getcpv(scan_atom)
8212 if scan_atom[-1] == "*":
8213 strippedAtom += "*"
8214 direction = scan_atom[0:-len(strippedAtom)]
8215
8216 justname = self.entropyTools.isjustname(strippedAtom)
8217 pkgkey = strippedAtom
8218 if justname == 0:
8219
8220 data = self.entropyTools.catpkgsplit(strippedAtom)
8221 if data is None:
8222 break
8223 pkgversion = data[2]+"-"+data[3]
8224 pkgkey = self.entropyTools.dep_getkey(strippedAtom)
8225
8226 splitkey = pkgkey.split("/")
8227 if (len(splitkey) == 2):
8228 pkgcat, pkgname = splitkey
8229 else:
8230 pkgcat, pkgname = "null", splitkey[0]
8231
8232 break
8233
8234
8235
8236 foundIDs = self.__generate_found_ids_match(pkgkey, pkgname, pkgcat,
8237 caseSensitive, multiMatch)
8238
8239
8240
8241 if foundIDs:
8242 foundIDs = self.__filterSlotTagUse(foundIDs, matchSlot,
8243 matchTag, matchUse, direction)
8244 if packagesFilter:
8245 foundIDs = self._packagesFilter(foundIDs)
8246
8247
8248 if foundIDs:
8249 dbpkginfo = self.__handle_found_ids_match(foundIDs, direction,
8250 matchTag, matchRevision, justname, strippedAtom, pkgversion)
8251
8252 if not dbpkginfo:
8253 if extendedResults:
8254 if multiMatch:
8255 x = set()
8256 else:
8257 x = (-1, 1, None, None, None,)
8258 self.__atomMatchStoreCache(
8259 atom, caseSensitive, matchSlot,
8260 multiMatch, matchTag,
8261 matchUse, packagesFilter, matchRevision,
8262 extendedResults, result = (x, 1)
8263 )
8264 return x, 1
8265 else:
8266 if multiMatch:
8267 x = set()
8268 else:
8269 x = -1
8270 self.__atomMatchStoreCache(
8271 atom, caseSensitive, matchSlot,
8272 multiMatch, matchTag,
8273 matchUse, packagesFilter, matchRevision,
8274 extendedResults, result = (x, 1)
8275 )
8276 return x, 1
8277
8278 if multiMatch:
8279 if extendedResults:
8280 x = set([(x[0], 0, x[1], self.retrieveVersionTag(x[0]), \
8281 self.retrieveRevision(x[0])) for x in dbpkginfo])
8282 self.__atomMatchStoreCache(
8283 atom, caseSensitive, matchSlot,
8284 multiMatch, matchTag,
8285 matchUse, packagesFilter, matchRevision,
8286 extendedResults, result = (x, 0)
8287 )
8288 return x, 0
8289 else:
8290 x = set([x[0] for x in dbpkginfo])
8291 self.__atomMatchStoreCache(
8292 atom, caseSensitive, matchSlot,
8293 multiMatch, matchTag,
8294 matchUse, packagesFilter, matchRevision,
8295 extendedResults, result = (x, 0)
8296 )
8297 return x, 0
8298
8299 if len(dbpkginfo) == 1:
8300 x = dbpkginfo.pop()
8301 if extendedResults:
8302 x = (x[0], 0, x[1], self.retrieveVersionTag(x[0]),
8303 self.retrieveRevision(x[0]),)
8304
8305 self.__atomMatchStoreCache(
8306 atom, caseSensitive, matchSlot,
8307 multiMatch, matchTag,
8308 matchUse, packagesFilter, matchRevision,
8309 extendedResults, result = (x, 0)
8310 )
8311 return x, 0
8312 else:
8313 self.__atomMatchStoreCache(
8314 atom, caseSensitive, matchSlot,
8315 multiMatch, matchTag,
8316 matchUse, packagesFilter, matchRevision,
8317 extendedResults, result = (x[0], 0)
8318 )
8319 return x[0], 0
8320
8321 dbpkginfo = list(dbpkginfo)
8322 pkgdata = {}
8323 versions = set()
8324
8325 for x in dbpkginfo:
8326 info_tuple = (x[1], self.retrieveVersionTag(x[0]), \
8327 self.retrieveRevision(x[0]))
8328 versions.add(info_tuple)
8329 pkgdata[info_tuple] = x[0]
8330
8331 newer = self.entropyTools.get_entropy_newer_version(list(versions))[0]
8332 x = pkgdata[newer]
8333 if extendedResults:
8334 x = (x, 0, newer[0], newer[1], newer[2])
8335 self.__atomMatchStoreCache(
8336 atom, caseSensitive, matchSlot,
8337 multiMatch, matchTag,
8338 matchUse, packagesFilter, matchRevision,
8339 extendedResults, result = (x, 0)
8340 )
8341 return x, 0
8342 else:
8343 self.__atomMatchStoreCache(
8344 atom, caseSensitive, matchSlot,
8345 multiMatch, matchTag,
8346 matchUse, packagesFilter, matchRevision,
8347 extendedResults, result = (x, 0)
8348 )
8349 return x, 0
8350
8353
8354 if pkgcat == "null":
8355 results = self.searchPackagesByName(pkgname,
8356 sensitive = caseSensitive, justid = True)
8357 else:
8358 results = self.searchPackagesByNameAndCategory(name = pkgname,
8359 category = pkgcat, sensitive = caseSensitive, justid = True
8360 )
8361
8362 mypkgcat = pkgcat
8363 mypkgname = pkgname
8364 virtual = False
8365
8366
8367 if (not results) and (mypkgcat == "virtual"):
8368
8369 virtuals = self.searchProvide(pkgkey, justid = True,
8370 get_extended = True)
8371 if virtuals:
8372 virtual = True
8373 flat_virtuals = []
8374 default_virtual = virtuals[0][0]
8375
8376 for v_id, v_is_default in virtuals:
8377 if v_is_default == 1:
8378 default_virtual = v_id
8379 flat_virtuals.append(v_id)
8380 mypkgname = self.retrieveName(default_virtual)
8381 mypkgcat = self.retrieveCategory(default_virtual)
8382 results = flat_virtuals
8383
8384
8385 if not results:
8386 return set()
8387
8388 if len(results) > 1:
8389
8390
8391 foundCat = None
8392 cats = set()
8393 for idpackage in results:
8394 cat = self.retrieveCategory(idpackage)
8395 cats.add(cat)
8396 if (cat == mypkgcat) or ((not virtual) and \
8397 (mypkgcat == "virtual") and (cat == mypkgcat)):
8398
8399
8400 foundCat = cat
8401
8402
8403 if (not foundCat) and (len(cats) == 1) and \
8404 (mypkgcat in ("virtual", "null")):
8405
8406 foundCat = sorted(cats)[0]
8407
8408 if not foundCat:
8409
8410 return set()
8411
8412
8413 mypkgcat = foundCat
8414
8415
8416 if (not multiMatch) and (pkgcat == "null" or virtual):
8417
8418 results = self.searchPackagesByNameAndCategory(
8419 name = mypkgname, category = mypkgcat,
8420 sensitive = caseSensitive, justid = True
8421 )
8422
8423
8424 return set(results)
8425
8426
8427
8428
8429
8430 idpackage = results[0]
8431
8432 if (mypkgcat == "virtual") and (not virtual):
8433
8434
8435 mypkgcat = self.retrieveCategory(idpackage)
8436
8437
8438 if mypkgcat != "null":
8439 foundCat = self.retrieveCategory(idpackage)
8440 if mypkgcat == foundCat:
8441 return set([idpackage])
8442 return set()
8443
8444
8445 return set([idpackage])
8446
8447
8448 - def __handle_found_ids_match(self, foundIDs, direction, matchTag,
8449 matchRevision, justname, strippedAtom, pkgversion):
8450
8451 dbpkginfo = set()
8452
8453 if ((direction) or ((not direction) and (not justname)) or \
8454 ((not direction) and (not justname) \
8455 and strippedAtom.endswith("*"))) and foundIDs:
8456
8457 if (not justname) and \
8458 ((direction == "~") or (direction == "=") or \
8459 ((not direction) and (not justname)) or ((not direction) and \
8460 not justname and strippedAtom.endswith("*"))):
8461
8462
8463
8464 if ((not direction) and (not justname)):
8465 direction = "="
8466
8467
8468 if (direction == "="):
8469 if (pkgversion.split("-")[-1] == "r0"):
8470 pkgversion = self.entropyTools.remove_revision(
8471 pkgversion)
8472
8473 if (direction == "~"):
8474 pkgrevision = self.entropyTools.dep_get_spm_revision(
8475 pkgversion)
8476 pkgversion = self.entropyTools.remove_revision(pkgversion)
8477
8478 for idpackage in foundIDs:
8479
8480 dbver = self.retrieveVersion(idpackage)
8481 if (direction == "~"):
8482 myrev = self.entropyTools.dep_get_spm_revision(
8483 dbver)
8484 myver = self.entropyTools.remove_revision(dbver)
8485 if myver == pkgversion and pkgrevision <= myrev:
8486
8487 dbpkginfo.add((idpackage, dbver))
8488 else:
8489
8490 if pkgversion[-1] == "*":
8491 if dbver.startswith(pkgversion[:-1]):
8492 dbpkginfo.add((idpackage, dbver))
8493 elif (matchRevision is not None) and (pkgversion == dbver):
8494 dbrev = self.retrieveRevision(idpackage)
8495 if dbrev == matchRevision:
8496 dbpkginfo.add((idpackage, dbver))
8497 elif (pkgversion == dbver) and (matchRevision is None):
8498 dbpkginfo.add((idpackage, dbver))
8499
8500 elif (direction.find(">") != -1) or (direction.find("<") != -1):
8501
8502 if not justname:
8503
8504
8505 if pkgversion.endswith("r0"):
8506
8507 self.entropyTools.remove_revision(pkgversion)
8508
8509 for idpackage in foundIDs:
8510
8511 revcmp = 0
8512 tagcmp = 0
8513 if matchRevision is not None:
8514 dbrev = self.retrieveRevision(idpackage)
8515 revcmp = const_cmp(matchRevision, dbrev)
8516
8517 if matchTag is not None:
8518 dbtag = self.retrieveVersionTag(idpackage)
8519 tagcmp = const_cmp(matchTag, dbtag)
8520
8521 dbver = self.retrieveVersion(idpackage)
8522 pkgcmp = self.entropyTools.compare_versions(
8523 pkgversion, dbver)
8524
8525 if pkgcmp is None:
8526 import warnings
8527 warnings.warn("WARNING, invalid version string " + \
8528 "stored in %s: %s <-> %s" % (
8529 self.dbname, pkgversion, dbver,)
8530 )
8531 continue
8532
8533 if direction == ">":
8534
8535 if pkgcmp < 0:
8536 dbpkginfo.add((idpackage, dbver))
8537 elif (matchRevision is not None) and pkgcmp <= 0 \
8538 and revcmp < 0:
8539 dbpkginfo.add((idpackage, dbver))
8540
8541 elif (matchTag is not None) and tagcmp < 0:
8542 dbpkginfo.add((idpackage, dbver))
8543
8544 elif direction == "<":
8545
8546 if pkgcmp > 0:
8547 dbpkginfo.add((idpackage, dbver))
8548 elif (matchRevision is not None) and pkgcmp >= 0 \
8549 and revcmp > 0:
8550 dbpkginfo.add((idpackage, dbver))
8551
8552 elif (matchTag is not None) and tagcmp > 0:
8553 dbpkginfo.add((idpackage, dbver))
8554
8555 elif direction == ">=":
8556
8557 if (matchRevision is not None) and pkgcmp <= 0:
8558 if pkgcmp == 0:
8559 if revcmp <= 0:
8560 dbpkginfo.add((idpackage, dbver))
8561 else:
8562 dbpkginfo.add((idpackage, dbver))
8563 elif pkgcmp <= 0 and matchRevision is None:
8564 dbpkginfo.add((idpackage, dbver))
8565 elif (matchTag is not None) and tagcmp <= 0:
8566 dbpkginfo.add((idpackage, dbver))
8567
8568 elif direction == "<=":
8569
8570 if (matchRevision is not None) and pkgcmp >= 0:
8571 if pkgcmp == 0:
8572 if revcmp >= 0:
8573 dbpkginfo.add((idpackage, dbver))
8574 else:
8575 dbpkginfo.add((idpackage, dbver))
8576 elif pkgcmp >= 0 and matchRevision is None:
8577 dbpkginfo.add((idpackage, dbver))
8578 elif (matchTag is not None) and tagcmp >= 0:
8579 dbpkginfo.add((idpackage, dbver))
8580
8581 else:
8582
8583 dbpkginfo = set([(x, self.retrieveVersion(x),) for x in foundIDs])
8584
8585 return dbpkginfo
8586