Some changes in __main__.py and utils.main and other.
Reinsert --no-browser option. Move some code to utils.main. Some other small style changes. Fix merge conflict misstakes. Change settings behavior. Add tests. Fix rebase problems.
This commit is contained in:
parent
21a1d77e29
commit
a1ad1e4c49
@ -15,17 +15,15 @@ import threading
|
|||||||
import wx
|
import wx
|
||||||
|
|
||||||
import openslides
|
import openslides
|
||||||
|
|
||||||
from openslides.utils.main import (
|
from openslides.utils.main import (
|
||||||
filesystem2unicode,
|
|
||||||
is_portable,
|
|
||||||
detect_openslides_type,
|
detect_openslides_type,
|
||||||
|
filesystem2unicode,
|
||||||
|
get_default_user_data_path,
|
||||||
|
get_port,
|
||||||
get_win32_portable_path,
|
get_win32_portable_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
from openslides.__main__ import (
|
|
||||||
get_port,
|
|
||||||
get_default_settings_path
|
|
||||||
)
|
|
||||||
|
|
||||||
# NOTE: djangos translation module can't be used here since it requires
|
# NOTE: djangos translation module can't be used here since it requires
|
||||||
# a defined settings module
|
# a defined settings module
|
||||||
@ -346,12 +344,14 @@ class MainWindow(wx.Frame):
|
|||||||
self.SetIcons(icons)
|
self.SetIcons(icons)
|
||||||
|
|
||||||
self.server_running = False
|
self.server_running = False
|
||||||
|
|
||||||
|
# Set path for gui settings to default user data according to the
|
||||||
|
# OpenSlides type. This does not depend on any argument the user might
|
||||||
|
# type in.
|
||||||
openslides_type = detect_openslides_type()
|
openslides_type = detect_openslides_type()
|
||||||
# XXX: this works, but I'd prefer keeping get_user_config_path
|
default_user_data_path = get_default_user_data_path(openslides_type)
|
||||||
# it was much clearer what path was intended IMHO ...
|
|
||||||
self.gui_settings_path = os.path.join(
|
self.gui_settings_path = os.path.join(
|
||||||
os.path.dirname(get_default_settings_path(openslides_type)),
|
default_user_data_path, 'openslides', 'gui_settings.json')
|
||||||
"gui_settings.json")
|
|
||||||
|
|
||||||
self.backupdb_enabled = False
|
self.backupdb_enabled = False
|
||||||
self.backupdb_destination = ""
|
self.backupdb_destination = ""
|
||||||
@ -633,9 +633,8 @@ class MainWindow(wx.Frame):
|
|||||||
else:
|
else:
|
||||||
args = ["--address", self._host, "--port", self._port]
|
args = ["--address", self._host, "--port", self._port]
|
||||||
|
|
||||||
# XXX: --no-browser is missing
|
if not self.cb_start_browser.GetValue():
|
||||||
#if not self.cb_start_browser.GetValue():
|
args.append("--no-browser")
|
||||||
# args.append("--no-browser")
|
|
||||||
|
|
||||||
self.server_running = True
|
self.server_running = True
|
||||||
self.cmd_run_ctrl.run_command("start", *args)
|
self.cmd_run_ctrl.run_command("start", *args)
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
from openslides.__main__ import main
|
from openslides.__main__ import main
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,28 +12,29 @@
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import base64
|
import base64
|
||||||
import imp
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
from django.conf import ENVIRONMENT_VARIABLE
|
from django.conf import ENVIRONMENT_VARIABLE
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
from openslides import get_version
|
from openslides import get_version
|
||||||
from openslides.utils.tornado_webserver import run_tornado
|
|
||||||
from openslides.utils.main import (
|
from openslides.utils.main import (
|
||||||
filesystem2unicode,
|
filesystem2unicode,
|
||||||
detect_openslides_type,
|
detect_openslides_type,
|
||||||
|
get_default_user_data_path,
|
||||||
|
get_port,
|
||||||
get_win32_app_data_path,
|
get_win32_app_data_path,
|
||||||
get_win32_portable_path,
|
get_win32_portable_path,
|
||||||
UNIX_VERSION,
|
UNIX_VERSION,
|
||||||
WINDOWS_VERSION,
|
WINDOWS_VERSION,
|
||||||
WINDOWS_PORTABLE_VERSION)
|
WINDOWS_PORTABLE_VERSION)
|
||||||
|
from openslides.utils.tornado_webserver import run_tornado
|
||||||
|
|
||||||
|
|
||||||
SETTINGS_TEMPLATE = """# -*- coding: utf-8 -*-
|
SETTINGS_TEMPLATE = """# -*- coding: utf-8 -*-
|
||||||
@ -75,6 +76,9 @@ INSTALLED_APPS += INSTALLED_PLUGINS
|
|||||||
# Absolute path to the directory that holds media.
|
# Absolute path to the directory that holds media.
|
||||||
# Example: "/home/media/media.lawrence.com/"
|
# Example: "/home/media/media.lawrence.com/"
|
||||||
MEDIA_ROOT = %(media_path_value)s
|
MEDIA_ROOT = %(media_path_value)s
|
||||||
|
|
||||||
|
# Path to Whoosh search index
|
||||||
|
HAYSTACK_CONNECTIONS['default']['PATH'] = %(whoosh_index_path_value)s
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@ -86,25 +90,35 @@ def main():
|
|||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
|
||||||
# Setup settings path: Take it either from command line or get default path
|
# Setup settings path: Take it either from command line or get default path
|
||||||
if not hasattr(args, 'settings') or not args.settings:
|
if hasattr(args, 'settings') and args.settings:
|
||||||
|
settings = args.settings
|
||||||
|
setup_django_settings_module(settings)
|
||||||
|
else:
|
||||||
|
if ENVIRONMENT_VARIABLE not in os.environ:
|
||||||
openslides_type = detect_openslides_type()
|
openslides_type = detect_openslides_type()
|
||||||
args.settings = get_default_settings_path(openslides_type)
|
settings = get_default_settings_path(openslides_type)
|
||||||
|
setup_django_settings_module(settings)
|
||||||
|
else:
|
||||||
|
# The environment variable is set, so we do not need to process
|
||||||
|
# anything more here.
|
||||||
|
settings = None
|
||||||
|
|
||||||
# Create settings if if still does not exist.
|
# Create settings if if still does not exist.
|
||||||
if not os.path.exists(args.settings):
|
if settings and not os.path.exists(settings):
|
||||||
# Setup path for local data (SQLite3 database, media, search index, ...):
|
# Setup path for user specific data (SQLite3 database, media, search index, ...):
|
||||||
# Take it either from command line or get default path
|
# Take it either from command line or get default path
|
||||||
if not hasattr(args, 'localpath') or not args.localpath:
|
if hasattr(args, 'user_data_path') and args.user_data_path:
|
||||||
openslides_type = detect_openslides_type()
|
user_data_path_values = get_user_data_path_values(
|
||||||
args.localpath = get_default_local_path(openslides_type)
|
user_data_path=args.user_data_path,
|
||||||
localpath_values = get_localpath_values(localpath=args.localpath, default=True, openslides_type=openslides_type)
|
default=False)
|
||||||
else:
|
else:
|
||||||
localpath_values = get_localpath_values(localpath=args.localpath, default=False)
|
openslides_type = detect_openslides_type()
|
||||||
create_settings(args.settings, localpath_values)
|
args.user_data_path = get_default_user_data_path(openslides_type)
|
||||||
|
user_data_path_values = get_user_data_path_values(
|
||||||
# Setup DJANGO_SETTINGS_MODULE environment variable
|
user_data_path=args.user_data_path,
|
||||||
if 'DJANGO_SETTINGS_MODULE' not in os.environ:
|
default=True,
|
||||||
setup_django_settings_module(args.settings)
|
openslides_type=openslides_type)
|
||||||
|
create_settings(settings, user_data_path_values)
|
||||||
|
|
||||||
# Process the subcommand's callback
|
# Process the subcommand's callback
|
||||||
return args.callback(args)
|
return args.callback(args)
|
||||||
@ -118,62 +132,48 @@ def parse_args():
|
|||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
sys.argv.append('start')
|
sys.argv.append('start')
|
||||||
|
|
||||||
|
# Init parser
|
||||||
description = 'Start script for OpenSlides.'
|
description = 'Start script for OpenSlides.'
|
||||||
if 'manage.py' not in sys.argv[0]:
|
if 'manage.py' not in sys.argv[0]:
|
||||||
description += (' If it is called without any argument, this will be '
|
description += (' If it is called without any argument, this will be '
|
||||||
'treated as if it is called with the "start" subcommand. '
|
'treated as if it is called with the "start" subcommand. '
|
||||||
'That means OpenSlides will setup settings and database, '
|
'That means OpenSlides will setup default settings and '
|
||||||
'start the tornado webserver, launch the default web '
|
'database, start the tornado webserver, launch the '
|
||||||
'browser and open the webinterface.')
|
'default web browser and open the webinterface.')
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description=description)
|
parser = argparse.ArgumentParser(description=description)
|
||||||
|
|
||||||
|
# Add version argument
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--version',
|
'--version',
|
||||||
action='version',
|
action='version',
|
||||||
version=get_version(),
|
version=get_version(),
|
||||||
help='Show version number and exit.')
|
help='Show version number and exit.')
|
||||||
|
|
||||||
|
# Init subparsers
|
||||||
subparsers = parser.add_subparsers(
|
subparsers = parser.add_subparsers(
|
||||||
dest='subcommand',
|
dest='subcommand',
|
||||||
title='Available subcommands',
|
title='Available subcommands',
|
||||||
description="Type 'python %s <subcommand> --help' for help on a specific subcommand." % parser.prog,
|
description="Type 'python %s <subcommand> --help' for help on a "
|
||||||
|
"specific subcommand." % parser.prog,
|
||||||
help='You can choose only one subcommand at once.')
|
help='You can choose only one subcommand at once.')
|
||||||
|
|
||||||
settings_args, settings_kwargs = (
|
|
||||||
('-s', '--settings'),
|
|
||||||
dict(help='Path to settings file.'))
|
|
||||||
localpath_args, localpath_kwargs = (
|
|
||||||
('-l', '--localpath'),
|
|
||||||
dict(help='Path to the directory for local files like SQLite3 database, '
|
|
||||||
'uploaded media and search index. This is only used, when a new '
|
|
||||||
'settings file is created.'))
|
|
||||||
address_args, address_kwargs = (
|
|
||||||
('-a', '--address',),
|
|
||||||
dict(default='0.0.0.0', help='IP address to listen on. Default is %(default)s.'))
|
|
||||||
port_args, port_kwargs = (
|
|
||||||
('-p', '--port'),
|
|
||||||
dict(type=int, default=80, help='Port to listen on. Default as admin or root is %(default)d, else 8000.'))
|
|
||||||
|
|
||||||
# Subcommand start
|
# Subcommand start
|
||||||
subcommand_start = subparsers.add_parser(
|
subcommand_start = subparsers.add_parser(
|
||||||
'start',
|
'start',
|
||||||
help='Setup settings and database, start tornado webserver, launch the '
|
help='Setup settings and database, start tornado webserver, launch the '
|
||||||
'default web browser and open the webinterface.')
|
'default web browser and open the webinterface.')
|
||||||
subcommand_start.add_argument(*settings_args, **settings_kwargs)
|
add_general_arguments(subcommand_start, ('settings', 'user_data_path', 'address', 'port'))
|
||||||
subcommand_start.add_argument(*localpath_args, **localpath_kwargs)
|
subcommand_start.add_argument(
|
||||||
subcommand_start.add_argument(*address_args, **address_kwargs)
|
'--no-browser',
|
||||||
subcommand_start.add_argument(*port_args, **port_kwargs)
|
action='store_true',
|
||||||
|
help='Do not launch the default web browser.')
|
||||||
subcommand_start.set_defaults(callback=start)
|
subcommand_start.set_defaults(callback=start)
|
||||||
|
|
||||||
# Subcommand runserver
|
# Subcommand runserver
|
||||||
subcommand_runserver = subparsers.add_parser(
|
subcommand_runserver = subparsers.add_parser(
|
||||||
'runserver',
|
'runserver',
|
||||||
help='Run OpenSlides using tornado webserver.')
|
help='Run OpenSlides using tornado webserver.')
|
||||||
subcommand_runserver.add_argument(*settings_args, **settings_kwargs)
|
add_general_arguments(subcommand_runserver, ('settings', 'user_data_path', 'address', 'port'))
|
||||||
subcommand_runserver.add_argument(*localpath_args, **localpath_kwargs)
|
|
||||||
subcommand_runserver.add_argument(*address_args, **address_kwargs)
|
|
||||||
subcommand_runserver.add_argument(*port_args, **port_kwargs)
|
|
||||||
subcommand_runserver.add_argument(
|
subcommand_runserver.add_argument(
|
||||||
'--start-browser',
|
'--start-browser',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@ -188,24 +188,21 @@ def parse_args():
|
|||||||
subcommand_syncdb = subparsers.add_parser(
|
subcommand_syncdb = subparsers.add_parser(
|
||||||
'syncdb',
|
'syncdb',
|
||||||
help='Create or update database tables.')
|
help='Create or update database tables.')
|
||||||
subcommand_syncdb.add_argument(*settings_args, **settings_kwargs)
|
add_general_arguments(subcommand_syncdb, ('settings', 'user_data_path'))
|
||||||
subcommand_syncdb.add_argument(*localpath_args, **localpath_kwargs)
|
|
||||||
subcommand_syncdb.set_defaults(callback=syncdb)
|
subcommand_syncdb.set_defaults(callback=syncdb)
|
||||||
|
|
||||||
# Subcommand createsuperuser
|
# Subcommand createsuperuser
|
||||||
subcommand_createsuperuser = subparsers.add_parser(
|
subcommand_createsuperuser = subparsers.add_parser(
|
||||||
'createsuperuser',
|
'createsuperuser',
|
||||||
help="Make sure the user 'admin' exists and uses 'admin' as password.")
|
help="Make sure the user 'admin' exists and uses 'admin' as password.")
|
||||||
subcommand_createsuperuser.add_argument(*settings_args, **settings_kwargs)
|
add_general_arguments(subcommand_createsuperuser, ('settings', 'user_data_path'))
|
||||||
subcommand_createsuperuser.add_argument(*localpath_args, **localpath_kwargs)
|
|
||||||
subcommand_createsuperuser.set_defaults(callback=createsuperuser)
|
subcommand_createsuperuser.set_defaults(callback=createsuperuser)
|
||||||
|
|
||||||
# Subcommand backupdb
|
# Subcommand backupdb
|
||||||
subcommand_backupdb = subparsers.add_parser(
|
subcommand_backupdb = subparsers.add_parser(
|
||||||
'backupdb',
|
'backupdb',
|
||||||
help='Store a backup copy of the SQLite3 database.')
|
help='Store a backup copy of the SQLite3 database at the given path.')
|
||||||
subcommand_backupdb.add_argument(*settings_args, **settings_kwargs)
|
add_general_arguments(subcommand_backupdb, ('settings', 'user_data_path'))
|
||||||
subcommand_backupdb.add_argument(*localpath_args, **localpath_kwargs)
|
|
||||||
subcommand_backupdb.add_argument(
|
subcommand_backupdb.add_argument(
|
||||||
'path',
|
'path',
|
||||||
help='Path to the backup file. An existing file will be overwritten.')
|
help='Path to the backup file. An existing file will be overwritten.')
|
||||||
@ -215,14 +212,14 @@ def parse_args():
|
|||||||
subcommand_deletedb = subparsers.add_parser(
|
subcommand_deletedb = subparsers.add_parser(
|
||||||
'deletedb',
|
'deletedb',
|
||||||
help='Delete the SQLite3 database.')
|
help='Delete the SQLite3 database.')
|
||||||
subcommand_deletedb.add_argument(*settings_args, **settings_kwargs)
|
add_general_arguments(subcommand_deletedb, ('settings', 'user_data_path'))
|
||||||
subcommand_deletedb.add_argument(*localpath_args, **localpath_kwargs)
|
|
||||||
subcommand_deletedb.set_defaults(callback=deletedb)
|
subcommand_deletedb.set_defaults(callback=deletedb)
|
||||||
|
|
||||||
# Subcommand django
|
# Subcommand django
|
||||||
subcommand_django_command_line_utility = subparsers.add_parser(
|
subcommand_django_command_line_utility = subparsers.add_parser(
|
||||||
'django',
|
'django',
|
||||||
description="Link to Django's command-line utility. Type 'python %s django help' for more help on this." % parser.prog,
|
description="Link to Django's command-line utility. Type "
|
||||||
|
"'python %s django help' for more help on this." % parser.prog,
|
||||||
help="Call Django's command-line utility.")
|
help="Call Django's command-line utility.")
|
||||||
subcommand_django_command_line_utility.set_defaults(
|
subcommand_django_command_line_utility.set_defaults(
|
||||||
callback=django_command_line_utility,
|
callback=django_command_line_utility,
|
||||||
@ -241,6 +238,45 @@ def parse_args():
|
|||||||
return known_args
|
return known_args
|
||||||
|
|
||||||
|
|
||||||
|
def add_general_arguments(subcommand, arguments):
|
||||||
|
"""
|
||||||
|
Adds the named arguments to the subcommand.
|
||||||
|
"""
|
||||||
|
general_arguments = {}
|
||||||
|
openslides_type = detect_openslides_type()
|
||||||
|
|
||||||
|
general_arguments['settings'] = (
|
||||||
|
('-s', '--settings'),
|
||||||
|
dict(help="Path to settings file. If this isn't provided, the "
|
||||||
|
"%s environment variable will be used. "
|
||||||
|
"If this isn't provided too, a default path according to the "
|
||||||
|
"OpenSlides type will be used. At the moment it is %s" % (
|
||||||
|
ENVIRONMENT_VARIABLE,
|
||||||
|
get_default_settings_path(openslides_type))))
|
||||||
|
general_arguments['user_data_path'] = (
|
||||||
|
('-d', '--user-data-path'),
|
||||||
|
dict(help='Path to the directory for user specific data files like SQLite3 '
|
||||||
|
'database, uploaded media and search index. This is only used, '
|
||||||
|
'when a new settings file is created. The given path is only '
|
||||||
|
'written into the new settings file. Default according to the '
|
||||||
|
'OpenSlides is at the moment %s' % get_default_user_data_path(openslides_type)))
|
||||||
|
general_arguments['address'] = (
|
||||||
|
('-a', '--address',),
|
||||||
|
dict(default='0.0.0.0', help='IP address to listen on. Default is %(default)s.'))
|
||||||
|
general_arguments['port'] = (
|
||||||
|
('-p', '--port'),
|
||||||
|
dict(type=int,
|
||||||
|
default=80,
|
||||||
|
help='Port to listen on. Default as admin or root is %(default)d, else 8000.'))
|
||||||
|
|
||||||
|
for argument in arguments:
|
||||||
|
try:
|
||||||
|
args, kwargs = general_arguments[argument]
|
||||||
|
except KeyError:
|
||||||
|
raise TypeError('The argument %s is not a valid general argument.' % argument)
|
||||||
|
subcommand.add_argument(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def get_default_settings_path(openslides_type):
|
def get_default_settings_path(openslides_type):
|
||||||
"""
|
"""
|
||||||
Returns the default settings path according to the OpenSlides type.
|
Returns the default settings path according to the OpenSlides type.
|
||||||
@ -260,54 +296,44 @@ def get_default_settings_path(openslides_type):
|
|||||||
return os.path.join(parent_directory, 'openslides', 'settings.py')
|
return os.path.join(parent_directory, 'openslides', 'settings.py')
|
||||||
|
|
||||||
|
|
||||||
def get_default_local_path(openslides_type):
|
def get_user_data_path_values(user_data_path, default=False, openslides_type=None):
|
||||||
"""
|
"""
|
||||||
Returns the default local path according to the OpenSlides type.
|
Returns a dictionary of the user specific data path values for the new
|
||||||
|
settings file.
|
||||||
|
|
||||||
The argument 'openslides_type' has to be one of the three types mentioned in
|
The argument 'user_data_path' is a path to the directory where OpenSlides
|
||||||
openslides.utils.main.
|
should store the user specific data like SQLite3 database, media and search
|
||||||
"""
|
index.
|
||||||
if openslides_type == UNIX_VERSION:
|
|
||||||
default_local_path = filesystem2unicode(os.environ.get(
|
|
||||||
'XDG_DATA_HOME', os.path.join(os.path.expanduser('~'), '.local', 'share')))
|
|
||||||
elif openslides_type == WINDOWS_VERSION:
|
|
||||||
default_local_path = get_win32_app_data_path()
|
|
||||||
elif openslides_type == WINDOWS_PORTABLE_VERSION:
|
|
||||||
default_local_path = get_win32_portable_path()
|
|
||||||
else:
|
|
||||||
raise TypeError('%s is not a valid OpenSlides type.' % openslides_type)
|
|
||||||
return default_local_path
|
|
||||||
|
|
||||||
|
|
||||||
def get_localpath_values(localpath, default=False, openslides_type=None):
|
|
||||||
"""
|
|
||||||
Returns the local path values for the new settings file.
|
|
||||||
|
|
||||||
The argument 'localpath' is a path to the directory where OpenSlides should
|
|
||||||
store the local data like SQLite3 database, media and search index.
|
|
||||||
|
|
||||||
The argument 'default' is a simple flag. If it is True and the OpenSlides
|
The argument 'default' is a simple flag. If it is True and the OpenSlides
|
||||||
type is the Windows portable version, this function returns callable
|
type is the Windows portable version, the returned dictionary contains
|
||||||
functions for the settings file, else it returns string paths.
|
strings of callable functions for the settings file, else it contains
|
||||||
|
string paths.
|
||||||
|
|
||||||
The argument 'openslides_type' can to be one of the three types mentioned in
|
The argument 'openslides_type' can to be one of the three types mentioned in
|
||||||
openslides.utils.main.
|
openslides.utils.main.
|
||||||
"""
|
"""
|
||||||
localpath_values = {}
|
user_data_path_values = {}
|
||||||
if default and openslides_type == WINDOWS_PORTABLE_VERSION:
|
if default and openslides_type == WINDOWS_PORTABLE_VERSION:
|
||||||
localpath_values['import_function'] = 'from openslides.utils.main import get_portable_paths'
|
user_data_path_values['import_function'] = 'from openslides.utils.main import get_portable_paths'
|
||||||
localpath_values['database_path_value'] = "get_portable_paths('database')"
|
user_data_path_values['database_path_value'] = "get_portable_paths('database')"
|
||||||
localpath_values['media_path_value'] = "get_portable_paths('media')"
|
user_data_path_values['media_path_value'] = "get_portable_paths('media')"
|
||||||
|
user_data_path_values['whoosh_index_path_value'] = "get_portable_paths('whoosh_index')"
|
||||||
else:
|
else:
|
||||||
localpath_values['import_function'] = ''
|
user_data_path_values['import_function'] = ''
|
||||||
# TODO: Decide whether to use only absolute paths here.
|
# TODO: Decide whether to use only absolute paths here.
|
||||||
localpath_values['database_path_value'] = "'%s'" % os.path.join(localpath, 'openslides', 'database.sqlite')
|
user_data_path_values['database_path_value'] = "'%s'" % os.path.join(
|
||||||
|
user_data_path, 'openslides', 'database.sqlite')
|
||||||
# TODO: Decide whether to use only absolute paths here.
|
# TODO: Decide whether to use only absolute paths here.
|
||||||
localpath_values['media_path_value'] = "'%s'" % os.path.join(localpath, 'openslides', 'media', '')
|
user_data_path_values['media_path_value'] = "'%s'" % os.path.join(
|
||||||
return localpath_values
|
user_data_path, 'openslides', 'media', '')
|
||||||
|
# TODO: Decide whether to use only absolute paths here.
|
||||||
|
user_data_path_values['whoosh_index_path_value'] = "'%s'" % os.path.join(
|
||||||
|
user_data_path, 'openslides', 'whoosh_index', '')
|
||||||
|
return user_data_path_values
|
||||||
|
|
||||||
|
|
||||||
def create_settings(settings_path, local_path_values):
|
def create_settings(settings_path, user_data_path_values):
|
||||||
"""
|
"""
|
||||||
Creates the settings file at the given path using the given values for the
|
Creates the settings file at the given path using the given values for the
|
||||||
file template.
|
file template.
|
||||||
@ -316,7 +342,7 @@ def create_settings(settings_path, local_path_values):
|
|||||||
if not os.path.exists(settings_module):
|
if not os.path.exists(settings_module):
|
||||||
os.makedirs(settings_module)
|
os.makedirs(settings_module)
|
||||||
context = {'secret_key': base64.b64encode(os.urandom(30))}
|
context = {'secret_key': base64.b64encode(os.urandom(30))}
|
||||||
context.update(local_path_values)
|
context.update(user_data_path_values)
|
||||||
settings_content = SETTINGS_TEMPLATE % context
|
settings_content = SETTINGS_TEMPLATE % context
|
||||||
with open(settings_path, 'w') as settings_file:
|
with open(settings_path, 'w') as settings_file:
|
||||||
settings_file.write(settings_content)
|
settings_file.write(settings_content)
|
||||||
@ -325,25 +351,24 @@ def create_settings(settings_path, local_path_values):
|
|||||||
|
|
||||||
def setup_django_settings_module(settings_path):
|
def setup_django_settings_module(settings_path):
|
||||||
"""
|
"""
|
||||||
Sets the environment variable DJANGO_SETTINGS_MODULE to the given settings.
|
Sets the environment variable ENVIRONMENT_VARIABLE, that means
|
||||||
|
'DJANGO_SETTINGS_MODULE', to the given settings.
|
||||||
"""
|
"""
|
||||||
settings_file = os.path.basename(settings_path)
|
settings_file = os.path.basename(settings_path)
|
||||||
settings_module_name = "".join(settings_file.split('.')[:-1])
|
settings_module_name = ".".join(settings_file.split('.')[:-1])
|
||||||
if '.' in settings_module_name:
|
if '.' in settings_module_name:
|
||||||
print("'.' is not an allowed character in the settings-file")
|
raise ImproperlyConfigured("'.' is not an allowed character in the settings-file")
|
||||||
sys.exit(1)
|
settings_module_dir = os.path.dirname(settings_path) # TODO: Use absolute path here or not?
|
||||||
settings_module_dir = os.path.dirname(settings_path)
|
sys.path.insert(0, settings_module_dir)
|
||||||
sys.path.append(settings_module_dir)
|
|
||||||
os.environ[ENVIRONMENT_VARIABLE] = '%s' % settings_module_name
|
os.environ[ENVIRONMENT_VARIABLE] = '%s' % settings_module_name
|
||||||
|
|
||||||
|
|
||||||
def start(args):
|
def start(args):
|
||||||
"""
|
"""
|
||||||
Starts OpenSlides: Runs syncdb and runs runserver (tornado webserver) with
|
Starts OpenSlides: Runs syncdb and runs runserver (tornado webserver).
|
||||||
the flag 'start_browser'.
|
|
||||||
"""
|
"""
|
||||||
syncdb(args)
|
syncdb(args)
|
||||||
args.start_browser = True
|
args.start_browser = not args.no_browser
|
||||||
args.no_reload = False
|
args.no_reload = False
|
||||||
runserver(args)
|
runserver(args)
|
||||||
|
|
||||||
@ -360,27 +385,6 @@ def runserver(args):
|
|||||||
run_tornado(args.address, port, not args.no_reload)
|
run_tornado(args.address, port, not args.no_reload)
|
||||||
|
|
||||||
|
|
||||||
def get_port(address, port):
|
|
||||||
"""
|
|
||||||
Returns the port for the server. If port 80 is given, checks if it is
|
|
||||||
available. If not returns port 8000.
|
|
||||||
|
|
||||||
The argument 'address' should be an IP address. The argument 'port' should
|
|
||||||
be an integer.
|
|
||||||
"""
|
|
||||||
if port == 80:
|
|
||||||
# test if we can use port 80
|
|
||||||
s = socket.socket()
|
|
||||||
try:
|
|
||||||
s.bind((address, port))
|
|
||||||
s.listen(-1)
|
|
||||||
except socket.error:
|
|
||||||
port = 8000
|
|
||||||
finally:
|
|
||||||
s.close()
|
|
||||||
return port
|
|
||||||
|
|
||||||
|
|
||||||
def get_browser_url(address, port):
|
def get_browser_url(address, port):
|
||||||
"""
|
"""
|
||||||
Returns the url to open the web browser.
|
Returns the url to open the web browser.
|
||||||
@ -418,15 +422,16 @@ def syncdb(args):
|
|||||||
Run syncdb to create or update the database.
|
Run syncdb to create or update the database.
|
||||||
"""
|
"""
|
||||||
# TODO: Check use of filesystem2unicode here.
|
# TODO: Check use of filesystem2unicode here.
|
||||||
path = filesystem2unicode(os.path.dirname(get_database_path_from_settings(args.settings)))
|
path = filesystem2unicode(os.path.dirname(get_database_path_from_settings()))
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
execute_from_command_line(["", "syncdb", "--noinput"])
|
execute_from_command_line(["", "syncdb", "--noinput"])
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def get_database_path_from_settings(settings_path):
|
def get_database_path_from_settings():
|
||||||
"""
|
"""
|
||||||
Retrieves the database path out of the given settings file. Returns None,
|
Retrieves the database path out of the settings file. Returns None,
|
||||||
if it is not a SQLite3 database.
|
if it is not a SQLite3 database.
|
||||||
"""
|
"""
|
||||||
from django.conf import settings as django_settings
|
from django.conf import settings as django_settings
|
||||||
@ -460,7 +465,7 @@ def createsuperuser(args):
|
|||||||
|
|
||||||
def backupdb(args):
|
def backupdb(args):
|
||||||
"""
|
"""
|
||||||
Stores a backup copy of the SQlite3 database.
|
Stores a backup copy of the SQlite3 database. Returns 0 on success, else 1.
|
||||||
"""
|
"""
|
||||||
from django.db import connection, transaction
|
from django.db import connection, transaction
|
||||||
|
|
||||||
@ -474,18 +479,19 @@ def backupdb(args):
|
|||||||
# now copy the file
|
# now copy the file
|
||||||
try:
|
try:
|
||||||
shutil.copy(src_path, dest_path)
|
shutil.copy(src_path, dest_path)
|
||||||
except IOError as e:
|
except IOError:
|
||||||
raise Exception("Database backup failed.")
|
raise Exception("Database backup failed.")
|
||||||
# and release the lock again
|
# and release the lock again
|
||||||
transaction.commit()
|
transaction.commit()
|
||||||
|
|
||||||
database_path = get_database_path_from_settings(args.settings)
|
database_path = get_database_path_from_settings()
|
||||||
if database_path:
|
if database_path:
|
||||||
do_backup(database_path, args.path)
|
do_backup(database_path, args.path)
|
||||||
print('Database %s successfully stored at %s.' % (database_path, args.path))
|
print('Database %s successfully stored at %s.' % (database_path, args.path))
|
||||||
return_value = 0
|
return_value = 0
|
||||||
else:
|
else:
|
||||||
print('Error: Default database is not SQLite3. Only SQLite3 databases can currently be backuped.')
|
print('Error: Default database is not SQLite3. Only SQLite3 databases '
|
||||||
|
'can currently be backuped.')
|
||||||
return_value = 1
|
return_value = 1
|
||||||
return return_value
|
return return_value
|
||||||
|
|
||||||
@ -494,7 +500,7 @@ def deletedb(args):
|
|||||||
"""
|
"""
|
||||||
Deletes the sqlite3 database. Returns 0 on success, else 1.
|
Deletes the sqlite3 database. Returns 0 on success, else 1.
|
||||||
"""
|
"""
|
||||||
database_path = get_database_path_from_settings(args.settings)
|
database_path = get_database_path_from_settings()
|
||||||
if database_path and os.path.exists(database_path):
|
if database_path and os.path.exists(database_path):
|
||||||
os.remove(database_path)
|
os.remove(database_path)
|
||||||
print('SQLite3 database file %s successfully deleted.' % database_path)
|
print('SQLite3 database file %s successfully deleted.' % database_path)
|
||||||
@ -518,7 +524,8 @@ def django_command_line_utility(args):
|
|||||||
else:
|
else:
|
||||||
command = None
|
command = None
|
||||||
if command:
|
if command:
|
||||||
print("Error: The command '%s' is disabled for use via Django's command line utility." % command)
|
print("Error: The command '%s' is disabled in OpenSlides for use via Django's "
|
||||||
|
"command line utility." % command)
|
||||||
return_value = 1
|
return_value = 1
|
||||||
else:
|
else:
|
||||||
execute_from_command_line(args.django_args)
|
execute_from_command_line(args.django_args)
|
||||||
|
@ -67,11 +67,9 @@ STATICFILES_DIRS = (
|
|||||||
filesystem2unicode(os.path.join(SITE_ROOT, 'static')),
|
filesystem2unicode(os.path.join(SITE_ROOT, 'static')),
|
||||||
)
|
)
|
||||||
|
|
||||||
#XXX: Note this setting (as well as our workaround finder)
|
|
||||||
# can be removed again once django-bug-#18404 has been resolved
|
|
||||||
STATICFILES_FINDERS = (
|
STATICFILES_FINDERS = (
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||||
'openslides.utils.staticfiles.AppDirectoriesFinder',
|
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||||
)
|
)
|
||||||
|
|
||||||
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
||||||
|
@ -10,9 +10,10 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import ctypes
|
import ctypes
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
|
||||||
@ -20,9 +21,11 @@ UNIX_VERSION = 'Unix Version'
|
|||||||
WINDOWS_VERSION = 'Windows Version'
|
WINDOWS_VERSION = 'Windows Version'
|
||||||
WINDOWS_PORTABLE_VERSION = 'Windows Portable Version'
|
WINDOWS_PORTABLE_VERSION = 'Windows Portable Version'
|
||||||
|
|
||||||
|
|
||||||
class PortableDirNotWritable(Exception):
|
class PortableDirNotWritable(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def filesystem2unicode(path):
|
def filesystem2unicode(path):
|
||||||
"""
|
"""
|
||||||
Transforms a path string to unicode according to the filesystem's encoding.
|
Transforms a path string to unicode according to the filesystem's encoding.
|
||||||
@ -36,7 +39,7 @@ def filesystem2unicode(path):
|
|||||||
|
|
||||||
def detect_openslides_type():
|
def detect_openslides_type():
|
||||||
"""
|
"""
|
||||||
Returns the type of this version.
|
Returns the type of this OpenSlides version.
|
||||||
"""
|
"""
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
if os.path.basename(sys.executable).lower() == 'openslides.exe':
|
if os.path.basename(sys.executable).lower() == 'openslides.exe':
|
||||||
@ -54,12 +57,24 @@ def detect_openslides_type():
|
|||||||
return openslides_type
|
return openslides_type
|
||||||
|
|
||||||
|
|
||||||
def is_portable():
|
def get_default_user_data_path(openslides_type):
|
||||||
"""
|
"""
|
||||||
Helper function just for the GUI.
|
Returns the default path for user specific data according to the OpenSlides
|
||||||
|
type.
|
||||||
|
|
||||||
|
The argument 'openslides_type' has to be one of the three types mentioned
|
||||||
|
in openslides.utils.main.
|
||||||
"""
|
"""
|
||||||
# TODO: Remove this function.
|
if openslides_type == UNIX_VERSION:
|
||||||
return detect_openslides_type() == WINDOWS_PORTABLE_VERSION
|
default_user_data_path = filesystem2unicode(os.environ.get(
|
||||||
|
'XDG_DATA_HOME', os.path.join(os.path.expanduser('~'), '.local', 'share')))
|
||||||
|
elif openslides_type == WINDOWS_VERSION:
|
||||||
|
default_user_data_path = get_win32_app_data_path()
|
||||||
|
elif openslides_type == WINDOWS_PORTABLE_VERSION:
|
||||||
|
default_user_data_path = get_win32_portable_path()
|
||||||
|
else:
|
||||||
|
raise TypeError('%s is not a valid OpenSlides type.' % openslides_type)
|
||||||
|
return default_user_data_path
|
||||||
|
|
||||||
|
|
||||||
def get_win32_app_data_path():
|
def get_win32_app_data_path():
|
||||||
@ -79,7 +94,7 @@ def get_win32_app_data_path():
|
|||||||
buf = ctypes.create_unicode_buffer(MAX_PATH)
|
buf = ctypes.create_unicode_buffer(MAX_PATH)
|
||||||
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 determine Windows' APPDATA path")
|
||||||
|
|
||||||
return buf.value
|
return buf.value
|
||||||
|
|
||||||
@ -97,7 +112,7 @@ def get_win32_portable_path():
|
|||||||
except OSError:
|
except OSError:
|
||||||
raise PortableDirNotWritable(
|
raise PortableDirNotWritable(
|
||||||
'Portable directory is not writeable. '
|
'Portable directory is not writeable. '
|
||||||
'Please choose another directory for settings and local files.')
|
'Please choose another directory for settings and data files.')
|
||||||
else:
|
else:
|
||||||
os.close(fd)
|
os.close(fd)
|
||||||
os.unlink(test_file)
|
os.unlink(test_file)
|
||||||
@ -107,13 +122,36 @@ def get_win32_portable_path():
|
|||||||
def get_portable_paths(name):
|
def get_portable_paths(name):
|
||||||
"""
|
"""
|
||||||
Returns the paths for the Windows portable version on runtime for the
|
Returns the paths for the Windows portable version on runtime for the
|
||||||
SQLite3 database and the media directory. The argument 'name' can be
|
SQLite3 database, the media directory and the search index. The argument
|
||||||
'database' or 'media'.
|
'name' can be 'database', 'media' or 'whoosh_index'.
|
||||||
"""
|
"""
|
||||||
if name == 'database':
|
if name == 'database':
|
||||||
path = os.path.join(get_win32_portable_path(), 'openslides', 'database.sqlite')
|
path = os.path.join(get_win32_portable_path(), 'openslides', 'database.sqlite')
|
||||||
elif name == 'media':
|
elif name == 'media':
|
||||||
path = os.path.join(get_win32_portable_path(), 'openslides', 'media', '')
|
path = os.path.join(get_win32_portable_path(), 'openslides', 'media', '')
|
||||||
|
elif name == 'whoosh_index':
|
||||||
|
path = os.path.join(get_win32_portable_path(), 'openslides', 'whoosh_index', '')
|
||||||
else:
|
else:
|
||||||
raise TypeError('Unknow type %s' % name)
|
raise TypeError('Unknown type %s' % name)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def get_port(address, port):
|
||||||
|
"""
|
||||||
|
Returns the port for the server. If port 80 is given, checks if it is
|
||||||
|
available. If not returns port 8000.
|
||||||
|
|
||||||
|
The argument 'address' should be an IP address. The argument 'port' should
|
||||||
|
be an integer.
|
||||||
|
"""
|
||||||
|
if port == 80:
|
||||||
|
# test if we can use port 80
|
||||||
|
s = socket.socket()
|
||||||
|
try:
|
||||||
|
s.bind((address, port))
|
||||||
|
s.listen(-1)
|
||||||
|
except socket.error:
|
||||||
|
port = 8000
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
return port
|
||||||
|
67
tests/utils/test_main.py
Normal file
67
tests/utils/test_main.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Tests for openslides.utils.main
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
||||||
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
|
from openslides.__main__ import (
|
||||||
|
get_default_settings_path,
|
||||||
|
get_browser_url,
|
||||||
|
get_user_data_path_values,
|
||||||
|
setup_django_settings_module)
|
||||||
|
from openslides.utils.test import TestCase
|
||||||
|
from openslides.utils.main import (
|
||||||
|
get_default_user_data_path,
|
||||||
|
UNIX_VERSION,
|
||||||
|
WINDOWS_PORTABLE_VERSION)
|
||||||
|
|
||||||
|
|
||||||
|
class TestFunctions(TestCase):
|
||||||
|
def test_get_default_user_data_path(self):
|
||||||
|
self.assertTrue('.local/share' in get_default_user_data_path(UNIX_VERSION))
|
||||||
|
|
||||||
|
def test_get_default_settings_path(self):
|
||||||
|
self.assertTrue('.config/openslides/settings.py' in get_default_settings_path(UNIX_VERSION))
|
||||||
|
|
||||||
|
def test_get_user_data_path_values_case_one(self):
|
||||||
|
self.assertEqual(
|
||||||
|
get_user_data_path_values('test_path_dfhvndshfgsef', default=False),
|
||||||
|
{'import_function': '',
|
||||||
|
'database_path_value': "'test_path_dfhvndshfgsef/openslides/database.sqlite'",
|
||||||
|
'media_path_value': "'test_path_dfhvndshfgsef/openslides/media/'",
|
||||||
|
'whoosh_index_path_value': "'test_path_dfhvndshfgsef/openslides/whoosh_index/'"})
|
||||||
|
|
||||||
|
def test_get_user_data_path_values_case_two(self):
|
||||||
|
self.assertEqual(
|
||||||
|
get_user_data_path_values('test_path_dfhvndshfgsef', default=True, openslides_type=WINDOWS_PORTABLE_VERSION),
|
||||||
|
{'import_function': 'from openslides.utils.main import get_portable_paths',
|
||||||
|
'database_path_value': "get_portable_paths('database')",
|
||||||
|
'media_path_value': "get_portable_paths('media')",
|
||||||
|
'whoosh_index_path_value': "get_portable_paths('whoosh_index')"})
|
||||||
|
|
||||||
|
def test_setup_django_settings_module(self):
|
||||||
|
setup_django_settings_module('test_dir_dhvnghfjdh456fzheg2f/test_path_bngjdhc756dzwncshdfnx.py')
|
||||||
|
self.assertEqual(os.environ['DJANGO_SETTINGS_MODULE'], 'test_path_bngjdhc756dzwncshdfnx')
|
||||||
|
self.assertEqual(sys.path[0], 'test_dir_dhvnghfjdh456fzheg2f')
|
||||||
|
|
||||||
|
def test_setup_django_settings_module_error(self):
|
||||||
|
self.assertRaisesMessage(
|
||||||
|
ImproperlyConfigured,
|
||||||
|
"'.' is not an allowed character in the settings-file",
|
||||||
|
setup_django_settings_module,
|
||||||
|
'wrong.file.py')
|
||||||
|
|
||||||
|
def test_get_browser_url(self):
|
||||||
|
self.assertEqual(get_browser_url('123.456.789.365', 6789), 'http://123.456.789.365:6789')
|
||||||
|
self.assertEqual(get_browser_url('123.456.789.365', 80), 'http://123.456.789.365')
|
||||||
|
self.assertEqual(get_browser_url('0.0.0.0', 6789), 'http://localhost:6789')
|
||||||
|
self.assertEqual(get_browser_url('0.0.0.0', 80), 'http://localhost')
|
Loading…
Reference in New Issue
Block a user