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