Merge pull request #800 from andkit/portable-improvements
Portable improvements
This commit is contained in:
commit
aca2570cb7
@ -6,11 +6,18 @@ How to create a new portable Windows distribution of OpenSlides:
|
|||||||
|
|
||||||
easy_install -Z django django-mptt beautifulsoup4 bleach pillow qrcode reportlab tornado
|
easy_install -Z django django-mptt beautifulsoup4 bleach pillow qrcode reportlab tornado
|
||||||
|
|
||||||
2.) Run in the main directory of the OpenSlides checkout:
|
2.) To update the version resource of the prebuild openslides.exe
|
||||||
|
pywin32 should be installed (it is not strictly required but at
|
||||||
|
least for releases that are to be published it is highly advisable)
|
||||||
|
|
||||||
|
To install it just grab the binary installer from:
|
||||||
|
http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win32-py2.7.exe/download
|
||||||
|
|
||||||
|
3.) Run in the main directory of the OpenSlides checkout:
|
||||||
|
|
||||||
python extras\win32-portable\prepare_portable.py
|
python extras\win32-portable\prepare_portable.py
|
||||||
|
|
||||||
3.) The portable OpenSlides distribution is now ready as a zip archive
|
4.) The portable OpenSlides distribution is now ready as a zip archive
|
||||||
in the 'dist' directory
|
in the 'dist' directory
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,6 +12,17 @@
|
|||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
|
||||||
|
#define PYTHON_DLL_PATH "\\Dlls\\python27.dll"
|
||||||
|
|
||||||
|
static void (*py_initialize)(void) = 0;
|
||||||
|
static void (*py_finalize)(void) = 0;
|
||||||
|
static void (*py_set_program_name)(char *) = 0;
|
||||||
|
static void (*py_set_python_home)(char *) = 0;
|
||||||
|
static int (*py_run_simple_string_flags)(const char *, PyCompilerFlags *) = 0;
|
||||||
|
static void (*py_sys_set_argv_ex)(int, char **, int) = 0;
|
||||||
|
static int (*py_main)(int, char **) = 0;
|
||||||
|
static int *py_ignore_environment_flag = 0;
|
||||||
|
|
||||||
static const char *run_openslides_code =
|
static const char *run_openslides_code =
|
||||||
"import openslides_gui.gui;"
|
"import openslides_gui.gui;"
|
||||||
"openslides_gui.gui.main()";
|
"openslides_gui.gui.main()";
|
||||||
@ -71,14 +82,94 @@ _get_module_name()
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_fatal_error(const char *text)
|
||||||
|
{
|
||||||
|
MessageBoxA(NULL, text, "Fatal error", MB_OK | MB_ICONERROR);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_fatal_error_fmt(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int size = 512;
|
||||||
|
char *buf = malloc(size);
|
||||||
|
va_list args;
|
||||||
|
int bytes_written;
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
bytes_written = vsnprintf(buf, size, fmt, args);
|
||||||
|
if (bytes_written > -1 && bytes_written < size)
|
||||||
|
break;
|
||||||
|
else if (bytes_written > size)
|
||||||
|
size = bytes_written + 1;
|
||||||
|
else
|
||||||
|
size *= 2;
|
||||||
|
|
||||||
|
buf = realloc(buf, size);
|
||||||
|
if (!buf)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
_fatal_error(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
_load_func(HMODULE module, const char *name)
|
||||||
|
{
|
||||||
|
void *address = GetProcAddress(module, name);
|
||||||
|
if (!address)
|
||||||
|
_fatal_error_fmt("Failed to look up symbol %s", name);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_load_python(const char *pyhome)
|
||||||
|
{
|
||||||
|
size_t pyhome_len = strlen(pyhome);
|
||||||
|
size_t size = pyhome_len + strlen(PYTHON_DLL_PATH) + 1;
|
||||||
|
char *buf = malloc(size);
|
||||||
|
HMODULE py_dll;
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
abort();
|
||||||
|
memcpy(buf, pyhome, pyhome_len);
|
||||||
|
memcpy(buf + pyhome_len, PYTHON_DLL_PATH, sizeof(PYTHON_DLL_PATH));
|
||||||
|
buf[size - 1] = '\0';
|
||||||
|
|
||||||
|
py_dll = LoadLibrary(buf);
|
||||||
|
if (!py_dll)
|
||||||
|
{
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
_fatal_error_fmt("Failed to load %s (error %d)", buf, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
py_initialize = (void (*)(void))_load_func(py_dll, "Py_Initialize");
|
||||||
|
py_finalize = (void (*)(void))_load_func(py_dll, "Py_Finalize");
|
||||||
|
py_set_program_name = (void (*)(char *))
|
||||||
|
_load_func(py_dll, "Py_SetProgramName");
|
||||||
|
py_set_python_home = (void (*)(char *))
|
||||||
|
_load_func(py_dll, "Py_SetPythonHome");
|
||||||
|
py_run_simple_string_flags = (int (*)(const char *, PyCompilerFlags *))
|
||||||
|
_load_func(py_dll, "PyRun_SimpleStringFlags");
|
||||||
|
py_sys_set_argv_ex = (void (*)(int, char **, int))
|
||||||
|
_load_func(py_dll, "PySys_SetArgvEx");
|
||||||
|
py_main = (int (*)(int, char **))_load_func(py_dll, "Py_Main");
|
||||||
|
py_ignore_environment_flag = (int *)
|
||||||
|
_load_func(py_dll, "Py_IgnoreEnvironmentFlag");
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_run()
|
_run()
|
||||||
{
|
{
|
||||||
if (PyRun_SimpleString(run_openslides_code) != 0)
|
if (py_run_simple_string_flags(run_openslides_code, NULL) != 0)
|
||||||
{
|
_fatal_error("Failed to execute openslides");
|
||||||
fprintf(stderr, "ERROR: failed to execute openslides\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -91,33 +182,33 @@ WinMain(HINSTANCE inst, HINSTANCE prev_inst, LPSTR cmdline, int show)
|
|||||||
int run_py_main = __argc > 1;
|
int run_py_main = __argc > 1;
|
||||||
char *py_home, *sep = NULL;
|
char *py_home, *sep = NULL;
|
||||||
|
|
||||||
Py_SetProgramName(__argv[0]);
|
|
||||||
|
|
||||||
py_home = _get_module_name();
|
py_home = _get_module_name();
|
||||||
|
if (!py_home)
|
||||||
|
_fatal_error("Could not determine portable root directory");
|
||||||
|
|
||||||
if (py_home)
|
sep = strrchr(py_home, '\\');
|
||||||
sep = strrchr(py_home, '\\');
|
|
||||||
/* should always be the true */
|
/* should always be the true */
|
||||||
if (sep)
|
if (sep)
|
||||||
{
|
|
||||||
*sep = '\0';
|
*sep = '\0';
|
||||||
Py_SetPythonHome(py_home);
|
|
||||||
Py_IgnoreEnvironmentFlag = 1;
|
_load_python(py_home);
|
||||||
}
|
py_set_program_name(__argv[0]);
|
||||||
|
py_set_python_home(py_home);
|
||||||
|
*py_ignore_environment_flag = 1;
|
||||||
|
|
||||||
if (run_py_main)
|
if (run_py_main)
|
||||||
{
|
{
|
||||||
/* we where given extra arguments, behave like python.exe */
|
/* we where given extra arguments, behave like python.exe */
|
||||||
returncode = Py_Main(__argc, __argv);
|
returncode = py_main(__argc, __argv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* no arguments given => start openslides gui */
|
/* no arguments given => start openslides gui */
|
||||||
Py_Initialize();
|
py_initialize();
|
||||||
PySys_SetArgvEx(__argc, __argv, 0);
|
py_sys_set_argv_ex(__argc, __argv, 0);
|
||||||
|
|
||||||
returncode = _run();
|
returncode = _run();
|
||||||
Py_Finalize();
|
py_finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
free(py_home);
|
free(py_home);
|
||||||
|
Binary file not shown.
48
extras/win32-portable/prepare_portable.py
Normal file → Executable file
48
extras/win32-portable/prepare_portable.py
Normal file → Executable file
@ -318,7 +318,7 @@ def compile_openslides_launcher():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
cc.add_include_dir(distutils.sysconfig.get_python_inc())
|
cc.add_include_dir(distutils.sysconfig.get_python_inc())
|
||||||
cc.add_library_dir(os.path.join(sys.exec_prefix, "Libs"))
|
cc.define_macro("_CRT_SECURE_NO_WARNINGS")
|
||||||
|
|
||||||
gui_data_dir = os.path.dirname(openslides_gui.__file__)
|
gui_data_dir = os.path.dirname(openslides_gui.__file__)
|
||||||
gui_data_dir = os.path.join(gui_data_dir, "data")
|
gui_data_dir = os.path.join(gui_data_dir, "data")
|
||||||
@ -343,11 +343,52 @@ def compile_openslides_launcher():
|
|||||||
])
|
])
|
||||||
cc.link_executable(
|
cc.link_executable(
|
||||||
objs, "extras/win32-portable/openslides",
|
objs, "extras/win32-portable/openslides",
|
||||||
extra_preargs=["/subsystem:windows"],
|
extra_preargs=["/subsystem:windows", "/nodefaultlib:python27.lib"],
|
||||||
|
libraries=["user32"]
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def openslides_launcher_update_version_resource():
|
||||||
|
try:
|
||||||
|
import win32api
|
||||||
|
import win32verstamp
|
||||||
|
except ImportError:
|
||||||
|
sys.stderr.write(
|
||||||
|
"Using precompiled executable and pywin32 is not available - "
|
||||||
|
"version resource may be out of date!\n")
|
||||||
|
return False
|
||||||
|
import struct
|
||||||
|
|
||||||
|
sys.stdout.write("Updating version resource")
|
||||||
|
# code based on win32verstamp.stamp() with some minor differences in
|
||||||
|
# version handling
|
||||||
|
major, minor, sub = openslides.VERSION[:3]
|
||||||
|
build = openslides.VERSION[4]
|
||||||
|
pre_release = openslides.VERSION[3] != "final"
|
||||||
|
version_str = openslides.get_version()
|
||||||
|
|
||||||
|
sdata = {
|
||||||
|
"CompanyName": "OpenSlides team",
|
||||||
|
"FileDescription": "OpenSlides",
|
||||||
|
"FileVersion": version_str,
|
||||||
|
"InternalName": "OpenSlides",
|
||||||
|
"LegalCopyright": u"Copyright \xa9 2011-2013",
|
||||||
|
"OriginalFilename": "openslides.exe",
|
||||||
|
"ProductName": "OpenSlides",
|
||||||
|
"ProductVersion": version_str,
|
||||||
|
}
|
||||||
|
vdata = {
|
||||||
|
"Translation": struct.pack("hh", 0x409, 0x4e4),
|
||||||
|
}
|
||||||
|
|
||||||
|
vs = win32verstamp.VS_VERSION_INFO(
|
||||||
|
major, minor, sub, build, sdata, vdata, pre_release, False)
|
||||||
|
h = win32api.BeginUpdateResource("extras/win32-portable/openslides.exe", 0)
|
||||||
|
win32api.UpdateResource(h, 16, 1, vs)
|
||||||
|
win32api.EndUpdateResource(h, 0)
|
||||||
|
|
||||||
|
|
||||||
def copy_dlls(odir):
|
def copy_dlls(odir):
|
||||||
dll_src = os.path.join(sys.exec_prefix, "DLLs")
|
dll_src = os.path.join(sys.exec_prefix, "DLLs")
|
||||||
dll_dest = os.path.join(odir, "DLLs")
|
dll_dest = os.path.join(odir, "DLLs")
|
||||||
@ -361,7 +402,7 @@ def copy_dlls(odir):
|
|||||||
|
|
||||||
pydllname = "python{0}{1}.dll".format(*sys.version_info[:2])
|
pydllname = "python{0}{1}.dll".format(*sys.version_info[:2])
|
||||||
src = os.path.join(os.environ["WINDIR"], "System32", pydllname)
|
src = os.path.join(os.environ["WINDIR"], "System32", pydllname)
|
||||||
dest = os.path.join(odir, pydllname)
|
dest = os.path.join(dll_dest, pydllname)
|
||||||
shutil.copyfile(src, dest)
|
shutil.copyfile(src, dest)
|
||||||
|
|
||||||
|
|
||||||
@ -442,6 +483,7 @@ def main():
|
|||||||
|
|
||||||
if not compile_openslides_launcher():
|
if not compile_openslides_launcher():
|
||||||
sys.stdout.write("Using prebuild openslides.exe\n")
|
sys.stdout.write("Using prebuild openslides.exe\n")
|
||||||
|
openslides_launcher_update_version_resource()
|
||||||
|
|
||||||
shutil.copyfile(
|
shutil.copyfile(
|
||||||
"extras/win32-portable/openslides.exe",
|
"extras/win32-portable/openslides.exe",
|
||||||
|
@ -349,6 +349,14 @@ def get_user_data_path(*args):
|
|||||||
|
|
||||||
|
|
||||||
def is_portable():
|
def is_portable():
|
||||||
|
"""Return True if openslides is run as portable version"""
|
||||||
|
|
||||||
|
# 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
|
||||||
exename = os.path.basename(sys.executable).lower()
|
exename = os.path.basename(sys.executable).lower()
|
||||||
return exename == "openslides.exe"
|
return exename == "openslides.exe"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user