Update portable to use new gui frontend

- switch portable to use gui frontend

 - add version resource and icon to portable

 - Regenerate openslides.exe
This commit is contained in:
Andy Kittner 2013-02-09 21:03:00 +01:00
parent 9826e3ec06
commit 56b02f8598
3 changed files with 178 additions and 44 deletions

View File

@ -12,18 +12,9 @@
#include <Python.h> #include <Python.h>
static const char *site_code =
"import sys;"
"import os;"
"import site;"
"path = os.path.dirname(sys.executable);"
"site_dir = os.path.join(path, \"site-packages\");"
"site.addsitedir(site_dir);"
"sys.path.append(path)";
static const char *run_openslides_code = static const char *run_openslides_code =
"import openslides.main;" "import openslides_gui.gui;"
"openslides.main.win32_portable_main()"; "openslides_gui.gui.main()";
/* determine the path to the executable /* determine the path to the executable
* NOTE: Py_GetFullProgramPath() can't be used because * NOTE: Py_GetFullProgramPath() can't be used because
@ -61,7 +52,7 @@ _get_module_name()
else if (res == size) else if (res == size)
{ {
/* NOTE: Don't check GetLastError() == ERROR_INSUFFICIENT_BUFFER /* NOTE: Don't check GetLastError() == ERROR_INSUFFICIENT_BUFFER
* here, it isn't set consisntently across all platforms * here, it isn't set consistently across all platforms
*/ */
size += 4096; size += 4096;
@ -83,12 +74,6 @@ _get_module_name()
static int static int
_run() _run()
{ {
if (PyRun_SimpleString(site_code) != 0)
{
fprintf(stderr, "ERROR: failed to initialize site path\n");
return 1;
}
if (PyRun_SimpleString(run_openslides_code) != 0) if (PyRun_SimpleString(run_openslides_code) != 0)
{ {
fprintf(stderr, "ERROR: failed to execute openslides\n"); fprintf(stderr, "ERROR: failed to execute openslides\n");
@ -99,13 +84,14 @@ _run()
} }
int int WINAPI
main(int argc, char *argv[]) WinMain(HINSTANCE inst, HINSTANCE prev_inst, LPSTR cmdline, int show)
{ {
int returncode; int returncode;
int run_py_main = __argc > 1;
char *py_home, *sep = NULL; char *py_home, *sep = NULL;
Py_SetProgramName(argv[0]); Py_SetProgramName(__argv[0]);
py_home = _get_module_name(); py_home = _get_module_name();
@ -116,14 +102,24 @@ main(int argc, char *argv[])
{ {
*sep = '\0'; *sep = '\0';
Py_SetPythonHome(py_home); Py_SetPythonHome(py_home);
Py_IgnoreEnvironmentFlag = 1;
} }
Py_Initialize(); if (run_py_main)
PySys_SetArgvEx(argc, argv, 0); {
/* we where given extra arguments, behave like python.exe */
returncode = Py_Main(__argc, __argv);
}
else
{
/* no arguments given => start openslides gui */
Py_Initialize();
PySys_SetArgvEx(__argc, __argv, 0);
returncode = _run(); returncode = _run();
Py_Finalize();
}
Py_Finalize();
free(py_home); free(py_home);
return returncode; return returncode;

BIN
extras/win32-portable/openslides.exe Normal file → Executable file

Binary file not shown.

View File

@ -20,8 +20,12 @@ import distutils.sysconfig
import pkg_resources import pkg_resources
import wx
sys.path.insert(0, os.getcwd()) sys.path.insert(0, os.getcwd())
sys.path.insert(1, os.path.join(os.getcwd(), "extras"))
import openslides import openslides
import openslides_gui
COMMON_EXCLUDE = [ COMMON_EXCLUDE = [
r".pyc$", r".pyc$",
@ -99,7 +103,43 @@ SITE_PACKAGES = {
}, },
"html5lib": { "html5lib": {
"copy": ["html5lib"], "copy": ["html5lib"],
} },
"wx": {
# NOTE: wxpython is a special case, see copy_wx
"copy": [],
"exclude": [
r"^wx/tools/",
r"^wx/py/",
r"^wx/build/",
r"^wx/lib/",
r"wx/_activex.pyd",
r"wx/_animate.pyd",
r"wx/_aui.pyd",
r"wx/_calendar.pyd",
r"wx/_combo.pyd",
r"wx/_gizmos.pyd",
r"wx/_glcanvas.pyd",
r"wx/_grid.pyd",
r"wx/_html.pyd",
r"wx/_media.pyd",
r"wx/_richtext.pyd",
r"wx/_stc.pyd",
r"wx/_webkit.pyd",
r"wx/_wizard.pyd",
r"wx/_xrc.pyd",
r"wx/gdiplus.dll",
r"wx/wxbase28uh_xml_vc.dll",
r"wx/wxmsw28uh_aui_vc.dll",
r"wx/wxmsw28uh_gizmos_vc.dll",
r"wx/wxmsw28uh_gizmos_xrc_vc.dll",
r"wx/wxmsw28uh_gl_vc.dll",
r"wx/wxmsw28uh_media_vc.dll",
r"wx/wxmsw28uh_qa_vc.dll",
r"wx/wxmsw28uh_richtext_vc.dll",
r"wx/wxmsw28uh_stc_vc.dll",
r"wx/wxmsw28uh_xrc_vc.dll",
],
},
} }
PY_DLLS = [ PY_DLLS = [
@ -128,11 +168,52 @@ bundled packages, please refer to the corresponding file in the
licenses/ directory. licenses/ directory.
""" """
OPENSLIDES_RC_TMPL = """
#include <winresrc.h>
#define ID_ICO_OPENSLIDES 1
ID_ICO_OPENSLIDES ICON "openslides.ico"
VS_VERSION_INFO VERSIONINFO
FILEVERSION {version[0]},{version[1]},{version[2]},{version[4]}
PRODUCTVERSION {version[0]},{version[1]},{version[2]},{version[4]}
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS {file_flags}
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "OpenSlides team\\0"
VALUE "FileDescription", "OpenSlides\\0"
VALUE "FileVersion", "{version_str}\\0"
VALUE "InternalName", "OpenSlides\\0"
VALUE "LegalCopyright", "Copyright \\251 2011-2013\\0"
VALUE "OriginalFilename", "openslides.exe\\0"
VALUE "ProductName", "OpenSlides\\0"
VALUE "ProductVersion", "{version_str}\\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4E4
END
END
"""
def compile_re_list(patterns): def compile_re_list(patterns):
expr = "|".join("(?:{0})".format(x) for x in patterns) expr = "|".join("(?:{0})".format(x) for x in patterns)
return re.compile(expr) return re.compile(expr)
def relpath(base, path, addslash = False):
def relpath(base, path, addslash=False):
b = os.path.normpath(os.path.abspath(base)) b = os.path.normpath(os.path.abspath(base))
p = os.path.normpath(os.path.abspath(path)) p = os.path.normpath(os.path.abspath(path))
if p == b: if p == b:
@ -150,6 +231,7 @@ def relpath(base, path, addslash = False):
return p return p
def filter_excluded_dirs(exclude_pattern, basedir, dirpath, dnames): def filter_excluded_dirs(exclude_pattern, basedir, dirpath, dnames):
i, l = 0, len(dnames) i, l = 0, len(dnames)
while i < l: while i < l:
@ -160,6 +242,7 @@ def filter_excluded_dirs(exclude_pattern, basedir, dirpath, dnames):
else: else:
i += 1 i += 1
def copy_dir_exclude(exclude, basedir, srcdir, destdir): def copy_dir_exclude(exclude, basedir, srcdir, destdir):
for dp, dnames, fnames in os.walk(srcdir): for dp, dnames, fnames in os.walk(srcdir):
filter_excluded_dirs(exclude, basedir, dp, dnames) filter_excluded_dirs(exclude, basedir, dp, dnames)
@ -177,22 +260,29 @@ def copy_dir_exclude(exclude, basedir, srcdir, destdir):
shutil.copyfile(fp, os.path.join(destdir, rp)) shutil.copyfile(fp, os.path.join(destdir, rp))
def collect_lib(libdir, odir): def collect_lib(libdir, odir):
exclude = compile_re_list(COMMON_EXCLUDE + LIBEXCLUDE) exclude = compile_re_list(COMMON_EXCLUDE + LIBEXCLUDE)
copy_dir_exclude(exclude, libdir, libdir, os.path.join(odir, "Lib")) copy_dir_exclude(exclude, libdir, libdir, os.path.join(odir, "Lib"))
def get_pkg_exclude(name, extra = ()):
def get_pkg_exclude(name, extra=()):
exclude = COMMON_EXCLUDE[:] exclude = COMMON_EXCLUDE[:]
exclude.extend(SITE_PACKAGES.get(name, {}).get("exclude", [])) exclude.extend(SITE_PACKAGES.get(name, {}).get("exclude", []))
exclude.extend(extra) exclude.extend(extra)
return compile_re_list(exclude) return compile_re_list(exclude)
def copy_package(name, info, odir): def copy_package(name, info, odir):
copy_things = info.get("copy", [])
if not copy_things:
return
dist = pkg_resources.get_distribution(name) dist = pkg_resources.get_distribution(name)
exclude = get_pkg_exclude(name) exclude = get_pkg_exclude(name)
site_dir = dist.location site_dir = dist.location
for thing in info.get("copy", []): for thing in copy_things:
fp = os.path.join(site_dir, thing) fp = os.path.join(site_dir, thing)
if not os.path.isdir(fp): if not os.path.isdir(fp):
rp = relpath(site_dir, fp) rp = relpath(site_dir, fp)
@ -201,6 +291,14 @@ def copy_package(name, info, odir):
else: else:
copy_dir_exclude(exclude, site_dir, fp, odir) copy_dir_exclude(exclude, site_dir, fp, odir)
def copy_wx(odir):
base_dir = os.path.dirname(os.path.dirname(wx.__file__))
wx_dir = os.path.join(base_dir, "wx")
exclude = get_pkg_exclude("wx")
copy_dir_exclude(exclude, base_dir, wx_dir, odir)
def collect_site_packages(sitedir, odir): def collect_site_packages(sitedir, odir):
if not os.path.exists(odir): if not os.path.exists(odir):
os.makedirs(odir) os.makedirs(odir)
@ -208,6 +306,10 @@ def collect_site_packages(sitedir, odir):
for name, info in SITE_PACKAGES.iteritems(): for name, info in SITE_PACKAGES.iteritems():
copy_package(name, info, odir) copy_package(name, info, odir)
assert "wx" in SITE_PACKAGES
copy_wx(odir)
def compile_openslides_launcher(): def compile_openslides_launcher():
try: try:
cc = distutils.ccompiler.new_compiler() cc = distutils.ccompiler.new_compiler()
@ -219,10 +321,34 @@ def compile_openslides_launcher():
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.add_library_dir(os.path.join(sys.exec_prefix, "Libs"))
objs = cc.compile(["extras/win32-portable/openslides.c"]) gui_data_dir = os.path.dirname(openslides_gui.__file__)
cc.link_executable(objs, "extras/win32-portable/openslides") gui_data_dir = os.path.join(gui_data_dir, "data")
shutil.copyfile(
os.path.join(gui_data_dir, "openslides.ico"),
"extras/win32-portable/openslides.ico")
rcfile = "extras/win32-portable/openslides.rc"
with open(rcfile, "w") as f:
if openslides.VERSION[3] == "final":
file_flags = "0"
else:
file_flags = "VS_FF_PRERELEASE"
f.write(OPENSLIDES_RC_TMPL.format(
version=openslides.VERSION,
version_str=openslides.get_version(),
file_flags=file_flags))
objs = cc.compile([
"extras/win32-portable/openslides.c",
rcfile,
])
cc.link_executable(
objs, "extras/win32-portable/openslides",
extra_preargs=["/subsystem:windows"],
)
return True return True
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")
@ -239,6 +365,7 @@ def copy_dlls(odir):
dest = os.path.join(odir, pydllname) dest = os.path.join(odir, pydllname)
shutil.copyfile(src, dest) shutil.copyfile(src, dest)
def copy_msvcr(odir): def copy_msvcr(odir):
candidates = glob.glob("{0}/x86_*{1}_{2}*".format( candidates = glob.glob("{0}/x86_*{1}_{2}*".format(
os.path.join(os.environ["WINDIR"], "winsxs"), os.path.join(os.environ["WINDIR"], "winsxs"),
@ -253,11 +380,11 @@ def copy_msvcr(odir):
msvcr_dll_dir = dp msvcr_dll_dir = dp
break break
else: else:
sys.stderr.write("Warning could not determine msvcr runtime location\n") sys.stderr.write(
sys.stderr.write("Private asssembly for VC runtime must be added manually\n") "Warning could not determine msvcr runtime location\n"
"Private asssembly for VC runtime must be added manually\n")
return return
msvcr_dest_dir = os.path.join(odir, MSVCR_NAME) msvcr_dest_dir = os.path.join(odir, MSVCR_NAME)
if not os.path.exists(msvcr_dest_dir): if not os.path.exists(msvcr_dest_dir):
os.makedirs(msvcr_dest_dir) os.makedirs(msvcr_dest_dir)
@ -267,7 +394,8 @@ def copy_msvcr(odir):
dest = os.path.join(msvcr_dest_dir, fn) dest = os.path.join(msvcr_dest_dir, fn)
shutil.copyfile(src, dest) shutil.copyfile(src, dest)
src = os.path.join(os.environ["WINDIR"], "winsxs", "Manifests", src = os.path.join(
os.environ["WINDIR"], "winsxs", "Manifests",
"{0}.manifest".format(msvcr_local_name)) "{0}.manifest".format(msvcr_local_name))
dest = os.path.join(msvcr_dest_dir, "{0}.manifest".format(MSVCR_NAME)) dest = os.path.join(msvcr_dest_dir, "{0}.manifest".format(MSVCR_NAME))
shutil.copyfile(src, dest) shutil.copyfile(src, dest)
@ -279,9 +407,13 @@ def write_readme(orig_readme, outfile):
text.extend(["\n", "\n", "Included Packages\n", 17 * "=" + "\n"]) text.extend(["\n", "\n", "Included Packages\n", 17 * "=" + "\n"])
for pkg in sorted(SITE_PACKAGES): for pkg in sorted(SITE_PACKAGES):
dist = pkg_resources.get_distribution(pkg) try:
text.append("{0}-{1}\n".format(dist.project_name, dist.version)) dist = pkg_resources.get_distribution(pkg)
text.append("{0}-{1}\n".format(dist.project_name, dist.version))
except pkg_resources.DistributionNotFound:
# FIXME: wxpython comes from an installer and has no distribution
# see what we can do about that
text.append("{0}-???\n".format(pkg))
with open(outfile, "w") as f: with open(outfile, "w") as f:
f.writelines(text) f.writelines(text)
@ -301,7 +433,7 @@ def main():
raise raise
os.makedirs(odir) os.makedirs(odir)
out_site_packages = os.path.join(odir, "site-packages") out_site_packages = os.path.join(odir, "Lib", "site-packages")
collect_lib(libdir, odir) collect_lib(libdir, odir)
collect_site_packages(sitedir, out_site_packages) collect_site_packages(sitedir, out_site_packages)
@ -312,20 +444,26 @@ 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")
shutil.copyfile("extras/win32-portable/openslides.exe", shutil.copyfile(
"extras/win32-portable/openslides.exe",
os.path.join(odir, "openslides.exe")) os.path.join(odir, "openslides.exe"))
shutil.copytree(
"extras/openslides_gui",
os.path.join(out_site_packages, "openslides_gui"))
copy_dlls(odir) copy_dlls(odir)
copy_msvcr(odir) copy_msvcr(odir)
shutil.copytree("extras/win32-portable/licenses", shutil.copytree(
"extras/win32-portable/licenses",
os.path.join(odir, "licenses")) os.path.join(odir, "licenses"))
zip_fp = os.path.join("dist", "openslides-{0}-portable.zip".format( zip_fp = os.path.join(
"dist", "openslides-{0}-portable.zip".format(
openslides.get_version())) openslides.get_version()))
write_readme("README.txt", write_readme("README.txt", os.path.join(odir, "README.txt"))
os.path.join(odir, "README.txt"))
with zipfile.ZipFile(zip_fp, "w", zipfile.ZIP_DEFLATED) as zf: with zipfile.ZipFile(zip_fp, "w", zipfile.ZIP_DEFLATED) as zf:
for dp, dnames, fnames in os.walk(odir): for dp, dnames, fnames in os.walk(odir):