#!/usr/bin/env python ############################################################################## # # # (c) 2005 Chad Whitacre # # This program is beerware. If you like it, buy me a beer someday. # # No warranty is expressed or implied. # # # ############################################################################## """ Advil takes the headaches out of planning and executing Zope migrations. To use advil, you will need your old instance and a new clean instance available on TCP/IP sockets via ZEO. Advil connects to these, using a different Products directory for each. To change these settings, edit the script. Advil assumes that SOFTWARE_HOME is in your environment. Once connected, you have three ways to prepare for and execute your migration: interactively If advil receives a single argument, -i, it will enter an interactive Python shell with 'old_app' and 'new_app' bound to the two Zope instances. This is useful for developing your migration strategy. via a script If advil receives a single argument that it doesn't otherwise recognize, then it will interpret it as a path to a python script to be executed with 'old_app' and 'new_app' in the namespace. This is especially useful for executing your migration. through the web You can of course connect to the ZEO servers via standard Zope client instances. This can be helpful for migration development, and it also means you can work with a live site. If advil receives no arguments, more than one argument, '-h', or '--help', then it prints this help message. TIP: To repeatedly run your script (for debugging, e.g.) without repeatedly loading Zope, simply use the Python built-in function `execfile' from within an interactive session. """ __version__ = '0.2' __author__ = "Chad Whitacre " # Settings. # ========= # # *_HOST hostname where ZEO is running # *_PORT port on which ZEO is running # *_PRODUCTS the path to the Products directory to use for that ZEO OLD_HOST = 'localhost' OLD_PORT = 9454 OLD_PRODUCTS = '/usr/local/zope/instances/old/Products' NEW_HOST = 'localhost' NEW_PORT = 9777 NEW_PRODUCTS = '/usr/local/zope/instances/new/Products' # Import from the standard library. # ================================= import code import os import sys import time # If we can, exit early rather than waiting for Zope to load. # =========================================================== if __name__ == '__main__': if len(sys.argv) <> 2: sys.exit(__doc__) arg = sys.argv[1] if arg.lower() in ('-h', '--help'): sys.exit(__doc__) if arg <> '-i': path = os.path.realpath(arg) if not os.path.isfile(path): sys.exit("ERROR: %s does not point to a regular file." % path) # Import from Zope. # ================= SOFTWARE_HOME = os.environ.get('SOFTWARE_HOME', '') if not SOFTWARE_HOME: sys.exit("Please set SOFTWARE_HOME to your Zope's lib/python.") sys.path.insert(1, SOFTWARE_HOME) import Products from ZEO import ClientStorage from ZODB import DB from OFS.Application import AppInitializer # Initialize the two Zopes. # ========================= # This could be sped up significantly by doing tricks a la ZopeTestCase: # # https://svn.plone.org/svn/collective/ZopeTestCase/tags/trunk/ZopeLite.py # # It is necessary to do *some* initialization, especially when a Product # (*cough*CMFPlone*cough*) performs circular imports; odd behavior results # otherwise. However, since the migration logic is an open question, it is # probably best to do the full initialization. Products.__path__.insert(0, 'placeholder') # will be replaced in a few lines def connect(host, port, products): sys.stdout.write("Opening Zope @ %s:%s ... " % (host, port)) sys.stdout.flush() start = time.time() Products.__path__[0] = products storage = ClientStorage.ClientStorage((host, port)) conn = DB(storage).open() app = conn.root()['Application'] AppInitializer(app).initialize() # this is what takes so much time print "done (%.3fs)" % (time.time()-start,) return app old_app = connect(OLD_HOST, OLD_PORT, OLD_PRODUCTS) new_app = connect(NEW_HOST, NEW_PORT, NEW_PRODUCTS) if __name__ == '__main__': if arg == '-i': code.interact( banner="Advil v%s -- " % __version__ +\ "Advil eases Zope migrations." , local=globals() ) else: execfile(path)