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