[Checkins] SVN: Products.ExternalEditor/trunk/Products/ExternalEditor/ Clean-up
Matthias Broquet
mbroquet at atreal.net
Wed Dec 1 10:06:49 EST 2010
Log message for revision 118661:
Clean-up
Changed:
U Products.ExternalEditor/trunk/Products/ExternalEditor/ExternalEditor.py
D Products.ExternalEditor/trunk/Products/ExternalEditor/zopeedit.py
-=-
Modified: Products.ExternalEditor/trunk/Products/ExternalEditor/ExternalEditor.py
===================================================================
--- Products.ExternalEditor/trunk/Products/ExternalEditor/ExternalEditor.py 2010-12-01 14:37:08 UTC (rev 118660)
+++ Products.ExternalEditor/trunk/Products/ExternalEditor/ExternalEditor.py 2010-12-01 15:06:48 UTC (rev 118661)
@@ -18,7 +18,6 @@
from string import join # For Zope 2.3 compatibility
import types
-import re
import urllib
import Acquisition
try:
@@ -94,7 +93,7 @@
if path:
target = path[-1]
if target.endswith('.zem'):
- # Remove extension added by EditLink() for Mac finder
+ # Remove extension added by EditLink()
# so we can traverse to the target in Zope
target = target[:-4]
request.set('target', target)
@@ -268,7 +267,6 @@
InitializeClass(ExternalEditor)
-#is_mac_user_agent = re.compile('.*Mac OS X.*|.*Mac_PowerPC.*').match
def EditLink(self, object, borrow_lock=0, skip_data=0):
"""Insert the external editor link to an object if appropriate"""
Deleted: Products.ExternalEditor/trunk/Products/ExternalEditor/zopeedit.py
===================================================================
--- Products.ExternalEditor/trunk/Products/ExternalEditor/zopeedit.py 2010-12-01 14:37:08 UTC (rev 118660)
+++ Products.ExternalEditor/trunk/Products/ExternalEditor/zopeedit.py 2010-12-01 15:06:48 UTC (rev 118661)
@@ -1,872 +0,0 @@
-#!/usr/bin/env python
-##############################################################################
-#
-# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Zope External Editor Helper Application by Casey Duncan
-
-$Id$"""
-
-__version__ = '0.9.3'
-
-import sys
-
-win32 = sys.platform == 'win32'
-
-if win32:
- # import pywin32 stuff first so it never looks into system32
- import pythoncom, pywintypes
-
- # prevent warnings from being turned into errors by py2exe
- import warnings
- warnings.filterwarnings('ignore')
-
-import os, re
-import rfc822
-import traceback
-import logging
-import urllib
-import shutil
-
-from tempfile import mktemp, NamedTemporaryFile
-from ConfigParser import ConfigParser
-from httplib import HTTPConnection, HTTPSConnection
-from urlparse import urlparse
-
-logger = logging.getLogger('zopeedit')
-log_file = None
-
-class Configuration:
-
- def __init__(self, path):
- # Create/read config file on instantiation
- self.path = path
- if not os.path.exists(path):
- f = open(path, 'w')
- f.write(default_configuration)
- f.close()
- self.changed = 0
- self.config = ConfigParser()
- self.config.readfp(open(path))
-
- def save(self):
- """Save config options to disk"""
- self.config.write(open(self.path, 'w'))
- self.changed = 0
-
- def set(self, section, option, value):
- self.config.set(section, option, value)
- self.changed = 1
-
- def __getattr__(self, name):
- # Delegate to the ConfigParser instance
- return getattr(self.config, name)
-
- def getAllOptions(self, meta_type, content_type, host_domain):
- """Return a dict of all applicable options for the
- given meta_type, content_type and host_domain
- """
- opt = {}
- sep = content_type.find('/')
- general_type = '%s/*' % content_type[:sep]
-
- # Divide up the domains segments and create a
- # list of domains from the bottom up
- host_domain = host_domain.split('.')
- domains = []
- for i in range(len(host_domain)):
- domains.append('domain:%s' % '.'.join(host_domain[i:]))
- domains.reverse()
-
- sections = ['general']
- sections.extend(domains)
- sections.append('meta-type:%s' % meta_type)
- sections.append('content-type:%s' % general_type)
- sections.append('content-type:%s' % content_type)
-
- for section in sections:
- if self.config.has_section(section):
- for option in self.config.options(section):
- opt[option] = self.config.get(section, option)
- return opt
-
-class ExternalEditor:
-
- did_lock = 0
-
- def __init__(self, input_file):
- global log_file
- log_file = NamedTemporaryFile(suffix='-zopeedit-log.txt')
-
- self.input_file = input_file
-
- # Setup logging.
- logging.basicConfig(stream=log_file,
- level=logging.DEBUG)
- logger.info('Opening %r.', input_file)
-
- try:
- # Read the configuration file
- if win32:
- # Check the home dir first and then the program dir
- config_path = os.path.expanduser('~\\ZopeEdit.ini')
-
- # sys.path[0] might be library.zip!!!!
- app_dir = sys.path[0]
- if app_dir.lower().endswith('library.zip'):
- app_dir = os.path.dirname(app_dir)
- global_config = os.path.join(app_dir or '', 'ZopeEdit.ini')
-
- if not os.path.exists(config_path):
- logger.debug('Config file %r does not exist. '
- 'Using global configuration file: %r.',
- config_path, global_config)
-
- # Don't check for the existence of the global
- # config file. It will be created anyway.
- config_path = global_config
- else:
- logger.debug('Using user configuration file: %r.',
- config_path)
-
- else:
- config_path = os.path.expanduser('~/.zope-external-edit')
-
- self.config = Configuration(config_path)
-
- # Open the input file and read the metadata headers
- in_f = open(input_file, 'rb')
- m = rfc822.Message(in_f)
-
- self.metadata = metadata = m.dict.copy()
-
- # parse the incoming url
- scheme, self.host, self.path = urlparse(metadata['url'])[:3]
- self.ssl = scheme == 'https'
-
- # Get all configuration options
- self.options = self.config.getAllOptions(
- metadata['meta_type'],
- metadata.get('content_type',''),
- self.host)
-
- # Should we keep the log file?
- self.keep_log = int(self.options.get('keep_log', 0))
-
- # Write the body of the input file to a separate file
- if int(self.options.get('long_file_name', 1)):
- sep = self.options.get('file_name_separator', ',')
- content_file = urllib.unquote('-%s%s' % (self.host, self.path))
- content_file = content_file.replace(
- '/', sep).replace(':',sep).replace(' ','_')
- else:
- content_file = '-' + urllib.unquote(self.path.split('/')[-1])
-
- extension = self.options.get('extension')
- if extension and not content_file.endswith(extension):
- content_file = content_file + extension
-
- if self.options.has_key('temp_dir'):
- while 1:
- temp = os.path.expanduser(self.options['temp_dir'])
- temp = os.tempnam(temp)
- content_file = '%s%s' % (temp, content_file)
- if not os.path.exists(content_file):
- break
- else:
- content_file = mktemp(content_file)
-
- logger.debug('Destination filename will be: %r.', content_file)
-
- body_f = open(content_file, 'wb')
- shutil.copyfileobj(in_f, body_f)
- self.content_file = content_file
- self.saved = 1
- in_f.close()
- body_f.close()
- self.clean_up = int(self.options.get('cleanup_files', 1))
- if self.clean_up:
- try:
- logger.debug('Cleaning up %r.', input_file)
- os.remove(input_file)
- except OSError:
- logger.exception('Failed to clean up %r.', input_file)
- pass # Sometimes we aren't allowed to delete it
-
- if self.ssl:
- # See if ssl is available
- try:
- from socket import ssl
- except ImportError:
- fatalError('SSL support is not available on this system. '
- 'Make sure openssl is installed '
- 'and reinstall Python.')
- self.lock_token = None
- self.did_lock = 0
- except:
- # for security, always delete the input file even if
- # a fatal error occurs, unless explicitly stated otherwise
- # in the config file
- if getattr(self, 'clean_up', 1):
- try:
- exc, exc_data = sys.exc_info()[:2]
- os.remove(input_file)
- except OSError:
- # Sometimes we aren't allowed to delete it
- raise exc, exc_data
- raise
-
- def __del__(self):
- if getattr(self, 'clean_up', 1) and hasattr(self, 'content_file'):
- # for security we always delete the files by default
- try:
- os.remove(self.content_file)
- except OSError:
- logger.exception('Failed to clean up %r', self.content_file)
- pass
-
- if self.did_lock:
- # Try not to leave dangling locks on the server
- try:
- self.unlock(interactive=0)
- except:
- logger.exception('Failure during unlock.')
-
- if getattr(self, 'keep_log', 0):
- if log_file is not None:
- base = getattr(self, 'content_file', '')
- if not base:
- base = getattr(self, 'input_file', 'noname')
- base = os.path.basename(base)
- fname = mktemp(suffix='-zopeedit-log.txt',
- prefix='%s-' % base)
- bkp_f = open(fname, 'wb')
-
- # Copy the log file to a backup file.
- log_file.seek(0)
- shutil.copyfileobj(log_file, bkp_f)
-
- def getEditorCommand(self):
- """Return the editor command"""
- editor = self.options.get('editor')
-
- if win32 and editor is None:
- from _winreg import HKEY_CLASSES_ROOT, OpenKeyEx, \
- QueryValueEx, EnumKey
- from win32api import FindExecutable, ExpandEnvironmentStrings
-
- # Find editor application based on mime type and extension
- content_type = self.metadata.get('content_type')
- extension = self.options.get('extension')
-
- logger.debug('Have content type: %r, extension: %r',
- content_type, extension)
-
- if content_type:
- # Search registry for the extension by MIME type
- try:
- key = 'MIME\\Database\\Content Type\\%s' % content_type
- key = OpenKeyEx(HKEY_CLASSES_ROOT, key)
- extension, nil = QueryValueEx(key, 'Extension')
- logger.debug('Registry has extension %r for '
- 'content type %r',
- extension, content_type)
- except EnvironmentError:
- pass
-
- if extension is None:
- url = self.metadata['url']
- dot = url.rfind('.')
-
- if dot != -1 and dot > url.rfind('/'):
- extension = url[dot:]
-
- logger.debug('Extracted extension from url: %r',
- extension)
-
- classname = editor = None
- if extension is not None:
- try:
- key = OpenKeyEx(HKEY_CLASSES_ROOT, extension)
- classname, nil = QueryValueEx(key, None)
- logger.debug('ClassName for extension %r is: %r',
- extension, classname)
- except EnvironmentError:
- classname = None
-
- if classname is not None:
- try:
- # Look for Edit action in registry
- key = OpenKeyEx(HKEY_CLASSES_ROOT,
- classname+'\\Shell\\Edit\\Command')
- editor, nil = QueryValueEx(key, None)
- logger.debug('Edit action for %r is: %r',
- classname, editor)
- except EnvironmentError:
- pass
-
- if classname is not None and editor is None:
- logger.debug('Could not find Edit action for %r. '
- 'Brute-force enumeration.', classname)
- # Enumerate the actions looking for one
- # starting with 'Edit'
- try:
- key = OpenKeyEx(HKEY_CLASSES_ROOT,
- classname+'\\Shell')
- index = 0
- while 1:
- try:
- subkey = EnumKey(key, index)
- index += 1
- if str(subkey).lower().startswith('edit'):
- subkey = OpenKeyEx(key, subkey + '\\Command')
- editor, nil = QueryValueEx(subkey,
- None)
- if editor is None:
- continue
- logger.debug('Found action %r for %r. '
- 'Command will be: %r',
- subkey, classname, editor)
- except EnvironmentError:
- break
- except EnvironmentError:
- pass
-
- if classname is not None and editor is None:
- try:
- # Look for Open action in registry
- key = OpenKeyEx(HKEY_CLASSES_ROOT,
- classname+'\\Shell\\Open\\Command')
- editor, nil = QueryValueEx(key, None)
- logger.debug('Open action for %r has command: %r. ',
- classname, editor)
- except EnvironmentError:
- pass
-
- if editor is None:
- try:
- nil, editor = FindExecutable(self.content_file, '')
- logger.debug('Executable for %r is: %r. ',
- self.content_file, editor)
- except pywintypes.error:
- pass
-
- # Don't use IE as an "editor"
- if editor is not None and editor.find('\\iexplore.exe') != -1:
- logger.debug('Found iexplore.exe. Skipping.')
- editor = None
-
- if editor is not None:
- return ExpandEnvironmentStrings(editor)
-
- if editor is None:
- fatalError('No editor was found for that object.\n'
- 'Specify an editor in the configuration file:\n'
- '(%s)' % self.config.path)
-
- return editor
-
- def launch(self):
- """Launch external editor"""
- use_locks = int(self.options.get('use_locks', 0))
- if use_locks and self.metadata.get('lock-token'):
- # A lock token came down with the data, so the object is
- # already locked, see if we can borrow the lock
- if (int(self.options.get('always_borrow_locks', 0))
- or self.metadata.get('borrow_lock')
- or askYesNo('This object is already locked by you in another'
- ' session.\n Do you want to borrow this lock'
- ' and continue?')):
- self.lock_token = 'opaquelocktoken:%s' \
- % self.metadata['lock-token']
- else:
- sys.exit()
-
- save_interval = float(self.options.get('save_interval'))
- last_mtime = os.path.getmtime(self.content_file)
- command = self.getEditorCommand()
-
- # Extract the executable name from the command
- if win32:
- if command.find('\\') != -1:
- bin = re.search(r'\\([^\.\\]+)\.exe', command.lower())
- if bin is not None:
- bin = bin.group(1)
- else:
- bin = command.lower().strip()
- else:
- bin = command
-
- logger.debug('Command %r, will use %r', command, bin)
-
- if bin is not None:
- # Try to load the plugin for this editor
- try:
- module = 'Plugins.%s' % bin
- Plugin = __import__(module, globals(), locals(),
- ('EditorProcess',))
- editor = Plugin.EditorProcess(self.content_file)
- logger.debug('Launching Plugin %r with: %r',
- Plugin, self.content_file)
- except (ImportError, AttributeError):
- bin = None
-
- if bin is None:
- # Use the standard EditorProcess class for this editor
- if win32:
- file_insert = '%1'
- else:
- file_insert = '$1'
-
- if command.find(file_insert) > -1:
- command = command.replace(file_insert, self.content_file)
- else:
- command = '%s %s' % (command, self.content_file)
-
- logger.debug('Launching EditorProcess with: %r', command)
- editor = EditorProcess(command)
-
- launch_success = editor.isAlive()
-
- if use_locks:
- self.lock()
-
- final_loop = 0
-
- while 1:
- if not final_loop:
- editor.wait(save_interval or 2)
-
- mtime = os.path.getmtime(self.content_file)
-
- if mtime != last_mtime:
- if save_interval or final_loop:
- launch_success = 1 # handle very short editing sessions
- self.saved = self.putChanges()
- last_mtime = mtime
-
- if not editor.isAlive():
- if final_loop:
- break
- else:
- # Go through the loop one final time for good measure.
- # Our editor's isAlive method may itself *block* during a
- # save operation (seen in COM calls, which seem to
- # respond asynchronously until they don't) and subsequently
- # return false, but the editor may have actually saved the
- # file to disk while the call blocked. We want to catch
- # any changes that happened during a blocking isAlive call.
- final_loop = 1
-
- if not launch_success:
- fatalError('Editor did not launch properly.\n'
- 'External editor lost connection '
- 'to editor process.\n'
- '(%s)' % command)
-
- if use_locks:
- self.unlock()
-
- if not self.saved \
- and askYesNo('File not saved to Zope.\nReopen local copy?'):
- self.launch()
-
- def putChanges(self):
- """Save changes to the file back to Zope"""
- if int(self.options.get('use_locks', 0)) and self.lock_token is None:
- # We failed to get a lock initially, so try again before saving
- if not self.lock():
- # Confirm save without lock
- if not askYesNo('Could not acquire lock. '
- 'Attempt to save to Zope anyway?'):
- return 0
-
- f = open(self.content_file, 'rb')
- body = f.read()
- f.close()
- headers = {'Content-Type':
- self.metadata.get('content_type', 'text/plain')}
-
- if self.lock_token is not None:
- headers['If'] = '<%s> (<%s>)' % (self.path, self.lock_token)
-
- response = self.zopeRequest('PUT', headers, body)
- del body # Don't keep the body around longer then we need to
-
- if response.status / 100 != 2:
- # Something went wrong
- if self.askRetryAfterError(response,
- 'Could not save to Zope.\n'
- 'Error occurred during HTTP put'):
- return self.putChanges()
- else:
- return 0
- return 1
-
- def lock(self):
- """Apply a webdav lock to the object in Zope"""
- if self.lock_token is not None:
- return 0 # Already have a lock token
-
- headers = {'Content-Type':'text/xml; charset="utf-8"',
- 'Timeout':'infinite',
- 'Depth':'infinity',
- }
- body = ('<?xml version="1.0" encoding="utf-8"?>\n'
- '<d:lockinfo xmlns:d="DAV:">\n'
- ' <d:lockscope><d:exclusive/></d:lockscope>\n'
- ' <d:locktype><d:write/></d:locktype>\n'
- ' <d:depth>infinity</d:depth>\n'
- ' <d:owner>\n'
- ' <d:href>Zope External Editor</d:href>\n'
- ' </d:owner>\n'
- '</d:lockinfo>'
- )
-
- response = self.zopeRequest('LOCK', headers, body)
-
- if response.status / 100 == 2:
- # We got our lock, extract the lock token and return it
- reply = response.read()
- token_start = reply.find('>opaquelocktoken:')
- token_end = reply.find('<', token_start)
- if token_start > 0 and token_end > 0:
- self.lock_token = reply[token_start+1:token_end]
- self.did_lock = 1
- else:
- # We can't lock her sir!
- if response.status == 423:
- message = '(object already locked)'
- else:
- message = ''
-
- if self.askRetryAfterError(response,
- 'Lock request failed',
- message):
- self.lock()
- else:
- self.did_lock = 0
- return self.did_lock
-
- def unlock(self, interactive=1):
- """Remove webdav lock from edited zope object"""
- if not self.did_lock or self.lock_token is None:
- return 0 # nothing to do
-
- headers = {'Lock-Token':self.lock_token}
- response = self.zopeRequest('UNLOCK', headers)
-
- if interactive and response.status / 100 != 2:
- # Captain, she's still locked!
- if self.askRetryAfterError(response, 'Unlock request failed'):
- self.unlock()
- else:
- self.did_lock = 0
- else:
- self.did_lock = 1
- self.lock_token = None
- return self.did_lock
-
- def zopeRequest(self, method, headers={}, body=''):
- """Send a request back to Zope"""
- try:
- if self.ssl:
- h = HTTPSConnection(self.host)
- else:
- h = HTTPConnection(self.host)
-
- h.putrequest(method, self.path)
- h.putheader('User-Agent', 'Zope External Editor/%s' % __version__)
- h.putheader('Connection', 'close')
-
- for header, value in headers.items():
- h.putheader(header, value)
-
- h.putheader("Content-Length", str(len(body)))
-
- if self.metadata.get('auth','').lower().startswith('basic'):
- h.putheader("Authorization", self.metadata['auth'])
-
- if self.metadata.get('cookie'):
- h.putheader("Cookie", self.metadata['cookie'])
-
- h.endheaders()
- h.send(body)
- return h.getresponse()
- except:
- # On error return a null response with error info
- class NullResponse:
- def getheader(self, n, d=None):
- return d
-
- def read(self):
- return '(No Response From Server)'
-
- response = NullResponse()
- response.reason = sys.exc_info()[1]
-
- try:
- response.status, response.reason = response.reason
- except ValueError:
- response.status = 0
-
- if response.reason == 'EOF occurred in violation of protocol':
- # Ignore this protocol error as a workaround for
- # broken ssl server implementations
- response.status = 200
-
- return response
-
- def askRetryAfterError(self, response, operation, message=''):
- """Dumps response data"""
- if not message \
- and response.getheader('Bobo-Exception-Type') is not None:
- message = '%s: %s' % (response.getheader('Bobo-Exception-Type'),
- response.getheader('Bobo-Exception-Value'))
- return askRetryCancel('%s:\n%d %s\n%s' % (operation, response.status,
- response.reason, message))
-
-title = 'Zope External Editor'
-
-## Platform specific declarations ##
-
-if win32:
- import Plugins # Assert dependancy
- from win32ui import MessageBox
- from win32process import CreateProcess, GetExitCodeProcess, STARTUPINFO
- from win32event import WaitForSingleObject
- from win32con import MB_OK, MB_OKCANCEL, MB_YESNO, MB_RETRYCANCEL, \
- MB_SYSTEMMODAL, MB_ICONERROR, MB_ICONQUESTION, \
- MB_ICONEXCLAMATION
-
- def errorDialog(message):
- MessageBox(message, title, MB_OK + MB_ICONERROR + MB_SYSTEMMODAL)
-
- def askRetryCancel(message):
- return MessageBox(message, title,
- MB_OK + MB_RETRYCANCEL + MB_ICONEXCLAMATION
- + MB_SYSTEMMODAL) == 4
-
- def askYesNo(message):
- return MessageBox(message, title,
- MB_OK + MB_YESNO + MB_ICONQUESTION +
- MB_SYSTEMMODAL) == 6
-
- class EditorProcess:
- def __init__(self, command):
- """Launch editor process"""
- try:
- logger.debug('CreateProcess: %r', command)
- self.handle, nil, nil, nil = CreateProcess(None, command, None,
- None, 1, 0, None,
- None, STARTUPINFO())
- except pywintypes.error, e:
- fatalError('Error launching editor process\n'
- '(%s):\n%s' % (command, e[2]))
- def wait(self, timeout):
- """Wait for editor to exit or until timeout"""
- WaitForSingleObject(self.handle, int(timeout * 1000.0))
-
- def isAlive(self):
- """Returns true if the editor process is still alive"""
- return GetExitCodeProcess(self.handle) == 259
-
-else: # Posix platform
- from time import sleep
- import re
-
- def has_tk():
- """Sets up a suitable tk root window if one has not
- already been setup. Returns true if tk is happy,
- false if tk throws an error (like its not available)"""
- # create a hidden root window to make Tk happy
- if not locals().has_key('tk_root'):
- try:
- global tk_root
- from Tkinter import Tk
- tk_root = Tk()
- tk_root.withdraw()
- return 1
- except:
- return 0
- return 1
-
- def errorDialog(message):
- """Error dialog box"""
- try:
- if has_tk():
- from tkMessageBox import showerror
- showerror(title, message)
- has_tk()
- finally:
- print message
-
- def askRetryCancel(message):
- if has_tk():
- from tkMessageBox import askretrycancel
- r = askretrycancel(title, message)
- has_tk() # ugh, keeps tk happy
- return r
-
- def askYesNo(message):
- if has_tk():
- from tkMessageBox import askyesno
- r = askyesno(title, message)
- has_tk() # must...make...tk...happy
- return r
-
- class EditorProcess:
- def __init__(self, command):
- """Launch editor process"""
- # Prepare the command arguments, we use this regex to
- # split on whitespace and properly handle quoting
- arg_re = r"""\s*([^'"]\S+)\s+|\s*"([^"]+)"\s*|\s*'([^']+)'\s*"""
- args = re.split(arg_re, command.strip())
- args = filter(None, args) # Remove empty elements
- self.pid = os.spawnvp(os.P_NOWAIT, args[0], args)
-
- def wait(self, timeout):
- """Wait for editor to exit or until timeout"""
- sleep(timeout)
-
- def isAlive(self):
- """Returns true if the editor process is still alive"""
- try:
- exit_pid, exit_status = os.waitpid(self.pid, os.WNOHANG)
- except OSError:
- return 0
- else:
- return exit_pid != self.pid
-
-def fatalError(message, exit=1):
- """Show error message and exit"""
- global log_file
- errorDialog('FATAL ERROR: %s' % message)
- # Write out debug info to a temp file
- debug_f = open(mktemp('-zopeedit-traceback.txt'), 'w')
- try:
- # Copy the log_file before it goes away on a fatalError.
- if log_file is not None:
- log_file.seek(0)
- shutil.copyfileobj(log_file, debug_f)
- print >> debug_f, '-' * 80
- traceback.print_exc(file=debug_f)
- finally:
- debug_f.close()
- if exit:
- sys.exit(0)
-
-default_configuration = """\
-# Zope External Editor helper application configuration
-
-[general]
-# General configuration options
-
-# Uncomment and specify an editor value to override the editor
-# specified in the environment
-#editor =
-
-# Automatic save interval, in seconds. Set to zero for
-# no auto save (save to Zope only on exit).
-save_interval = 1
-
-# Temporary file cleanup. Set to false for debugging or
-# to waste disk space. Note: setting this to false is a
-# security risk to the zope server
-cleanup_files = 1
-
-# Use WebDAV locking to prevent concurrent editing by
-# different users. Disable for single user use or for
-# better performance
-use_locks = 1
-
-# To suppress warnings about borrowing locks on objects
-# locked by you before you began editing you can
-# set this flag. This is useful for applications that
-# use server-side locking, like CMFStaging
-always_borrow_locks = 0
-
-# Specific settings by content-type or meta-type. Specific
-# settings override general options above. Content-type settings
-# override meta-type settings for the same option.
-
-[meta-type:DTML Document]
-extension=.dtml
-
-[meta-type:DTML Method]
-extension=.dtml
-
-[meta-type:Script (Python)]
-extension=.py
-
-[meta-type:Page Template]
-extension=.pt
-
-[meta-type:Z SQL Method]
-extension=.sql
-
-[content-type:text/plain]
-extension=.txt
-
-[content-type:text/html]
-extension=.html
-
-[content-type:text/xml]
-extension=.xml
-
-[content-type:text/css]
-extension=.css
-
-[content-type:text/javascript]
-extension=.js
-
-[content-type:image/*]
-editor=gimp
-
-[content-type:image/gif]
-extension=.gif
-
-[content-type:image/jpeg]
-extension=.jpg
-
-[content-type:image/png]
-extension=.png"""
-
-def main():
- try:
- args = sys.argv
-
- if '--version' in args or '-v' in args:
- credits = ('Zope External Editor %s\n'
- 'By Casey Duncan, Zope Corporation\n'
- 'http://www.zope.com/') % __version__
- if win32:
- errorDialog(credits)
- else:
- print credits
- sys.exit()
-
- input_file = sys.argv[1]
- except IndexError:
- fatalError('Input file name missing.\n'
- 'Usage: zopeedit inputfile')
- try:
- ExternalEditor(input_file).launch()
- except KeyboardInterrupt:
- pass
- except SystemExit:
- pass
- except:
- fatalError(sys.exc_info()[1])
-
-if __name__ == '__main__':
- main()
More information about the checkins
mailing list