1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
# Standard library imports
import sys
import pickle
import logging
# Enthought library imports
from apptools.persistence.versioned_unpickler import VersionedUnpickler
logger = logging.getLogger(__name__)
def load_project(pickle_filename, updater_path, application_version, protocol,
max_pass=-1):
""" Reads a project from a pickle file and if necessary will update it to
the latest version of the application.
"""
latest_file = pickle_filename
# Read the pickled project's metadata.
f = open(latest_file, 'rb')
metadata = VersionedUnpickler(f).load(max_pass)
f.close()
project_version = metadata.get('version', False)
if not project_version:
raise ValueError, "Could not read version number from the project file"
logger.debug('Project version: %d, Application version: %d' %
(project_version, application_version))
# here you can temporarily force an upgrade each time for testing ....
# project_version = 0
latest_file = upgrade_project(pickle_filename, updater_path,
project_version, application_version, protocol,
max_pass)
# Finally we can import the project ...
logger.info('loading %s' % latest_file)
i_f = open(latest_file, 'rb')
version = VersionedUnpickler(i_f).load(max_pass)
project = VersionedUnpickler(i_f).load(max_pass)
i_f.close()
return project
def upgrade_project(pickle_filename, updater_path, project_version, application_version, protocol, max_pass=-1):
""" Repeatedly read and write the project to disk updating it one version
at a time.
Example the p5.project is at version 0
The application is at version 3
p5.project --- Update1 ---> p5.project.v1
p5.project.v1 --- Update2 ---> p5.project.v2
p5.project.v2 --- Update3 ---> p5.project.v3
p5.project.v3 ---> loaded into app
The user then has the option to save the updated project as p5.project
"""
first_time = True
latest_file = pickle_filename
# update the project until it's version matches the application's
while project_version < application_version:
next_version = project_version + 1
if first_time:
i_f = open(pickle_filename, 'rb')
data = i_f.read()
open('%s.bak' % pickle_filename, 'wb').write(data)
i_f.seek(0) # rewind the file to the start
else:
name = '%s.v%d' % (pickle_filename, project_version)
i_f = open(name, 'rb')
latest_file = name
logger.info('converting %s' % latest_file)
# find this version's updater ...
updater_name = '%s.update%d' % (updater_path, next_version)
__import__(updater_name)
mod = sys.modules[updater_name]
klass = getattr(mod, 'Update%d' % next_version)
updater = klass()
# load and update this version of the project
version = VersionedUnpickler(i_f).load(max_pass)
project = VersionedUnpickler(i_f, updater).load(max_pass)
i_f.close()
# set the project version to be the same as the updater we just
# ran on the unpickled files ...
project.metadata['version'] = next_version
# Persist the updated project ...
name = '%s.v%d' % (pickle_filename, next_version)
latest_file = name
o_f = open(name, 'wb')
pickle.dump(project.metadata, o_f, protocol=protocol)
pickle.dump(project, o_f, protocol=protocol)
o_f.close()
# Bump up the version number of the pickled project...
project_version += 1
first_time = False
return latest_file
### EOF #################################################################
|