1 |
commit: bec81d9137f5b68398401e79df094207680eb006 |
2 |
Author: André Erdmann <dywi <AT> mailerd <DOT> de> |
3 |
AuthorDate: Fri Aug 30 12:42:18 2013 +0000 |
4 |
Commit: André Erdmann <dywi <AT> mailerd <DOT> de> |
5 |
CommitDate: Fri Aug 30 12:42:18 2013 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=bec81d91 |
7 |
|
8 |
distmap: add_distfile_owner() |
9 |
|
10 |
This commit also includes a stub for detecting/handling file collisions. |
11 |
|
12 |
--- |
13 |
roverlay/db/distmap.py | 97 +++++++++++++++++++++++++++++++++++++++++--------- |
14 |
1 file changed, 80 insertions(+), 17 deletions(-) |
15 |
|
16 |
diff --git a/roverlay/db/distmap.py b/roverlay/db/distmap.py |
17 |
index ca3d236..b3b285c 100644 |
18 |
--- a/roverlay/db/distmap.py |
19 |
+++ b/roverlay/db/distmap.py |
20 |
@@ -4,17 +4,17 @@ |
21 |
# Distributed under the terms of the GNU General Public License; |
22 |
# either version 2 of the License, or (at your option) any later version. |
23 |
|
24 |
-import errno |
25 |
- |
26 |
import bz2 |
27 |
import gzip |
28 |
|
29 |
+import errno |
30 |
import os.path |
31 |
+import logging |
32 |
import shutil |
33 |
|
34 |
- |
35 |
import roverlay.digest |
36 |
import roverlay.util |
37 |
+import roverlay.util.objects |
38 |
import roverlay.stats.collector |
39 |
|
40 |
|
41 |
@@ -30,6 +30,14 @@ class DistMapInfo ( object ): |
42 |
RESTORE_FROM_DISTFILE = '_' |
43 |
UNSET = 'U' |
44 |
|
45 |
+ @classmethod |
46 |
+ def from_package_info ( cls, p_info, allow_digest_create=True ): |
47 |
+ key, value = p_info.get_distmap_value ( |
48 |
+ allow_digest_create=allow_digest_create |
49 |
+ ) |
50 |
+ return key, cls ( *value ) |
51 |
+ # --- end of from_package_info (...) --- |
52 |
+ |
53 |
def __init__ ( self, distfile, repo_name, repo_file, sha256 ): |
54 |
"""Distmap entry constructor. |
55 |
|
56 |
@@ -44,12 +52,26 @@ class DistMapInfo ( object ): |
57 |
self.repo_name = repo_name if repo_name is not None else self.UNSET |
58 |
self.sha256 = sha256 |
59 |
|
60 |
+ # references to objects that "own" (use, ...) this distfile |
61 |
+ self.backrefs = set() |
62 |
+ self.add_backref = self.backrefs.add |
63 |
+ |
64 |
if repo_file == self.RESTORE_FROM_DISTFILE: |
65 |
self.repo_file = distfile |
66 |
else: |
67 |
self.repo_file = repo_file if repo_file is not None else self.UNSET |
68 |
# --- end of __init__ (...) --- |
69 |
|
70 |
+ #def add_backref ( self, ref ): self.backrefs.add ( ref ) |
71 |
+ |
72 |
+ def has_backref_to ( self, obj ): |
73 |
+ return any ( ( ref.deref_unsafe() is obj ) for ref in self.backrefs ) |
74 |
+ # --- end of has_backref_to (...) --- |
75 |
+ |
76 |
+ def has_backrefs ( self ): |
77 |
+ return bool ( self.backrefs ) |
78 |
+ # --- end of has_backrefs (...) --- |
79 |
+ |
80 |
@property |
81 |
def digest ( self ): |
82 |
return self.sha256 |
83 |
@@ -139,16 +161,16 @@ def get_distmap ( distmap_file, distmap_compression, ignore_missing=False ): |
84 |
class _DistMapBase ( object ): |
85 |
|
86 |
# { attr[, as_attr] } |
87 |
- DISTMAP_BIND_ATTR = frozenset ({ 'get', 'keys', 'items', 'values', }) |
88 |
- |
89 |
- class AbstractMethod ( NotImplementedError ): |
90 |
- pass |
91 |
- # --- end of AbstractMethod --- |
92 |
+ DISTMAP_BIND_ATTR = frozenset ({ |
93 |
+ 'get', 'keys', 'items', 'values', ( 'get', 'get_entry' ), |
94 |
+ }) |
95 |
|
96 |
def __init__ ( self ): |
97 |
super ( _DistMapBase, self ).__init__() |
98 |
+ self.logger = logging.getLogger ( self.__class__.__name__ ) |
99 |
self.dirty = False |
100 |
self._distmap = dict() |
101 |
+ |
102 |
self.stats = roverlay.stats.collector.static.distmap |
103 |
|
104 |
self._rebind_distmap() |
105 |
@@ -202,9 +224,33 @@ class _DistMapBase ( object ): |
106 |
if isinstance ( attr, str ): |
107 |
setattr ( self, attr, getattr ( self._distmap, attr ) ) |
108 |
else: |
109 |
- setattr ( self, attr [1], getattr ( self._distmap, attr[0] ) ) |
110 |
+ setattr ( self, attr[1], getattr ( self._distmap, attr[0] ) ) |
111 |
# --- end of _rebind_distmap (...) --- |
112 |
|
113 |
+ def add_distfile_owner ( self, backref, distfile, distfilepath=None ): |
114 |
+ entry = self.get_entry ( distfile ) |
115 |
+ if entry is not None: |
116 |
+ entry.add_backref ( backref ) |
117 |
+ else: |
118 |
+ new_entry = self.add_dummy_entry ( |
119 |
+ distfile, distfilepath=distfilepath, log_level=True |
120 |
+ ) |
121 |
+ # ^ raises: ? if distfile is missing |
122 |
+ new_entry.add_backref ( backref ) |
123 |
+ # --- end of add_distfile_owner (...) --- |
124 |
+ |
125 |
+ def get_distfile_slot ( self, backref, distfile ): |
126 |
+ entry = self.get_entry ( distfile ) |
127 |
+ if entry is None: |
128 |
+ raise NotImplementedError ( "backref gets new 'slot'." ) |
129 |
+ return 1 |
130 |
+ elif entry.has_backref_to ( backref.deref_safe() ): |
131 |
+ return 2 |
132 |
+ else: |
133 |
+ raise NotImplementedError ( "handle file collision." ) |
134 |
+ return 0 |
135 |
+ # --- end of get_distfile_slot (...) --- |
136 |
+ |
137 |
def check_revbump_necessary ( self, package_info ): |
138 |
"""Tries to find package_info's distfile in the distmap and returns |
139 |
whether a revbump is necessary (True) or not (False). |
140 |
@@ -351,6 +397,8 @@ class _DistMapBase ( object ): |
141 |
arguments: |
142 |
* distfile -- distfile path relative to the distroot |
143 |
* distmap_info -- distmap entry |
144 |
+ |
145 |
+ Returns: distmap_info |
146 |
""" |
147 |
if self.update_only: |
148 |
entry = self._distmap.get ( distfile, None ) |
149 |
@@ -362,7 +410,7 @@ class _DistMapBase ( object ): |
150 |
self._distmap [distfile] = distmap_info |
151 |
self._file_added ( distfile ) |
152 |
|
153 |
- return True |
154 |
+ return distmap_info |
155 |
# --- end of add_entry (...) --- |
156 |
|
157 |
def add_entry_for ( self, p_info ): |
158 |
@@ -370,14 +418,16 @@ class _DistMapBase ( object ): |
159 |
|
160 |
arguments: |
161 |
* p_info -- |
162 |
+ |
163 |
+ Returns: created entry |
164 |
""" |
165 |
- key = p_info.get_distmap_key() |
166 |
- return self.add_entry ( |
167 |
- key, DistMapInfo ( key, *p_info.get_distmap_value() ) |
168 |
- ) |
169 |
+ key, value = DistMapInfo.from_package_info ( p_info ) |
170 |
+ return self.add_entry ( key, value ) |
171 |
# --- end of add_entry_for (...) --- |
172 |
|
173 |
- def add_dummy_entry ( self, distfile, distfilepath=None, hashdict=None ): |
174 |
+ def add_dummy_entry ( |
175 |
+ self, distfile, distfilepath=None, hashdict=None, log_level=None |
176 |
+ ): |
177 |
"""Adds a dummy entry. |
178 |
Such an entry contains a checksum and a distfile, but no information |
179 |
about its origin (repo name/file). |
180 |
@@ -386,7 +436,18 @@ class _DistMapBase ( object ): |
181 |
* distfile -- distfile path relative to the distroot |
182 |
* distfilepath -- absolute path to the distfile |
183 |
* hashdict -- dict with already calculated hashes |
184 |
+ * log_level -- if not None: log entry creation with the given log |
185 |
+ level (or INFO if log_level is True) |
186 |
+ |
187 |
+ Returns: created entry |
188 |
""" |
189 |
+ if log_level is None or log_level is False: |
190 |
+ pass |
191 |
+ elif log_level is True: |
192 |
+ self.logger.info ( "adding dummy entry for " + distfile ) |
193 |
+ else: |
194 |
+ self.logger.log ( log_level, "adding dummy entry for " + distfile ) |
195 |
+ |
196 |
if hashdict and DistMapInfo.DIGEST_TYPE in hashdict: |
197 |
digest = hashdict [DistMapInfo.DIGEST_TYPE] |
198 |
else: |
199 |
@@ -523,15 +584,17 @@ class _FileDistMapBase ( _DistMapBase ): |
200 |
return False |
201 |
# --- end of _read_header (...) --- |
202 |
|
203 |
+ @roverlay.util.objects.abstractmethod |
204 |
def read ( self, filepath=None ): |
205 |
"""Reads the distmap. |
206 |
|
207 |
arguments: |
208 |
* filepath -- path to the distmap file (defaults to self.dbfile) |
209 |
""" |
210 |
- raise self.__class__.AbstractMethod() |
211 |
+ pass |
212 |
# --- end of read (...) --- |
213 |
|
214 |
+ @roverlay.util.objects.abstractmethod |
215 |
def write ( self, filepath=None, force=False ): |
216 |
"""Writes the distmap. |
217 |
|
218 |
@@ -539,7 +602,7 @@ class _FileDistMapBase ( _DistMapBase ): |
219 |
* filepath -- path to the distmap file (defaults to self.dbfile) |
220 |
* force -- enforce writing even if distmap not modified |
221 |
""" |
222 |
- raise self.__class__.AbstractMethod() |
223 |
+ pass |
224 |
# --- end of write (...) --- |
225 |
|
226 |
# --- end of _FileDistMapBase --- |