Skip to content

Commit fbd537c

Browse files
committed
Support for passing in known classes for given oids.
Can be used if there is no 1-to-1 mapping from old to new classes.
1 parent 24b8772 commit fbd537c

File tree

4 files changed

+40
-16
lines changed

4 files changed

+40
-16
lines changed

CHANGES.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ Changes
44
0.6 (unreleased)
55
----------------
66

7-
- ...
7+
- Support for passing in known classes for given oids.
8+
Can be used if there is no 1-to-1 mapping from old to new classes.
9+
810

911
0.5 (2010-10-07)
1012
----------------

src/zodbupdate/main.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import ZODB.FileStorage
1616
import ZODB.config
1717
import ZODB.serialize
18+
import ZODB.utils
19+
import json
1820
import logging
1921
import optparse
2022
import pkg_resources
@@ -57,7 +59,9 @@
5759
parser.add_option(
5860
"--pack", action="store_true", dest="pack",
5961
help="pack the storage when done. use in conjunction of -c if you have blobs storage")
60-
62+
parser.add_option(
63+
"-k", "--known-classes",
64+
help="file containing a mapping from oids to module/class tuples in JSON format")
6165

6266

6367
class DuplicateFilter(object):
@@ -108,6 +112,13 @@ def main():
108112
if options.oid:
109113
start_at = options.oid
110114

115+
class_by_oid = {}
116+
if options.known_classes:
117+
classes_file = open(options.known_classes, 'r')
118+
class_by_oid = {ZODB.utils.repr_to_oid(key): value
119+
for key, value in json.load(classes_file).items()}
120+
classes_file.close()
121+
111122
rename_rules = {}
112123
for entry_point in pkg_resources.iter_entry_points('zodbupdate'):
113124
rules = entry_point.load()
@@ -119,6 +130,7 @@ def main():
119130
storage,
120131
dry=options.dry_run,
121132
renames=rename_rules,
133+
class_by_oid=class_by_oid,
122134
start_at=start_at,
123135
debug=options.debug,
124136
pickler_name=options.pickler)

src/zodbupdate/serialize.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -144,21 +144,25 @@ class ObjectRenamer(object):
144144
- in class information (first pickle of the record).
145145
"""
146146

147-
def __init__(self, changes, pickler_name='C'):
147+
def __init__(self, changes, class_by_oid={}, pickler_name='C'):
148148
self.__added = dict()
149149
self.__changes = dict()
150150
for old, new in changes.iteritems():
151151
self.__changes[tuple(old.split(' '))] = tuple(new.split(' '))
152+
self.__class_by_oid = class_by_oid
152153
self.__changed = False
153154
self.__pickler_name = pickler_name
154155

155-
def __update_symb(self, symb_info):
156+
def __update_symb(self, symb_info, oid=None):
156157
"""This method look in a klass or symbol have been renamed or
157158
not. If the symbol have not been renamed explicitly, it's
158159
loaded and its location is checked to see if it have moved as
159160
well.
160161
"""
161-
if symb_info in self.__changes:
162+
if oid in self.__class_by_oid:
163+
self.__changed = True
164+
return self.__class_by_oid[oid]
165+
elif symb_info in self.__changes:
162166
self.__changed = True
163167
return self.__changes[symb_info]
164168
else:
@@ -195,15 +199,21 @@ def __persistent_load(self, reference):
195199
"""
196200
if isinstance(reference, tuple):
197201
oid, klass_info = reference
198-
if isinstance(klass_info, tuple):
199-
klass_info = self.__update_symb(klass_info)
202+
if oid in self.__class_by_oid:
203+
self.__changed = True
204+
klass_info = find_global(*self.__class_by_oid[oid], Broken=ZODBBroken)
205+
elif isinstance(klass_info, tuple):
206+
klass_info = self.__update_symb(klass_info, oid=oid)
200207
return ZODBReference((oid, klass_info))
201208
if isinstance(reference, list):
202209
mode, information = reference
203210
if mode == 'm':
204211
database_name, oid, klass_info = information
205-
if isinstance(klass_info, tuple):
206-
klass_info = self.__update_symb(klass_info)
212+
if oid in self.__class_by_oid:
213+
self.__changed = True
214+
klass_info = find_global(*self.__class_by_oid[oid], Broken=ZODBBroken)
215+
elif isinstance(klass_info, tuple):
216+
klass_info = self.__update_symb(klass_info, oid=oid)
207217
return ZODBReference(['m', (database_name, oid, klass_info)])
208218
return ZODBReference(reference)
209219

@@ -230,7 +240,7 @@ def __pickler(self, output_file):
230240
pickler.persistent_id = self.__persistent_id
231241
return pickler
232242

233-
def __update_class_meta(self, class_meta):
243+
def __update_class_meta(self, class_meta, oid):
234244
"""Update class information, which can contain information
235245
about a renamed class.
236246
"""
@@ -242,10 +252,10 @@ def __update_class_meta(self, class_meta):
242252
u'Warning: Missing factory for %s' % u' '.join(symb_info))
243253
return (symb_info, args)
244254
elif isinstance(symb, tuple):
245-
return self.__update_symb(symb), args
255+
return self.__update_symb(symb, oid=oid), args
246256
return class_meta
247257

248-
def rename(self, input_file):
258+
def rename(self, input_file, oid):
249259
"""Take a ZODB record (as a file object) as input. We load it,
250260
replace any reference to renamed class we know of. If any
251261
modification are done, we save the record again and return it,
@@ -257,7 +267,7 @@ def rename(self, input_file):
257267
class_meta = unpickler.load()
258268
data = unpickler.load()
259269

260-
class_meta = self.__update_class_meta(class_meta)
270+
class_meta = self.__update_class_meta(class_meta, oid)
261271

262272
if not (self.__changed or
263273
(hasattr(unpickler, 'need_repickle') and

src/zodbupdate/update.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
class Updater(object):
3131
"""Update class references for all current objects in a storage."""
3232

33-
def __init__(self, storage, dry=False, renames=None,
33+
def __init__(self, storage, dry=False, renames=None, class_by_oid={},
3434
start_at='0x00', debug=False, pickler_name='C'):
3535
self.dry = dry
3636
self.storage = storage
3737
self.processor = zodbupdate.serialize.ObjectRenamer(
38-
renames or {}, pickler_name)
38+
renames or {}, class_by_oid=class_by_oid, pickler_name=pickler_name)
3939
self.start_at = start_at
4040
self.debug = debug
4141

@@ -62,7 +62,7 @@ def __call__(self):
6262
for oid, serial, current in self.records:
6363
logger.debug('Processing OID %s' % ZODB.utils.oid_repr(oid))
6464

65-
new = self.processor.rename(current)
65+
new = self.processor.rename(current, oid)
6666
if new is None:
6767
continue
6868

0 commit comments

Comments
 (0)