# Twisted, the Framework of Your Internet # Copyright (C) 2001 Matthew W. Lefkowitz # # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from twisted.python import log, usage, util from twisted.persisted import styles # System imports import os, sys from cPickle import load from cStringIO import StringIO mainMod = sys.modules['__main__'] # Functions from twistd/mktap class EverythingEphemeral(styles.Ephemeral): def __getattr__(self, key): try: return getattr(mainMod, key) except AttributeError: log.msg("Warning! Loading from __main__: %s" % key) return styles.Ephemeral() class LoaderCommon: """Simple logic for loading persisted data""" loadmessage = "Loading %s..." def __init__(self, filename, encrypted=None, passphrase=None): self.filename = filename self.encrypted = encrypted self.passphrase = passphrase def load(self): "Returns the application" log.msg(self.loadmessage % self.filename) if self.encrypted: self.data = open(self.filename, 'r').read() self.decrypt() else: self.read() return self.decode() def read(self): self.data = open(self.filename, 'r').read() def decrypt(self): try: import md5 from Crypto.Cipher import AES self.data = AES.new(md5.new(self.passphrase).digest()[:16]).decrypt(self.data) except ImportError: print "The --decrypt flag requires the PyCrypto module, no file written." def decode(self): pass class LoaderXML(LoaderCommon): loadmessage = '' def decode(self): from twisted.persisted.marmalade import unjellyFromXML sys.modules['__main__'] = EverythingEphemeral() application = unjellyFromXML(StringIO(self.data)) sys.modules['__main__'] = mainMod styles.doUpgrade() return application class LoaderPython(LoaderCommon): def read(self): pass def decrypt(self): log.msg("Python files are never encrypted") def decode(self): pyfile = os.path.abspath(self.filename) d = {'__file__': self.filename} execfile(pyfile, d, d) try: application = d['application'] except KeyError: log.msg("Error - python file %s must set a variable named 'application', an instance of twisted.internet.app.Application. No such variable was found!" % repr(self.filename)) sys.exit() return application class LoaderSource(LoaderCommon): def decode(self): from twisted.persisted.aot import unjellyFromSource sys.modules['__main__'] = EverythingEphemeral() application = unjellyFromSource(StringIO(self.data)) application.persistStyle = "aot" sys.modules['__main__'] = mainMod styles.doUpgrade() return application class LoaderTap(LoaderCommon): def decode(self): sys.modules['__main__'] = EverythingEphemeral() application = load(StringIO(self.data)) sys.modules['__main__'] = mainMod styles.doUpgrade() return application loaders = {'python': LoaderPython, 'xml': LoaderXML, 'source': LoaderSource, 'pickle': LoaderTap} def loadPersisted(filename, kind, encrypted, passphrase): "Loads filename, of the specified kind and returns an application" Loader = loaders[kind] l = Loader(filename, encrypted, passphrase) application = l.load() return application def savePersisted(app, filename, encrypted): if encrypted: try: import Crypto app.save(filename=filename, passphrase=util.getPassword("Encryption passphrase: ")) except ImportError: print "The --encrypt flag requires the PyCrypto module, no file written." else: app.save(filename=filename) class ConvertOptions(usage.Options): synopsis = "Usage: tapconvert [options]" optParameters = [ ['in', 'i', None, "The filename of the tap to read from"], ['out', 'o', None, "A filename to write the tap to"], ['typein', 'f', 'guess', "The format to use; this can be 'guess', 'python', 'pickle', 'xml', or 'source'."], ['typeout', 't', 'source', "The output format to use; this can be 'pickle', 'xml', or 'source'."], ['decrypt', 'd', None, "The specified tap/aos/xml file is encrypted."], ['encrypt', 'e', None, "Encrypt file before writing"]] def postOptions(self): if self['in'] is None: self.opt_help() raise usage.UsageError("You must specify the input filename.") def guessType(filename): ext = os.path.splitext(filename)[1] try: return { '.py': 'python', '.tap': 'pickle', '.tas': 'source', '.tax': 'xml' }[ext] except KeyError: raise usage.UsageError("Could not guess type for '%s'" % (filename,)) def run(): options = ConvertOptions() try: options.parseOptions(sys.argv[1:]) except usage.UsageError, e: print e return passphrase = None if options.opts['decrypt']: import getpass passphrase = getpass.getpass('Passphrase: ') if options["typein"] == "guess": options["typein"] = guessType(options["in"]) a = loadPersisted(options["in"], options["typein"], options["decrypt"], passphrase) try: a.persistStyle = ({'xml': 'xml', 'source': 'aot', 'pickle': 'pickle'} [options["typeout"]]) except KeyError: print "Error: Unsupported output type." else: savePersisted(a, filename=options["out"], encrypted=options["encrypt"])