Rework default settings handling (fixes #409)

This commit is contained in:
Andy Kittner 2012-11-24 14:22:02 +01:00
parent b75c9f32db
commit c405e9b648

View File

@ -13,13 +13,15 @@
# for python 2.5 support # for python 2.5 support
from __future__ import with_statement from __future__ import with_statement
import os
import sys
import optparse
import socket
import time
import threading
import base64 import base64
import ctypes
import optparse
import os
import socket
import sys
import tempfile
import threading
import time
import webbrowser import webbrowser
import django.conf import django.conf
@ -28,14 +30,15 @@ from django.core.management import execute_from_command_line
CONFIG_TEMPLATE = """#!/usr/bin/env python CONFIG_TEMPLATE = """#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import openslides.main
from openslides.global_settings import * from openslides.global_settings import *
# Use 'DEBUG = True' to get more details for server errors # Use 'DEBUG = True' to get more details for server errors
# (Default for relaeses: 'False') # (Default for releases: 'False')
DEBUG = False DEBUG = False
TEMPLATE_DEBUG = DEBUG TEMPLATE_DEBUG = DEBUG
DBPATH = %(dbpath)r DBPATH = %(dbpath)s
DATABASES = { DATABASES = {
'default': { 'default': {
@ -64,6 +67,10 @@ INSTALLED_APPS += INSTALLED_PLUGINS
KEY_LENGTH = 30 KEY_LENGTH = 30
# sentinel used to signal that the database ought to be stored
# relative to the portable's directory
_portable_db_path = object()
_fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() _fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
def _fs2unicode(s): def _fs2unicode(s):
@ -71,8 +78,7 @@ def _fs2unicode(s):
return s return s
return s.decode(_fs_encoding) return s.decode(_fs_encoding)
def process_options(argv = None):
def main(argv=None, opt_defaults=None, database_path=None):
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]
@ -90,21 +96,48 @@ def main(argv=None, opt_defaults=None, database_path=None):
parser.add_option( parser.add_option(
"--no-reload", action="store_true", help="Do not reload the development server") "--no-reload", action="store_true", help="Do not reload the development server")
if not opt_defaults is None:
parser.set_defaults(**opt_defaults)
opts, args = parser.parse_args(argv) opts, args = parser.parse_args(argv)
if args: if args:
sys.stderr.write("This command does not take arguments!\n\n") sys.stderr.write("This command does not take arguments!\n\n")
parser.print_help() parser.print_help()
sys.exit(1) sys.exit(1)
return opts
def main(argv=None):
opts = process_options(argv)
_main(opts)
def win32_portable_main(argv=None):
"""special entry point for the win32 portable version"""
opts = process_options(argv)
database_path = None
if opts.settings is None:
portable_dir = get_portable_path()
try:
fd, test_file = tempfile.mkstemp(dir=portable_dir)
except OSError:
portable_dir_writeable = False
else:
portable_dir_writeable = True
os.close(fd)
os.unlink(test_file)
if portable_dir_writeable:
opts.settings = os.path.join(portable_dir,
"openslides", "settings.py")
database_path = _portable_db_path
_main(opts, database_path=database_path)
def _main(opts, database_path=None):
# Find the path to the settings # Find the path to the settings
settings_path = opts.settings settings_path = opts.settings
if settings_path is None: if settings_path is None:
config_home = os.environ.get('XDG_CONFIG_HOME', \ settings_path = get_user_config_path('openslides', 'settings.py')
os.path.join(os.path.expanduser('~'), '.config'))
settings_path = os.path.join(config_home, 'openslides', 'settings.py')
# Create settings if necessary # Create settings if necessary
if not os.path.exists(settings_path): if not os.path.exists(settings_path):
@ -141,14 +174,17 @@ def main(argv=None, opt_defaults=None, database_path=None):
def create_settings(settings_path, database_path=None): def create_settings(settings_path, database_path=None):
settings_module = os.path.dirname(settings_path) settings_module = os.path.dirname(settings_path)
if database_path is _portable_db_path:
database_path = get_portable_db_path()
dbpath_value = 'openslides.main.get_portable_db_path()'
else:
if database_path is None: if database_path is None:
data_home = os.environ.get('XDG_DATA_HOME', \ database_path = get_user_data_path('openslides', 'database.sqlite')
os.path.join(os.path.expanduser('~'), '.local', 'share')) dbpath_value = repr(_fs2unicode(database_path))
database_path = os.path.join(data_home, 'openslides', 'database.sqlite')
settings_content = CONFIG_TEMPLATE % dict( settings_content = CONFIG_TEMPLATE % dict(
default_key=base64.b64encode(os.urandom(KEY_LENGTH)), default_key=base64.b64encode(os.urandom(KEY_LENGTH)),
dbpath=_fs2unicode(database_path)) dbpath=dbpath_value)
if not os.path.exists(settings_module): if not os.path.exists(settings_module):
os.makedirs(settings_module) os.makedirs(settings_module)
@ -269,31 +305,41 @@ def start_browser(url):
t = threading.Thread(target=f) t = threading.Thread(target=f)
t.start() t.start()
def win32_portable_main(argv=None): def get_user_config_path(*args):
"""special entry point for the win32 portable version""" if sys.platform == "win32":
import tempfile return win32_get_app_data_path(*args)
config_home = os.environ.get('XDG_CONFIG_HOME', \
os.path.join(os.path.expanduser('~'), '.config'))
return os.path.join(_fs2unicode(config_home), *args)
def get_user_data_path(*args):
if sys.platform == "win32":
return win32_get_app_data_path(*args)
data_home = os.environ.get('XDG_DATA_HOME', \
os.path.join(os.path.expanduser('~'), '.local', 'share'))
return os.path.join(_fs2unicode(data_home), *args)
def get_portable_path(*args):
# NOTE: sys.executable will be the path to openslides.exe # NOTE: sys.executable will be the path to openslides.exe
# since it is essentially a small wrapper that embeds the # since it is essentially a small wrapper that embeds the
# python interpreter # python interpreter
portable_dir = os.path.dirname(os.path.abspath(sys.executable))
try:
fd, test_file = tempfile.mkstemp(dir=portable_dir)
except OSError:
portable_dir_writeable = False
else:
portable_dir_writeable = True
os.close(fd)
os.unlink(test_file)
if portable_dir_writeable: exename = os.path.basename(sys.executable).lower()
default_settings = os.path.join(portable_dir, "openslides", if exename != "openslides.exe":
"openslides_personal_settings.py") raise Exception("Cannot determine portable path when "
database_path = os.path.join(portable_dir, "openslides", "not running as portable")
"database.sqlite")
else:
import ctypes
portable_dir = _fs2unicode(os.path.dirname(os.path.abspath(sys.executable)))
return os.path.join(portable_dir, *args)
def get_portable_db_path():
return get_portable_path('openslides', 'database.sqlite')
def win32_get_app_data_path(*args):
shell32 = ctypes.WinDLL("shell32.dll") shell32 = ctypes.WinDLL("shell32.dll")
SHGetFolderPath = shell32.SHGetFolderPathW SHGetFolderPath = shell32.SHGetFolderPathW
SHGetFolderPath.argtypes = (ctypes.c_void_p, ctypes.c_int, SHGetFolderPath.argtypes = (ctypes.c_void_p, ctypes.c_int,
@ -307,13 +353,8 @@ def win32_portable_main(argv=None):
res = SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, buf) res = SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, buf)
if res != 0: if res != 0:
raise Exception("Could not deterime APPDATA path") raise Exception("Could not deterime APPDATA path")
default_settings = os.path.join(buf.value, "openslides",
"openslides_personal_settings.py")
database_path = os.path.join(buf.value, "openslides",
"database.sqlite")
main(argv, opt_defaults={ "settings": default_settings }, return os.path.join(buf.value, *args)
database_path=database_path)
if __name__ == "__main__": if __name__ == "__main__":