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
from __future__ import with_statement
import os
import sys
import optparse
import socket
import time
import threading
import base64
import ctypes
import optparse
import os
import socket
import sys
import tempfile
import threading
import time
import webbrowser
import django.conf
@ -28,14 +30,15 @@ from django.core.management import execute_from_command_line
CONFIG_TEMPLATE = """#!/usr/bin/env python
# -*- coding: utf-8 -*-
import openslides.main
from openslides.global_settings import *
# Use 'DEBUG = True' to get more details for server errors
# (Default for relaeses: 'False')
# (Default for releases: 'False')
DEBUG = False
TEMPLATE_DEBUG = DEBUG
DBPATH = %(dbpath)r
DBPATH = %(dbpath)s
DATABASES = {
'default': {
@ -64,6 +67,10 @@ INSTALLED_APPS += INSTALLED_PLUGINS
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()
def _fs2unicode(s):
@ -71,8 +78,7 @@ def _fs2unicode(s):
return s
return s.decode(_fs_encoding)
def main(argv=None, opt_defaults=None, database_path=None):
def process_options(argv = None):
if argv is None:
argv = sys.argv[1:]
@ -90,21 +96,48 @@ def main(argv=None, opt_defaults=None, database_path=None):
parser.add_option(
"--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)
if args:
sys.stderr.write("This command does not take arguments!\n\n")
parser.print_help()
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
settings_path = opts.settings
if settings_path is None:
config_home = os.environ.get('XDG_CONFIG_HOME', \
os.path.join(os.path.expanduser('~'), '.config'))
settings_path = os.path.join(config_home, 'openslides', 'settings.py')
settings_path = get_user_config_path('openslides', 'settings.py')
# Create settings if necessary
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):
settings_module = os.path.dirname(settings_path)
if database_path is None:
data_home = os.environ.get('XDG_DATA_HOME', \
os.path.join(os.path.expanduser('~'), '.local', 'share'))
database_path = os.path.join(data_home, 'openslides', 'database.sqlite')
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:
database_path = get_user_data_path('openslides', 'database.sqlite')
dbpath_value = repr(_fs2unicode(database_path))
settings_content = CONFIG_TEMPLATE % dict(
default_key=base64.b64encode(os.urandom(KEY_LENGTH)),
dbpath=_fs2unicode(database_path))
dbpath=dbpath_value)
if not os.path.exists(settings_module):
os.makedirs(settings_module)
@ -269,51 +305,56 @@ def start_browser(url):
t = threading.Thread(target=f)
t.start()
def win32_portable_main(argv=None):
"""special entry point for the win32 portable version"""
import tempfile
def get_user_config_path(*args):
if sys.platform == "win32":
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
# since it is essentially a small wrapper that embeds the
# 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:
default_settings = os.path.join(portable_dir, "openslides",
"openslides_personal_settings.py")
database_path = os.path.join(portable_dir, "openslides",
"database.sqlite")
else:
import ctypes
exename = os.path.basename(sys.executable).lower()
if exename != "openslides.exe":
raise Exception("Cannot determine portable path when "
"not running as portable")
shell32 = ctypes.WinDLL("shell32.dll")
SHGetFolderPath = shell32.SHGetFolderPathW
SHGetFolderPath.argtypes = (ctypes.c_void_p, ctypes.c_int,
ctypes.c_void_p, ctypes.c_uint32, ctypes.c_wchar_p)
SHGetFolderPath.restype = ctypes.c_uint32
portable_dir = _fs2unicode(os.path.dirname(os.path.abspath(sys.executable)))
return os.path.join(portable_dir, *args)
CSIDL_LOCAL_APPDATA = 0x001c
MAX_PATH = 260
def get_portable_db_path():
return get_portable_path('openslides', 'database.sqlite')
buf = ctypes.create_unicode_buffer(MAX_PATH)
res = SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, buf)
if res != 0:
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")
def win32_get_app_data_path(*args):
shell32 = ctypes.WinDLL("shell32.dll")
SHGetFolderPath = shell32.SHGetFolderPathW
SHGetFolderPath.argtypes = (ctypes.c_void_p, ctypes.c_int,
ctypes.c_void_p, ctypes.c_uint32, ctypes.c_wchar_p)
SHGetFolderPath.restype = ctypes.c_uint32
main(argv, opt_defaults={ "settings": default_settings },
database_path=database_path)
CSIDL_LOCAL_APPDATA = 0x001c
MAX_PATH = 260
buf = ctypes.create_unicode_buffer(MAX_PATH)
res = SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, buf)
if res != 0:
raise Exception("Could not deterime APPDATA path")
return os.path.join(buf.value, *args)
if __name__ == "__main__":