2012-04-25 22:29:19 +02:00
|
|
|
|
#!/usr/bin/env python
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
"""
|
|
|
|
|
openslides.main
|
|
|
|
|
~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
Main script to start and set up OpenSlides.
|
|
|
|
|
|
2013-02-16 16:19:20 +01:00
|
|
|
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
2012-04-25 22:29:19 +02:00
|
|
|
|
:license: GNU GPL, see LICENSE for more details.
|
|
|
|
|
"""
|
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
import base64
|
|
|
|
|
import ctypes
|
2012-04-15 16:04:08 +02:00
|
|
|
|
import optparse
|
2012-11-24 14:22:02 +01:00
|
|
|
|
import os
|
2012-04-15 16:04:08 +02:00
|
|
|
|
import socket
|
2012-11-24 14:22:02 +01:00
|
|
|
|
import sys
|
|
|
|
|
import tempfile
|
2012-04-15 16:04:08 +02:00
|
|
|
|
import threading
|
2012-11-24 14:22:02 +01:00
|
|
|
|
import time
|
2012-04-15 16:04:08 +02:00
|
|
|
|
import webbrowser
|
|
|
|
|
|
2013-02-27 18:22:24 +01:00
|
|
|
|
from django.conf import ENVIRONMENT_VARIABLE
|
2012-04-15 16:04:08 +02:00
|
|
|
|
from django.core.management import execute_from_command_line
|
|
|
|
|
|
2012-11-29 15:01:49 +01:00
|
|
|
|
from openslides import get_version
|
2013-02-27 18:22:24 +01:00
|
|
|
|
from openslides.utils.tornado_webserver import run_tornado
|
2012-11-29 15:01:49 +01:00
|
|
|
|
|
2013-03-11 21:32:09 +01:00
|
|
|
|
|
2012-08-23 23:34:30 +02:00
|
|
|
|
CONFIG_TEMPLATE = """#!/usr/bin/env python
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
import openslides.main
|
2012-11-01 10:56:38 +01:00
|
|
|
|
from openslides.global_settings import *
|
2012-04-15 16:04:08 +02:00
|
|
|
|
|
2012-08-05 09:52:00 +02:00
|
|
|
|
# Use 'DEBUG = True' to get more details for server errors
|
2012-11-24 14:22:02 +01:00
|
|
|
|
# (Default for releases: 'False')
|
2012-08-04 20:59:27 +02:00
|
|
|
|
DEBUG = False
|
|
|
|
|
TEMPLATE_DEBUG = DEBUG
|
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
DBPATH = %(dbpath)s
|
2012-08-04 20:59:27 +02:00
|
|
|
|
|
|
|
|
|
DATABASES = {
|
|
|
|
|
'default': {
|
|
|
|
|
'ENGINE': 'django.db.backends.sqlite3',
|
|
|
|
|
'NAME': DBPATH,
|
|
|
|
|
'USER': '',
|
|
|
|
|
'PASSWORD': '',
|
|
|
|
|
'HOST': '',
|
|
|
|
|
'PORT': '',
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Set timezone
|
|
|
|
|
TIME_ZONE = 'Europe/Berlin'
|
|
|
|
|
|
|
|
|
|
# Make this unique, and don't share it with anybody.
|
|
|
|
|
SECRET_KEY = %(default_key)r
|
|
|
|
|
|
|
|
|
|
# Add OpenSlides plugins to this list (see example entry in comment)
|
|
|
|
|
INSTALLED_PLUGINS = (
|
|
|
|
|
# 'pluginname',
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
INSTALLED_APPS += INSTALLED_PLUGINS
|
2013-02-16 16:19:20 +01:00
|
|
|
|
|
|
|
|
|
# Absolute path to the directory that holds media.
|
|
|
|
|
# Example: "/home/media/media.lawrence.com/"
|
|
|
|
|
MEDIA_ROOT = %(media_root_path)s
|
|
|
|
|
|
2012-08-04 20:59:27 +02:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
KEY_LENGTH = 30
|
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
# sentinel used to signal that the database ought to be stored
|
|
|
|
|
# relative to the portable's directory
|
|
|
|
|
_portable_db_path = object()
|
|
|
|
|
|
2012-08-14 14:19:59 +02:00
|
|
|
|
|
2013-04-21 18:42:58 +02:00
|
|
|
|
def process_options(argv=None, manage_runserver=False):
|
2012-04-15 16:04:08 +02:00
|
|
|
|
if argv is None:
|
|
|
|
|
argv = sys.argv[1:]
|
|
|
|
|
|
2012-08-04 20:59:27 +02:00
|
|
|
|
parser = optparse.OptionParser(
|
2013-01-23 19:37:12 +01:00
|
|
|
|
description="Run openslides using the tornado webserver")
|
2013-06-17 17:41:59 +02:00
|
|
|
|
parser.add_option(
|
|
|
|
|
"-a", "--address",
|
|
|
|
|
help="IP Address to listen on. Default: 0.0.0.0")
|
|
|
|
|
parser.add_option(
|
|
|
|
|
"-p", "--port", type="int",
|
|
|
|
|
help="Port to listen on. Default: 8000 (start as admin/root: 80)")
|
2012-08-14 14:19:59 +02:00
|
|
|
|
parser.add_option(
|
|
|
|
|
"--syncdb", action="store_true",
|
2012-11-29 15:01:49 +01:00
|
|
|
|
help="Update/create database before starting the server.")
|
2013-06-02 18:00:11 +02:00
|
|
|
|
parser.add_option(
|
|
|
|
|
"--backupdb", action="store", metavar="BACKUP_PATH",
|
2013-06-17 17:41:59 +02:00
|
|
|
|
help="Make a backup copy of the database to BACKUP_PATH.")
|
2012-08-14 14:19:59 +02:00
|
|
|
|
parser.add_option(
|
|
|
|
|
"--reset-admin", action="store_true",
|
2012-11-29 15:01:49 +01:00
|
|
|
|
help="Make sure the user 'admin' exists and uses 'admin' as password.")
|
2012-08-14 14:19:59 +02:00
|
|
|
|
parser.add_option(
|
2013-06-17 17:41:59 +02:00
|
|
|
|
"-s", "--settings", help="Set the path to the settings file.")
|
2013-01-22 20:36:04 +01:00
|
|
|
|
parser.add_option(
|
|
|
|
|
"--no-browser",
|
|
|
|
|
action="store_false", dest="start_browser", default=True,
|
2013-06-17 17:41:59 +02:00
|
|
|
|
help="Do not automatically start the web browser.")
|
|
|
|
|
parser.add_option(
|
|
|
|
|
"--no-reload", action="store_true",
|
|
|
|
|
help="Do not reload the web server.")
|
2013-02-09 20:42:43 +01:00
|
|
|
|
parser.add_option(
|
|
|
|
|
"--no-run", action="store_true",
|
2013-06-17 17:41:59 +02:00
|
|
|
|
help="Do not start the web server.")
|
2012-11-29 15:01:49 +01:00
|
|
|
|
parser.add_option(
|
|
|
|
|
"--version", action="store_true",
|
|
|
|
|
help="Show version and exit.")
|
2012-04-15 16:04:08 +02:00
|
|
|
|
|
|
|
|
|
opts, args = parser.parse_args(argv)
|
2013-04-21 18:42:58 +02:00
|
|
|
|
|
|
|
|
|
# Do not parse any argv if the script is started via manage.py runserver.
|
|
|
|
|
# This simulates the django runserver command
|
|
|
|
|
if manage_runserver:
|
|
|
|
|
opts.start_browser = False
|
|
|
|
|
opts.no_reload = False
|
|
|
|
|
return opts
|
|
|
|
|
|
2012-11-29 15:01:49 +01:00
|
|
|
|
if opts.version:
|
|
|
|
|
print get_version()
|
|
|
|
|
exit(0)
|
2013-01-23 21:12:36 +01:00
|
|
|
|
|
2013-04-21 18:42:58 +02:00
|
|
|
|
if args:
|
2012-08-14 14:19:59 +02:00
|
|
|
|
sys.stderr.write("This command does not take arguments!\n\n")
|
|
|
|
|
parser.print_help()
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
return opts
|
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
|
2013-04-21 18:42:58 +02:00
|
|
|
|
def main(argv=None, manage_runserver=False):
|
|
|
|
|
opts = process_options(argv, manage_runserver)
|
2012-11-24 14:22:02 +01:00
|
|
|
|
_main(opts)
|
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
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:
|
2012-11-24 20:35:06 +01:00
|
|
|
|
opts.settings = os.path.join(
|
|
|
|
|
portable_dir, "openslides", "settings.py")
|
2012-11-24 14:22:02 +01:00
|
|
|
|
database_path = _portable_db_path
|
|
|
|
|
|
|
|
|
|
_main(opts, database_path=database_path)
|
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
def _main(opts, database_path=None):
|
2012-08-14 14:19:59 +02:00
|
|
|
|
# Find the path to the settings
|
2012-11-01 10:56:38 +01:00
|
|
|
|
settings_path = opts.settings
|
|
|
|
|
if settings_path is None:
|
2012-11-24 14:22:02 +01:00
|
|
|
|
settings_path = get_user_config_path('openslides', 'settings.py')
|
2012-08-14 14:19:59 +02:00
|
|
|
|
|
|
|
|
|
# Create settings if necessary
|
2012-11-01 10:56:38 +01:00
|
|
|
|
if not os.path.exists(settings_path):
|
2012-11-09 10:19:53 +01:00
|
|
|
|
create_settings(settings_path, database_path)
|
2012-04-15 16:04:08 +02:00
|
|
|
|
|
2012-08-14 14:19:59 +02:00
|
|
|
|
# Set the django environment to the settings
|
2012-11-01 10:56:38 +01:00
|
|
|
|
setup_django_environment(settings_path)
|
2012-08-04 20:59:27 +02:00
|
|
|
|
|
2012-08-14 14:19:59 +02:00
|
|
|
|
# Find url to openslides
|
2012-05-31 00:27:47 +02:00
|
|
|
|
addr, port = detect_listen_opts(opts.address, opts.port)
|
|
|
|
|
|
2012-08-14 14:19:59 +02:00
|
|
|
|
# Create Database if necessary
|
|
|
|
|
if not database_exists() or opts.syncdb:
|
|
|
|
|
run_syncdb()
|
|
|
|
|
|
|
|
|
|
# Reset Admin
|
|
|
|
|
elif opts.reset_admin:
|
2013-06-16 12:00:57 +02:00
|
|
|
|
reset_admin_user()
|
2012-08-14 14:19:59 +02:00
|
|
|
|
|
2013-06-02 18:00:11 +02:00
|
|
|
|
if opts.backupdb:
|
|
|
|
|
backup_database(opts.backupdb)
|
|
|
|
|
|
2013-02-09 20:42:43 +01:00
|
|
|
|
if opts.no_run:
|
|
|
|
|
return
|
|
|
|
|
|
2012-08-14 14:19:59 +02:00
|
|
|
|
# Start OpenSlides
|
2013-03-27 15:53:31 +01:00
|
|
|
|
reload = True
|
2012-08-14 14:19:59 +02:00
|
|
|
|
if opts.no_reload:
|
2013-03-27 15:53:31 +01:00
|
|
|
|
reload = False
|
2013-01-22 20:36:04 +01:00
|
|
|
|
|
|
|
|
|
if opts.start_browser:
|
2013-06-13 14:36:38 +02:00
|
|
|
|
if port == 80:
|
|
|
|
|
suffix = ""
|
|
|
|
|
else:
|
|
|
|
|
suffix = ":%d" % port
|
|
|
|
|
start_browser("http://localhost%s" % suffix)
|
2013-01-22 20:36:04 +01:00
|
|
|
|
|
2013-03-27 15:53:31 +01:00
|
|
|
|
# Start the server
|
|
|
|
|
run_tornado(addr, port, reload)
|
2012-04-15 16:04:08 +02:00
|
|
|
|
|
|
|
|
|
|
2012-11-01 10:56:38 +01:00
|
|
|
|
def create_settings(settings_path, database_path=None):
|
|
|
|
|
settings_module = os.path.dirname(settings_path)
|
2012-04-15 16:04:08 +02:00
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
if database_path is _portable_db_path:
|
|
|
|
|
database_path = get_portable_db_path()
|
|
|
|
|
dbpath_value = 'openslides.main.get_portable_db_path()'
|
2013-02-16 16:19:20 +01:00
|
|
|
|
media_root_path_value = 'openslides.main.get_portable_media_root_path()'
|
2012-11-24 14:22:02 +01:00
|
|
|
|
else:
|
|
|
|
|
if database_path is None:
|
|
|
|
|
database_path = get_user_data_path('openslides', 'database.sqlite')
|
2012-11-24 20:49:04 +01:00
|
|
|
|
dbpath_value = repr(fs2unicode(database_path))
|
2013-02-16 16:19:20 +01:00
|
|
|
|
media_root_path_value = repr(fs2unicode(get_user_data_path('openslides', 'media', '')))
|
2012-11-01 10:56:38 +01:00
|
|
|
|
|
|
|
|
|
settings_content = CONFIG_TEMPLATE % dict(
|
2012-08-14 14:19:59 +02:00
|
|
|
|
default_key=base64.b64encode(os.urandom(KEY_LENGTH)),
|
2013-02-16 16:19:20 +01:00
|
|
|
|
dbpath=dbpath_value,
|
|
|
|
|
media_root_path=media_root_path_value)
|
2012-11-01 10:56:38 +01:00
|
|
|
|
|
|
|
|
|
if not os.path.exists(settings_module):
|
|
|
|
|
os.makedirs(settings_module)
|
2012-08-14 14:19:59 +02:00
|
|
|
|
|
2012-11-01 10:56:38 +01:00
|
|
|
|
if not os.path.exists(os.path.dirname(database_path)):
|
|
|
|
|
os.makedirs(os.path.dirname(database_path))
|
2012-04-15 16:04:08 +02:00
|
|
|
|
|
2012-11-01 10:56:38 +01:00
|
|
|
|
with open(settings_path, 'w') as file:
|
|
|
|
|
file.write(settings_content)
|
2012-08-04 20:59:27 +02:00
|
|
|
|
|
2012-11-01 10:56:38 +01:00
|
|
|
|
|
|
|
|
|
def setup_django_environment(settings_path):
|
|
|
|
|
settings_file = os.path.basename(settings_path)
|
|
|
|
|
settings_module_name = "".join(settings_file.split('.')[:-1])
|
|
|
|
|
if '.' in settings_module_name:
|
|
|
|
|
print "'.' is not an allowed character in the settings-file"
|
|
|
|
|
sys.exit(1)
|
2012-11-09 09:51:10 +01:00
|
|
|
|
settings_module_dir = os.path.dirname(settings_path)
|
2012-11-01 10:56:38 +01:00
|
|
|
|
sys.path.append(settings_module_dir)
|
2013-02-27 18:22:24 +01:00
|
|
|
|
os.environ[ENVIRONMENT_VARIABLE] = '%s' % settings_module_name
|
2012-04-15 16:04:08 +02:00
|
|
|
|
|
2012-07-10 14:00:51 +02:00
|
|
|
|
|
2013-02-09 20:45:58 +01:00
|
|
|
|
def detect_listen_opts(address=None, port=None):
|
2012-04-15 16:04:08 +02:00
|
|
|
|
if address is None:
|
2013-06-13 14:36:38 +02:00
|
|
|
|
address = "0.0.0.0"
|
2012-04-15 16:04:08 +02:00
|
|
|
|
|
|
|
|
|
if port is None:
|
|
|
|
|
# test if we can use port 80
|
|
|
|
|
s = socket.socket()
|
|
|
|
|
port = 80
|
|
|
|
|
try:
|
|
|
|
|
s.bind((address, port))
|
|
|
|
|
s.listen(-1)
|
|
|
|
|
except socket.error:
|
|
|
|
|
port = 8000
|
|
|
|
|
finally:
|
|
|
|
|
s.close()
|
|
|
|
|
|
|
|
|
|
return address, port
|
|
|
|
|
|
2012-07-10 14:00:51 +02:00
|
|
|
|
|
2012-08-14 14:19:59 +02:00
|
|
|
|
def database_exists():
|
|
|
|
|
"""Detect if database exists"""
|
2012-04-27 01:09:12 +02:00
|
|
|
|
# can't be imported in global scope as they already require
|
|
|
|
|
# the settings module during import
|
|
|
|
|
from django.db import DatabaseError
|
2012-08-14 14:19:59 +02:00
|
|
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
|
|
|
from openslides.participant.models import User
|
2012-04-25 19:37:51 +02:00
|
|
|
|
|
|
|
|
|
try:
|
2012-11-01 10:56:38 +01:00
|
|
|
|
# TODO: Use another model, the User could be deactivated
|
2012-04-25 19:37:51 +02:00
|
|
|
|
User.objects.count()
|
|
|
|
|
except DatabaseError:
|
2012-08-05 09:52:00 +02:00
|
|
|
|
return False
|
2012-08-14 14:19:59 +02:00
|
|
|
|
except ImproperlyConfigured:
|
|
|
|
|
print "Your settings file seems broken"
|
|
|
|
|
sys.exit(0)
|
2012-08-05 09:52:00 +02:00
|
|
|
|
else:
|
2012-04-25 19:37:51 +02:00
|
|
|
|
return True
|
|
|
|
|
|
2012-07-10 14:00:51 +02:00
|
|
|
|
|
2012-08-14 14:19:59 +02:00
|
|
|
|
def run_syncdb():
|
|
|
|
|
# now initialize the database
|
|
|
|
|
argv = ["", "syncdb", "--noinput"]
|
|
|
|
|
execute_from_command_line(argv)
|
2012-04-15 16:04:08 +02:00
|
|
|
|
|
2012-07-10 14:00:51 +02:00
|
|
|
|
|
2013-06-16 12:00:57 +02:00
|
|
|
|
def reset_admin_user():
|
2012-08-14 14:19:59 +02:00
|
|
|
|
# can't be imported in global scope as it already requires
|
|
|
|
|
# the settings module during import
|
2013-06-16 12:00:57 +02:00
|
|
|
|
from openslides.participant.api import create_or_reset_admin_user
|
|
|
|
|
create_or_reset_admin_user()
|
2012-08-14 14:19:59 +02:00
|
|
|
|
|
|
|
|
|
|
2013-06-02 18:00:11 +02:00
|
|
|
|
def backup_database(dest_path):
|
|
|
|
|
argv = ["", "backupdb", "--destination={0}".format(dest_path)]
|
|
|
|
|
execute_from_command_line(argv)
|
|
|
|
|
|
|
|
|
|
|
2012-08-14 14:19:59 +02:00
|
|
|
|
def start_browser(url):
|
|
|
|
|
browser = webbrowser.get()
|
|
|
|
|
|
|
|
|
|
def f():
|
|
|
|
|
time.sleep(1)
|
|
|
|
|
browser.open(url)
|
|
|
|
|
|
|
|
|
|
t = threading.Thread(target=f)
|
|
|
|
|
t.start()
|
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
|
2012-11-24 14:01:21 +01:00
|
|
|
|
def fs2unicode(s):
|
|
|
|
|
if isinstance(s, unicode):
|
|
|
|
|
return s
|
|
|
|
|
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
|
|
|
|
return s.decode(fs_encoding)
|
|
|
|
|
|
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
def get_user_config_path(*args):
|
|
|
|
|
if sys.platform == "win32":
|
|
|
|
|
return win32_get_app_data_path(*args)
|
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
config_home = os.environ.get(
|
|
|
|
|
'XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config'))
|
2012-11-24 14:22:02 +01:00
|
|
|
|
|
2012-11-24 20:49:04 +01:00
|
|
|
|
return os.path.join(fs2unicode(config_home), *args)
|
2012-08-27 21:48:46 +02:00
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
def get_user_data_path(*args):
|
|
|
|
|
if sys.platform == "win32":
|
|
|
|
|
return win32_get_app_data_path(*args)
|
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
data_home = os.environ.get(
|
|
|
|
|
'XDG_DATA_HOME', os.path.join(
|
|
|
|
|
os.path.expanduser('~'), '.local', 'share'))
|
2012-11-24 14:22:02 +01:00
|
|
|
|
|
2012-11-24 20:49:04 +01:00
|
|
|
|
return os.path.join(fs2unicode(data_home), *args)
|
2012-11-24 14:22:02 +01:00
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
|
2013-02-09 20:45:58 +01:00
|
|
|
|
def is_portable():
|
|
|
|
|
exename = os.path.basename(sys.executable).lower()
|
|
|
|
|
return exename == "openslides.exe"
|
|
|
|
|
|
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
def get_portable_path(*args):
|
2012-08-27 21:48:46 +02:00
|
|
|
|
# NOTE: sys.executable will be the path to openslides.exe
|
|
|
|
|
# since it is essentially a small wrapper that embeds the
|
|
|
|
|
# python interpreter
|
2012-11-24 14:22:02 +01:00
|
|
|
|
|
2013-02-09 20:45:58 +01:00
|
|
|
|
if not is_portable():
|
2012-11-24 20:35:06 +01:00
|
|
|
|
raise Exception(
|
|
|
|
|
"Cannot determine portable path when "
|
2012-11-24 14:22:02 +01:00
|
|
|
|
"not running as portable")
|
|
|
|
|
|
2012-11-24 20:49:04 +01:00
|
|
|
|
portable_dir = fs2unicode(os.path.dirname(os.path.abspath(sys.executable)))
|
2012-11-24 14:22:02 +01:00
|
|
|
|
return os.path.join(portable_dir, *args)
|
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
def get_portable_db_path():
|
|
|
|
|
return get_portable_path('openslides', 'database.sqlite')
|
|
|
|
|
|
2012-11-24 20:35:06 +01:00
|
|
|
|
|
2013-02-16 16:19:20 +01:00
|
|
|
|
def get_portable_media_root_path():
|
|
|
|
|
return get_portable_path('openslides', 'media', '')
|
|
|
|
|
|
|
|
|
|
|
2012-11-24 14:22:02 +01:00
|
|
|
|
def win32_get_app_data_path(*args):
|
|
|
|
|
shell32 = ctypes.WinDLL("shell32.dll")
|
|
|
|
|
SHGetFolderPath = shell32.SHGetFolderPathW
|
2012-11-24 20:35:06 +01:00
|
|
|
|
SHGetFolderPath.argtypes = (
|
|
|
|
|
ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_uint32,
|
|
|
|
|
ctypes.c_wchar_p)
|
2012-11-24 14:22:02 +01:00
|
|
|
|
SHGetFolderPath.restype = ctypes.c_uint32
|
|
|
|
|
|
|
|
|
|
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)
|
2012-08-27 21:48:46 +02:00
|
|
|
|
|
2012-08-14 14:19:59 +02:00
|
|
|
|
|
2012-04-15 16:04:08 +02:00
|
|
|
|
if __name__ == "__main__":
|
2013-02-09 20:45:58 +01:00
|
|
|
|
if is_portable():
|
|
|
|
|
win32_portable_main()
|
|
|
|
|
else:
|
|
|
|
|
main()
|