OpenSlides/openslides/utils/main.py

158 lines
4.9 KiB
Python
Raw Normal View History

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
openslides.utils.main
~~~~~~~~~~~~~~~~~~~~~
Some functions for OpenSlides.
:copyright: 20112013 by OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details.
"""
import ctypes
import os
import socket
import sys
2013-10-12 21:30:34 +02:00
import tempfile
UNIX_VERSION = 'Unix Version'
WINDOWS_VERSION = 'Windows Version'
WINDOWS_PORTABLE_VERSION = 'Windows Portable Version'
2013-10-12 21:30:34 +02:00
class PortableDirNotWritable(Exception):
pass
def filesystem2unicode(path):
"""
Transforms a path string to unicode according to the filesystem's encoding.
"""
# TODO: Delete this function after switch to Python 3.
if not isinstance(path, unicode):
filesystem_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
path = path.decode(filesystem_encoding)
return path
def detect_openslides_type():
"""
Returns the type of this OpenSlides version.
"""
if sys.platform == 'win32':
if os.path.basename(sys.executable).lower() == 'openslides.exe':
# Note: sys.executable is the path of the *interpreter*
# the portable version embeds python so it *is* the interpreter.
# The wrappers generated by pip and co. will spawn the usual
# python(w).exe, so there is no danger of mistaking them
# for the portable even though they may also be called
# openslides.exe
openslides_type = WINDOWS_PORTABLE_VERSION
else:
openslides_type = WINDOWS_VERSION
else:
openslides_type = UNIX_VERSION
return openslides_type
def get_default_user_data_path(openslides_type):
"""
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.
"""
if openslides_type == UNIX_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():
"""
Returns the path to Windows' AppData directory.
"""
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
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 determine Windows' APPDATA path")
return buf.value
def get_win32_portable_path():
"""
Returns the path to the Windows portable version.
"""
# NOTE: sys.executable will be the path to openslides.exe
# since it is essentially a small wrapper that embeds the
# python interpreter
portable_path = filesystem2unicode(os.path.dirname(os.path.abspath(sys.executable)))
try:
fd, test_file = tempfile.mkstemp(dir=portable_path)
except OSError:
2013-10-12 21:30:34 +02:00
raise PortableDirNotWritable(
'Portable directory is not writeable. '
'Please choose another directory for settings and data files.')
2013-10-12 21:30:34 +02:00
else:
os.close(fd)
os.unlink(test_file)
return portable_path
def get_portable_paths(name):
"""
Returns the paths for the Windows portable version on runtime for the
SQLite3 database, the media directory and the search index. The argument
'name' can be 'database', 'media' or 'whoosh_index'.
"""
if name == 'database':
path = os.path.join(get_win32_portable_path(), 'openslides', 'database.sqlite')
elif name == '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:
raise TypeError('Unknown type %s' % name)
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