Browse Source

Move DB specific stuff to EixDB

Johann Schmitz 1 year ago
parent
commit
c61d2de4a7
2 changed files with 194 additions and 196 deletions
  1. 194
    2
      peix/__init__.py
  2. 0
    194
      peix/format.py

+ 194
- 2
peix/__init__.py View File

@@ -1,21 +1,213 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 import os
3
-
3
+import collections
4 4
 from peix.format import EixFileFormat
5 5
 
6 6
 
7
+class Package(collections.namedtuple('Package', ['category', 'name', 'description', 'homepage', 'license', 'versions'])):
8
+    def __str__(self):
9
+        return "%s/%s" % (self.category, self.name)
10
+
11
+
12
+class Version(collections.namedtuple('Version', [
13
+    'eapi', 'arch_mask', 'properties_mask', 'restrict_mask', 'keywords', 'version_parts', 'slot', 'overlay', 'uses',
14
+    'depend', 'rdepend', 'pdepend', 'hdepend'
15
+])):
16
+    VTYPE_GARBAGE = 0  # garbage that was found after any valid version string
17
+    VTYPE_ALPHA = 1  # number of "_alpha" (may be empty)
18
+    VTYPE_BETA = 2  # number of "_beta" (may be empty)
19
+    VTYPE_PRE = 3  # number of "_pre" (may be empty)
20
+    VTYPE_RC = 4  # number of "_rc" (may be empty)
21
+    VTYPE_REV = 5  # number of "-r" (may be empty)
22
+    VTYPE_INTER_REV = 6  # number of inter-revision [2]
23
+    VTYPE_PATCH = 7  # number of "_p" (may be empty)
24
+    VTYPE_CHAR = 8  # single character
25
+    VTYPE_PRIMARY = 9  # numeric version part
26
+    VTYPE_FIRST = 10  # first numeric version part
27
+
28
+    def __init__(self, *args, **kwargs):
29
+        super(Version, self).__init__()
30
+        self.version_str = None
31
+
32
+    def __str__(self):
33
+        if self.version_str is None:
34
+            # Prefix	Name
35
+            # "." (dot)	primary, inter_rev
36
+            # "" (empty)	first, char, garbage
37
+            # "_alpha"	alpha
38
+            # "_beta"	beta
39
+            # "_pre"	pre
40
+            # "_rc"	rc
41
+            # "-r"	revision
42
+            # "_p"	patch
43
+            prefixes = {
44
+                Version.VTYPE_PRIMARY: '.',
45
+                Version.VTYPE_INTER_REV: '.',
46
+                Version.VTYPE_FIRST: '',
47
+                Version.VTYPE_CHAR: '',
48
+                Version.VTYPE_GARBAGE: '',
49
+                Version.VTYPE_ALPHA: '_alpha',
50
+                Version.VTYPE_BETA: '_beta',
51
+                Version.VTYPE_PRE: '_pre',
52
+                Version.VTYPE_RC: '_rc',
53
+                Version.VTYPE_REV: '_pre',
54
+                Version.VTYPE_PATCH: '_p',
55
+            }
56
+            self.version_str = ''.join(["%s%s" % (prefixes[vtype], vstr) for vtype, vstr in self.version_parts])
57
+
58
+        return self.version_str
59
+
60
+    @property
61
+    def masked_package_mask(self):
62
+        return self.arch_mask & 0x01 == 0x01
63
+
64
+    @property
65
+    def masked_by_profile(self):
66
+        return self.arch_mask & 0x02 == 0x02
67
+
68
+    @property
69
+    def in_system(self):
70
+        return self.arch_mask & 0x04 == 0x04
71
+
72
+    @property
73
+    def in_world(self):
74
+        return self.arch_mask & 0x08 == 0x08
75
+
76
+    @property
77
+    def in_world_sets(self):
78
+        return self.arch_mask & 0x10 == 0x10
79
+
80
+    @property
81
+    def in_profile(self):
82
+        return self.arch_mask & 0x20 == 0x20
83
+
84
+    restrict_binchecks = property(lambda self: self.restrict_mask & 0x0001 == 0x0001)
85
+    restrict_strip = property(lambda self: self.restrict_mask & 0x0002 == 0x0002)
86
+    restrict_test = property(lambda self: self.restrict_mask & 0x0004 == 0x0004)
87
+    restrict_userpriv = property(lambda self: self.restrict_mask & 0x0008 == 0x0008)
88
+    restrict_installsources = property(lambda self: self.restrict_mask & 0x0010 == 0x0010)
89
+    restrict_fetch = property(lambda self: self.restrict_mask & 0x0020 == 0x0020)
90
+    restrict_mirror = property(lambda self: self.restrict_mask & 0x0040 == 0x0040)
91
+    restrict_primaryuri = property(lambda self: self.restrict_mask & 0x0080 == 0x0080)
92
+    restrict_bindist = property(lambda self: self.restrict_mask & 0x0100 == 0x0100)
93
+    restrict_parallel = property(lambda self: self.restrict_mask & 0x0200 == 0x0200)
94
+
95
+
7 96
 class EixDB(EixFileFormat):
8 97
     
9 98
     def __init__(self, cache_file):
10 99
         super(EixDB, self).__init__()
100
+        self.dependencies_stored = False
101
+        self.required_use_stored = False
102
+        self.depend = None
103
+        self.no_categories = None
104
+        self.overlays = self.eapi = self.licenses = self.keywords = self.use_flags = self.slots = self.world_sets \
105
+            = self.packages = None
11 106
         self.cache_file = cache_file
12 107
     
13 108
     def read(self):
14 109
         try:
15 110
             self.fd = os.open(self.cache_file, os.O_RDONLY)
16 111
             
17
-            self.read_header()
112
+            self.read_database()
18 113
             
19 114
         finally:
20 115
             if self.fd:
21 116
                 os.close(self.fd)
117
+
118
+    def read_database(self):
119
+        self.read_magic()
120
+        self.file_format_version = self.read_number()
121
+        self.no_categories = self.read_number()
122
+        self.overlays = self.read_overlays()
123
+        self.eapi = self.read_hash()
124
+        self.licenses = self.read_hash()
125
+        self.keywords = self.read_hash()
126
+        self.use_flags = self.read_hash()
127
+        self.slots = self.read_hash()
128
+        self.world_sets = self.read_hash()
129
+
130
+        flags = self.read_number()
131
+        self.dependencies_stored = flags & 0x01 == 0x01
132
+        self.required_use_stored = flags & 0x02 == 0x02
133
+
134
+        depend_hash_length = self.read_number()
135
+        self.depend = self.read_hash()
136
+
137
+        self.packages = self.read_packages()
138
+
139
+
140
+    def read_overlay(self):
141
+        return self.read_string(), self.read_string()
142
+
143
+    def read_overlays(self):
144
+        return self.read_vector(self.read_overlay)
145
+
146
+    def read_packages(self):
147
+
148
+        def _inner():
149
+            for _ in range(0, self.no_categories):
150
+                category = self.read_string()
151
+                for p in self.read_vector(lambda: self.read_package(category)):
152
+                    yield p
153
+
154
+        return list(_inner())
155
+
156
+    def read_version(self):
157
+        eapi = self.eapi[self.read_number()]
158
+        mask_bitmask = self.read_number()
159
+        prop_bitmask = self.read_number()
160
+        restrict_bitmask = self.read_number()
161
+        keywords = self.read_hashed_words(self.keywords)
162
+        version_parts = self.read_vector(self.read_version_part)
163
+        slot = self.read_hashed_string(self.slots)
164
+        overlay_idx = self.read_number()
165
+        use_flags = self.read_hashed_words(self.use_flags)
166
+        required_use = self.read_hashed_words(self.use_flags)
167
+
168
+        depend = None
169
+        rdepend = None
170
+        pdepend = None
171
+        hdepend = None
172
+
173
+        if self.dependencies_stored:
174
+            self.read_number()
175
+            depend = self.read_hashed_words(self.depend)
176
+            rdepend = self.read_hashed_words(self.depend)
177
+            pdepend = self.read_hashed_words(self.depend)
178
+            hdepend = self.read_hashed_words(self.depend)
179
+
180
+        return Version(eapi, mask_bitmask, prop_bitmask, restrict_bitmask, keywords, version_parts, slot or '0', self.overlays[overlay_idx],
181
+                       use_flags, depend, rdepend, pdepend, hdepend)
182
+
183
+    def read_package(self, category_name):
184
+        offset_to_next = self.read_number()
185
+
186
+        name = self.read_string()
187
+        desc = self.read_string()
188
+        homepage = self.read_string()
189
+        license = self.licenses[self.read_number()]
190
+        versions = self.read_vector(self.read_version)
191
+        return Package(category_name, name, desc, homepage, license, versions)
192
+
193
+    def read_version_part(self):
194
+        # A VersionPart consists of two data: a number (referred to as type) and a "string" (referred to as value).
195
+        # The number is encoded in the lower 5 bits of the length-part of the "string"; of course, the actual length is
196
+        # shifted by the same number of bits.
197
+
198
+        # A version string '0.9.1-r1' is split into the following parts:
199
+
200
+        # 10 (first):  0
201
+        # 9 (primary): 9
202
+        # 9:           1
203
+        # 5 (rev)      -r1
204
+
205
+        num = self.read_number()
206
+
207
+        # remove the lower bits of `num` by shifting everything to the right
208
+        str_len = num >> 5
209
+        # extract the type (lower 5 bits) by masking out the `str_len` (the lower 5 bits)
210
+        vp_type = num & ~(str_len << 5)
211
+
212
+        buf = os.read(self.fd, str_len)
213
+        return vp_type, buf.decode('utf-8')

+ 0
- 194
peix/format.py View File

@@ -1,97 +1,5 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 import os
3
-import collections
4
-
5
-
6
-class Package(collections.namedtuple('Package', ['category', 'name', 'description', 'homepage', 'license', 'versions'])):
7
-    
8
-    def __str__(self):
9
-        return "%s/%s" % (self.category, self.name)
10
-
11
-
12
-class Version(collections.namedtuple('Version', [
13
-    'eapi', 'arch_mask', 'properties_mask', 'restrict_mask', 'keywords', 'version_parts', 'slot', 'overlay', 'uses',
14
-    'depend', 'rdepend', 'pdepend', 'hdepend'
15
-])):
16
-    
17
-    VTYPE_GARBAGE = 0 # garbage that was found after any valid version string
18
-    VTYPE_ALPHA = 1	# number of "_alpha" (may be empty)
19
-    VTYPE_BETA = 2	# number of "_beta" (may be empty)
20
-    VTYPE_PRE = 3 # number of "_pre" (may be empty)
21
-    VTYPE_RC = 4 # number of "_rc" (may be empty)
22
-    VTYPE_REV = 5 # number of "-r" (may be empty)
23
-    VTYPE_INTER_REV = 6	# number of inter-revision [2]
24
-    VTYPE_PATCH = 7	# number of "_p" (may be empty)
25
-    VTYPE_CHAR = 8 # single character
26
-    VTYPE_PRIMARY = 9 # numeric version part
27
-    VTYPE_FIRST = 10 #first numeric version part
28
-    
29
-    def __init__(self, *args, **kwargs):
30
-        super(Version, self).__init__()
31
-        self.version_str = None
32
-    
33
-    def __str__(self):
34
-        if self.version_str is None:
35
-            # Prefix	Name
36
-            # "." (dot)	primary, inter_rev
37
-            # "" (empty)	first, char, garbage
38
-            # "_alpha"	alpha
39
-            # "_beta"	beta
40
-            # "_pre"	pre
41
-            # "_rc"	rc
42
-            # "-r"	revision
43
-            # "_p"	patch
44
-            prefixes = {
45
-                Version.VTYPE_PRIMARY: '.',
46
-                Version.VTYPE_INTER_REV: '.',
47
-                Version.VTYPE_FIRST: '',
48
-                Version.VTYPE_CHAR: '',
49
-                Version.VTYPE_GARBAGE: '',
50
-                Version.VTYPE_ALPHA: '_alpha',
51
-                Version.VTYPE_BETA: '_beta',
52
-                Version.VTYPE_PRE: '_pre',
53
-                Version.VTYPE_RC: '_rc',
54
-                Version.VTYPE_REV: '_pre',
55
-                Version.VTYPE_PATCH: '_p',
56
-            }
57
-            self.version_str = ''.join(["%s%s" % (prefixes[vtype], vstr) for vtype, vstr in self.version_parts])
58
-        
59
-        return self.version_str
60
-
61
-    @property
62
-    def masked_package_mask(self):
63
-        return self.arch_mask & 0x01 == 0x01
64
-    
65
-    @property
66
-    def masked_by_profile(self):
67
-        return self.arch_mask & 0x02 == 0x02
68
-    
69
-    @property
70
-    def in_system(self):
71
-        return self.arch_mask & 0x04 == 0x04
72
-
73
-    @property
74
-    def in_world(self):
75
-        return self.arch_mask & 0x08 == 0x08
76
-
77
-    @property
78
-    def in_world_sets(self):
79
-        return self.arch_mask & 0x10 == 0x10
80
-
81
-    @property
82
-    def in_profile(self):
83
-        return self.arch_mask & 0x20 == 0x20
84
-
85
-    restrict_binchecks = property(lambda self: self.restrict_mask & 0x0001 == 0x0001)
86
-    restrict_strip = property(lambda self: self.restrict_mask & 0x0002 == 0x0002)
87
-    restrict_test = property(lambda self: self.restrict_mask & 0x0004 == 0x0004)
88
-    restrict_userpriv = property(lambda self: self.restrict_mask & 0x0008 == 0x0008)
89
-    restrict_installsources = property(lambda self: self.restrict_mask & 0x0010 == 0x0010)
90
-    restrict_fetch = property(lambda self: self.restrict_mask & 0x0020 == 0x0020)
91
-    restrict_mirror = property(lambda self: self.restrict_mask & 0x0040 == 0x0040)
92
-    restrict_primaryuri = property(lambda self: self.restrict_mask & 0x0080 == 0x0080)
93
-    restrict_bindist = property(lambda self: self.restrict_mask & 0x0100 == 0x0100)
94
-    restrict_parallel = property(lambda self: self.restrict_mask & 0x0200 == 0x0200)
95 3
 
96 4
 
97 5
 class EixFileFormat(object):
@@ -100,38 +8,11 @@ class EixFileFormat(object):
100 8
         self.fd = None
101 9
         
102 10
         self.file_format_version = None
103
-        self.no_categories = None
104
-        self.overlays = self.eapi = self.licenses = self.keywords = self.use_flags = self.slots = self.world_sets \
105
-            = self.packages = None
106
-        self.dependencies_stored = False
107
-        self.required_use_stored = False
108
-        self.depend = None
109 11
 
110 12
     def read_magic(self):
111 13
         magic_bytes = os.read(self.fd, 4)
112 14
         assert magic_bytes == b'eix\n'
113 15
 
114
-    def read_header(self):
115
-        self.read_magic()
116
-        self.file_format_version = self.read_number()
117
-        self.no_categories = self.read_number()
118
-        self.overlays = self.read_overlays()
119
-        self.eapi = self.read_hash()
120
-        self.licenses = self.read_hash()
121
-        self.keywords = self.read_hash()
122
-        self.use_flags = self.read_hash()
123
-        self.slots = self.read_hash()
124
-        self.world_sets = self.read_hash()
125
-
126
-        flags = self.read_number()
127
-        self.dependencies_stored = flags & 0x01 == 0x01
128
-        self.required_use_stored = flags & 0x02 == 0x02
129
-
130
-        depend_hash_length = self.read_number()
131
-        self.depend = self.read_hash()
132
-
133
-        self.packages = self.read_packages()
134
-
135 16
     def read_number(self):
136 17
         # From: https://github.com/vaeth/eix/blob/master/doc/eix-db.txt.in#number
137 18
         #
@@ -195,36 +76,10 @@ class EixFileFormat(object):
195 76
         buf = os.read(self.fd, self.read_number())
196 77
         return buf.decode('utf-8')
197 78
 
198
-    def read_overlays(self):
199
-        return self.read_vector(self.read_overlay)
200
-
201
-    def read_overlay(self):
202
-        return self.read_string(), self.read_string()
203
-
204 79
     def read_hash(self):
205 80
         # A hash is a vector of strings.
206 81
         return self.read_vector(self.read_string)
207 82
 
208
-    def read_packages(self):
209
-        
210
-        def _inner():
211
-            for _ in range(0, self.no_categories):
212
-                category = self.read_string()
213
-                for p in self.read_vector(lambda: self.read_package(category)):
214
-                    yield p
215
-
216
-        return list(_inner())
217
-
218
-    def read_package(self, category_name):
219
-        offset_to_next = self.read_number()
220
-
221
-        name = self.read_string()
222
-        desc = self.read_string()
223
-        homepage = self.read_string()
224
-        license = self.licenses[self.read_number()]
225
-        versions = self.read_vector(self.read_version)
226
-        return Package(category_name, name, desc, homepage, license, versions)
227
-    
228 83
     def read_hashed_string(self, hash):
229 84
         # A number which is considered as an index in the corresponding hash; 0 denotes the first string of the hash,
230 85
         # 1 the second, ...
@@ -233,52 +88,3 @@ class EixFileFormat(object):
233 88
     def read_hashed_words(self, hash):
234 89
         # A vector of HashedStrings. The resulting strings are meant to be concatenated, with spaces as separators.
235 90
         return ' '.join(self.read_vector(lambda: hash[self.read_number()]))
236
-
237
-    def read_version(self):
238
-        eapi = self.eapi[self.read_number()]
239
-        mask_bitmask = self.read_number()
240
-        prop_bitmask = self.read_number()
241
-        restrict_bitmask = self.read_number()
242
-        keywords = self.read_hashed_words(self.keywords)
243
-        version_parts = self.read_vector(self.read_version_part)
244
-        slot = self.read_hashed_string(self.slots)
245
-        overlay_idx = self.read_number()
246
-        use_flags = self.read_hashed_words(self.use_flags)
247
-        required_use = self.read_hashed_words(self.use_flags)
248
-
249
-        depend = None
250
-        rdepend = None
251
-        pdepend = None
252
-        hdepend = None
253
-
254
-        if self.dependencies_stored:
255
-            self.read_number()
256
-            depend = self.read_hashed_words(self.depend)
257
-            rdepend = self.read_hashed_words(self.depend)
258
-            pdepend = self.read_hashed_words(self.depend)
259
-            hdepend = self.read_hashed_words(self.depend)
260
-
261
-        return Version(eapi, mask_bitmask, prop_bitmask, restrict_bitmask, keywords, version_parts, slot or '0', self.overlays[overlay_idx],
262
-                       use_flags, depend, rdepend, pdepend, hdepend)
263
-        
264
-    def read_version_part(self):
265
-        # A VersionPart consists of two data: a number (referred to as type) and a "string" (referred to as value).
266
-        # The number is encoded in the lower 5 bits of the length-part of the "string"; of course, the actual length is
267
-        # shifted by the same number of bits.
268
-
269
-        # A version string '0.9.1-r1' is split into the following parts:
270
-
271
-        # 10 (first):  0
272
-        # 9 (primary): 9
273
-        # 9:           1
274
-        # 5 (rev)      -r1
275
-
276
-        num = self.read_number()
277
-
278
-        # remove the lower bits of `num` by shifting everything to the right
279
-        str_len = num >> 5
280
-        # extract the type (lower 5 bits) by masking out the `str_len` (the lower 5 bits)
281
-        vp_type = num & ~(str_len << 5)
282
-
283
-        buf = os.read(self.fd, str_len)
284
-        return vp_type, buf.decode('utf-8')