commit
1415461141
@ -10,6 +10,8 @@ Version 2.0.0 (unreleased)
|
|||||||
|
|
||||||
Agenda:
|
Agenda:
|
||||||
- Updated the tests and changed internal parts of method of the agenda model.
|
- Updated the tests and changed internal parts of method of the agenda model.
|
||||||
|
- Changed API of related objects. All assignments, motions and custom slides
|
||||||
|
are now agenda items and can be hidden.
|
||||||
- Removed mptt.
|
- Removed mptt.
|
||||||
Assignments:
|
Assignments:
|
||||||
- Renamed app from assignment to assignments.
|
- Renamed app from assignment to assignments.
|
||||||
@ -25,6 +27,7 @@ Users:
|
|||||||
- Used authentication frontend via AngularJS.
|
- Used authentication frontend via AngularJS.
|
||||||
Other:
|
Other:
|
||||||
- New OpenSlides logo.
|
- New OpenSlides logo.
|
||||||
|
- New design for web interface.
|
||||||
- Added multiple countdown support.
|
- Added multiple countdown support.
|
||||||
- Changed supported Python version to >= 3.3.
|
- Changed supported Python version to >= 3.3.
|
||||||
- Used Django 1.7 as lowest requirement.
|
- Used Django 1.7 as lowest requirement.
|
||||||
@ -53,6 +56,8 @@ Other:
|
|||||||
- Used setup.cfg for development tools.
|
- Used setup.cfg for development tools.
|
||||||
- Removed code for Windows portable version with GUI. Used new repository for
|
- Removed code for Windows portable version with GUI. Used new repository for
|
||||||
this.
|
this.
|
||||||
|
Translations:
|
||||||
|
- Added DE and FR translations.
|
||||||
|
|
||||||
|
|
||||||
Version 1.7 (2015-02-16)
|
Version 1.7 (2015-02-16)
|
||||||
|
@ -3,6 +3,7 @@ include CHANGELOG
|
|||||||
include LICENSE
|
include LICENSE
|
||||||
include README.rst
|
include README.rst
|
||||||
include requirements_production.txt
|
include requirements_production.txt
|
||||||
|
include bower.json
|
||||||
recursive-include openslides *.*
|
recursive-include openslides *.*
|
||||||
recursive-exclude openslides *.pyc
|
recursive-exclude openslides *.pyc
|
||||||
recursive-exclude openslides *.swp
|
recursive-exclude openslides *.swp
|
||||||
|
74
README.rst
74
README.rst
@ -131,15 +131,14 @@ To start OpenSlides simply run on command line::
|
|||||||
openslides
|
openslides
|
||||||
|
|
||||||
If you run this command the first time, a new database and the admin account
|
If you run this command the first time, a new database and the admin account
|
||||||
(Username: `admin`) will be created. Please change the password (Password:
|
(Username: `admin`, Password: `admin`) will be created. Please change the password
|
||||||
`admin`) after first login!
|
after first login!
|
||||||
|
|
||||||
OpenSlides will start using the integrated Tornado webserver. It will also
|
OpenSlides will start using the integrated Tornado webserver. It will also
|
||||||
try to open the webinterface in your default webbrowser. The server will
|
try to open the webinterface in your default webbrowser. The server will
|
||||||
try to listen on the local ip address on port 80 or port 8000 if you do not
|
try to listen on the local ip address on port 8000. That means that the server
|
||||||
have admin permissions. That means that the server will be available to
|
will be available to everyone on your local network (at least for commonly used
|
||||||
everyone on your local network (at least for commonly used network
|
network configurations).
|
||||||
configurations).
|
|
||||||
|
|
||||||
If you use a virtual environment (see install instructions, step 2), do not
|
If you use a virtual environment (see install instructions, step 2), do not
|
||||||
forget to activate the environment before restart after you have closed the
|
forget to activate the environment before restart after you have closed the
|
||||||
@ -242,22 +241,23 @@ VI. Used software
|
|||||||
|
|
||||||
OpenSlides uses the following projects or parts of them:
|
OpenSlides uses the following projects or parts of them:
|
||||||
|
|
||||||
* `backports.ssl_match_hostname <https://bitbucket.org/brandon/backports.ssl_match_hostname>`_,
|
* `backports-abc <https://github.com/cython/backports_abc>`_,
|
||||||
License: Python Software Foundation License
|
License: Python Software Foundation License
|
||||||
|
|
||||||
* `Beautiful Soup <http://www.crummy.com/software/BeautifulSoup/>`_,
|
* `Beautiful Soup <http://www.crummy.com/software/BeautifulSoup/>`_,
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
* `Bootstrap <http://getbootstrap.com/2.3.2/>`_, License: Apache
|
|
||||||
License v2.0
|
|
||||||
|
|
||||||
* `Django <https://www.djangoproject.com>`_, License: BSD
|
* `Django <https://www.djangoproject.com>`_, License: BSD
|
||||||
|
|
||||||
* `Django CKEditor <https://github.com/riklaunim/django-ckeditor>`_, License: BSD
|
|
||||||
|
|
||||||
* `Django haystack <http://haystacksearch.org>`_, License: BSD
|
* `Django haystack <http://haystacksearch.org>`_, License: BSD
|
||||||
|
|
||||||
* `pdf.js <http://mozilla.github.io/pdf.js/>`_, License: Apache License v2.0
|
* `Django REST framework <http://www.django-rest-framework.org>`_, License: BSD
|
||||||
|
|
||||||
|
* `html5-lib <https://github.com/html5lib/html5lib-python>`_, License: MIT
|
||||||
|
|
||||||
|
* `jsonfield <https://github.com/bradjasper/django-jsonfield/>`_, License: MIT
|
||||||
|
|
||||||
|
* `natsort <https://github.com/SethMMorton/natsort/>`_, License: MIT
|
||||||
|
|
||||||
* `ReportLab <http://www.reportlab.com/software/opensource/rl-toolkit/>`_,
|
* `ReportLab <http://www.reportlab.com/software/opensource/rl-toolkit/>`_,
|
||||||
License: BSD
|
License: BSD
|
||||||
@ -270,24 +270,46 @@ OpenSlides uses the following projects or parts of them:
|
|||||||
* `sockjs-tornado <https://github.com/mrjoes/sockjs-tornado>`_,
|
* `sockjs-tornado <https://github.com/mrjoes/sockjs-tornado>`_,
|
||||||
License: MIT
|
License: MIT
|
||||||
|
|
||||||
* `Sphinx <http://sphinx-doc.org/>`_, License: BSD
|
|
||||||
|
|
||||||
* Sphinx extension `autoimage <https://gist.github.com/kroger/3856821/>`_,
|
|
||||||
License: MIT
|
|
||||||
|
|
||||||
* `Sphinx Bootstrap Theme
|
|
||||||
<http://ryan-roemer.github.io/sphinx-bootstrap-theme/>`_, License: MIT
|
|
||||||
|
|
||||||
* `Tornado <http://www.tornadoweb.org/en/stable/>`_, License: Apache
|
* `Tornado <http://www.tornadoweb.org/en/stable/>`_, License: Apache
|
||||||
License v2.0
|
License v2.0
|
||||||
|
|
||||||
* `Ubuntu TrueType Font <http://font.ubuntu.com>`_, License: Ubuntu Font
|
|
||||||
Licence 1.0
|
|
||||||
|
|
||||||
* `Whoosh <https://bitbucket.org/mchaput/whoosh/wiki/Home/>`_, License: BSD
|
|
||||||
|
|
||||||
* Several JavaScript packages (see bower.json)
|
* Several JavaScript packages (see bower.json)
|
||||||
|
|
||||||
|
* `angular <https://angularjs.org>`_, License: MIT
|
||||||
|
* `angular-animate <https://github.com/angular/bower-angular-animate>`_, License: MIT
|
||||||
|
* `angular-bootstrap <https://angular-ui.github.io/bootstrap>`_, License: MIT
|
||||||
|
* `angular-ckeditor <https://github.com/lemonde/angular-ckeditor>`_, License: MIT
|
||||||
|
* `angular-csv-import <https://github.com/cybadave/angular-csv-import>`_, License: MIT
|
||||||
|
* `angular-formly <http://angular-formly.com/>`_, License: MIT
|
||||||
|
* `angular-formly-templates-bootstrap <http://angular-formly.com/>`_, License: MIT
|
||||||
|
* `angular-gettext <https://angular-gettext.rocketeer.be/>`_, License: MIT
|
||||||
|
* `angular-loading-bar <https://chieffancypants.github.io/angular-loading-bar/>`_, License: MIT
|
||||||
|
* `angular-messages <https://github.com/angular/bower-angular-messages>`_, License: MIT
|
||||||
|
* `angular-sanitize <https://github.com/angular/bower-angular-sanitize>`_, License: MIT
|
||||||
|
* `angular-scroll-glue <https://github.com/Luegg/angularjs-scroll-glue>`_, License: MIT
|
||||||
|
* `angular-ui-router <http://angular-ui.github.io/ui-router>`_, License: MIT
|
||||||
|
* `angular-ui-select <https://github.com/angular-ui/ui-select>`_, License: MIT
|
||||||
|
* `angular-ui-switch <https://github.com/xpepermint/angular-ui-switch>`_, License: MIT
|
||||||
|
* `angular-ui-tree <https://github.com/JimLiu/angular-ui-tree>`_, License: MIT
|
||||||
|
* `api-check <https://github.com/kentcdodds/apiCheck.js>`_, License: MIT
|
||||||
|
* `bootbox <http://bootboxjs.com/>`_, License: MIT
|
||||||
|
* `bootstrap <http://getbootstrap.com>`_, License: MIT
|
||||||
|
* `bootstrap-css-only <http://getbootstrap.com>`_, License: MIT
|
||||||
|
* `ckeditor <http://ckeditor.com>`_, License: For licensing, see LICENSE.md or http://ckeditor.com/license.
|
||||||
|
* `font-awesome-bower <https://github.com/interval-braining/font-awesome-bower>`_, License: MIT
|
||||||
|
* `jquery <https://jquery.com>`_, License: MIT
|
||||||
|
* `jquery.cookie <https://plugins.jquery.com/cookie>`_, License: MIT
|
||||||
|
* `js-data <http://www.js-data.io>`_, License: MIT
|
||||||
|
* `js-data-angular <http://www.js-data.io/docs/js-data-angular>`_, License: MIT
|
||||||
|
* `js-data-http <http://www.js-data.io/docs/dshttpadapter>`_, License: MIT
|
||||||
|
* `lodash <https://lodash.com/>`_, License: MIT
|
||||||
|
* `ng-dialog <https://github.com/likeastore/ngDialog>`_, License: MIT
|
||||||
|
* `ng-file-upload <https://github.com/danialfarid/ng-file-upload>`_, License: MIT
|
||||||
|
* `ngBootbox <https://github.com/eriktufvesson/ngBootbox>`_, License: MIT
|
||||||
|
* `open-sans-fontface <https://github.com/FontFaceKit/open-sans>`_, License: Apache License version 2.0
|
||||||
|
* `roboto-condensed <https://github.com/davidcunningham/roboto-condensed>`_, License: Apache-2.0
|
||||||
|
* `sockjs <https://github.com/sockjs/sockjs-client>`_, License: MIT
|
||||||
|
|
||||||
|
|
||||||
VII. License and authors
|
VII. License and authors
|
||||||
========================
|
========================
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
from .gui import main
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
Binary file not shown.
Before Width: | Height: | Size: 7.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 22 KiB |
@ -1,756 +0,0 @@
|
|||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import Queue
|
|
||||||
import datetime
|
|
||||||
import errno
|
|
||||||
import gettext
|
|
||||||
import itertools
|
|
||||||
import json
|
|
||||||
import locale
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import wx
|
|
||||||
|
|
||||||
import openslides
|
|
||||||
|
|
||||||
from openslides.utils.main import (
|
|
||||||
detect_openslides_type,
|
|
||||||
filesystem2unicode,
|
|
||||||
unicode2filesystem,
|
|
||||||
get_default_user_data_path,
|
|
||||||
get_port,
|
|
||||||
PortableDirNotWritable,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# NOTE: djangos translation module can't be used here since it requires
|
|
||||||
# a defined settings module
|
|
||||||
_translations = gettext.NullTranslations()
|
|
||||||
_ = lambda text: _translations.ugettext(text)
|
|
||||||
ungettext = lambda msg1, msg2, n: _translations.ungettext(msg1, msg2, n)
|
|
||||||
|
|
||||||
|
|
||||||
def get_data_path(*args):
|
|
||||||
path = filesystem2unicode(__file__)
|
|
||||||
return os.path.join(os.path.dirname(path), "data", *args)
|
|
||||||
|
|
||||||
|
|
||||||
class RunCmdEvent(wx.PyCommandEvent):
|
|
||||||
def __init__(self, evt_type, evt_id):
|
|
||||||
super(RunCmdEvent, self).__init__(evt_type, evt_id)
|
|
||||||
|
|
||||||
self.running = False
|
|
||||||
self.exitcode = None
|
|
||||||
|
|
||||||
EVT_RUN_CMD_ID = wx.NewEventType()
|
|
||||||
EVT_RUN_CMD = wx.PyEventBinder(EVT_RUN_CMD_ID, 1)
|
|
||||||
|
|
||||||
|
|
||||||
class RunCommandControl(wx.Panel):
|
|
||||||
UPDATE_INTERVAL = 500
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
super(RunCommandControl, self).__init__(parent)
|
|
||||||
|
|
||||||
self.child_process = None
|
|
||||||
self.output_queue = Queue.Queue()
|
|
||||||
self.output_read_thread = None
|
|
||||||
self.canceled = False
|
|
||||||
self.output_mutex = threading.RLock()
|
|
||||||
|
|
||||||
vbox = wx.BoxSizer(wx.VERTICAL)
|
|
||||||
|
|
||||||
self.te_output = wx.TextCtrl(
|
|
||||||
self, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL)
|
|
||||||
vbox.Add(self.te_output, 1, wx.EXPAND)
|
|
||||||
|
|
||||||
self.update_timer = wx.Timer(self)
|
|
||||||
self.Bind(wx.EVT_TIMER, self.on_update_timer, self.update_timer)
|
|
||||||
|
|
||||||
self.SetSizerAndFit(vbox)
|
|
||||||
|
|
||||||
def _read_output(self):
|
|
||||||
while True:
|
|
||||||
# NOTE: don't use iterator interface since it uses an
|
|
||||||
# internal buffer and we don't see output in a timely fashion
|
|
||||||
line = self.child_process.stdout.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
self.output_queue.put(line)
|
|
||||||
|
|
||||||
def is_alive(self):
|
|
||||||
if self.child_process is None:
|
|
||||||
return False
|
|
||||||
return self.child_process.poll() is None
|
|
||||||
|
|
||||||
def run_command(self, *args):
|
|
||||||
if self.is_alive():
|
|
||||||
raise ValueError("already running a command")
|
|
||||||
|
|
||||||
cmd = [sys.executable, "-u", "-m", "openslides"]
|
|
||||||
cmd.extend(args)
|
|
||||||
|
|
||||||
# XXX: subprocess on windows only handles byte strings
|
|
||||||
# with python3 this will hopefully no longer be the case
|
|
||||||
cmd = [unicode2filesystem(x) for x in cmd]
|
|
||||||
|
|
||||||
creationflags = getattr(subprocess, "CREATE_NEW_PROCESS_GROUP", 0)
|
|
||||||
self.child_process = subprocess.Popen(
|
|
||||||
cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.STDOUT, creationflags=creationflags)
|
|
||||||
self.child_process.stdin.close()
|
|
||||||
self.output_read_thread = threading.Thread(target=self._read_output)
|
|
||||||
self.output_read_thread.start()
|
|
||||||
|
|
||||||
self.update_timer.Start(self.UPDATE_INTERVAL)
|
|
||||||
|
|
||||||
evt = RunCmdEvent(EVT_RUN_CMD_ID, self.GetId())
|
|
||||||
evt.running = True
|
|
||||||
self.GetEventHandler().ProcessEvent(evt)
|
|
||||||
|
|
||||||
def cancel_command(self):
|
|
||||||
if not self.is_alive():
|
|
||||||
return
|
|
||||||
|
|
||||||
# TODO: try sigint first, then get more aggressive if user insists
|
|
||||||
self.child_process.kill()
|
|
||||||
self.canceled = True
|
|
||||||
|
|
||||||
def on_update_timer(self, evt):
|
|
||||||
is_alive = self.is_alive()
|
|
||||||
if not is_alive:
|
|
||||||
# join thread to make sure everything was read
|
|
||||||
self.output_read_thread.join()
|
|
||||||
self.output_read_thread = None
|
|
||||||
|
|
||||||
for line_no in itertools.count():
|
|
||||||
try:
|
|
||||||
data = self.output_queue.get(block=False)
|
|
||||||
except Queue.Empty:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# XXX: check whether django uses utf-8 or locale for
|
|
||||||
# it's cli output
|
|
||||||
text = data.decode("utf-8", errors="replace")
|
|
||||||
with self.output_mutex:
|
|
||||||
self.te_output.AppendText(text)
|
|
||||||
|
|
||||||
# avoid waiting too long here if child is still alive
|
|
||||||
if is_alive and line_no > 10:
|
|
||||||
break
|
|
||||||
|
|
||||||
if not is_alive:
|
|
||||||
exitcode = self.child_process.returncode
|
|
||||||
self.update_timer.Stop()
|
|
||||||
self.child_process = None
|
|
||||||
|
|
||||||
evt = RunCmdEvent(EVT_RUN_CMD_ID, self.GetId())
|
|
||||||
evt.running = False
|
|
||||||
evt.exitcode = exitcode
|
|
||||||
self.GetEventHandler().ProcessEvent(evt)
|
|
||||||
|
|
||||||
def append_message(self, text, newline="\n"):
|
|
||||||
with self.output_mutex:
|
|
||||||
self.te_output.AppendText(text + newline)
|
|
||||||
|
|
||||||
|
|
||||||
class SettingsDialog(wx.Dialog):
|
|
||||||
def __init__(self, parent):
|
|
||||||
super(SettingsDialog, self).__init__(parent, wx.ID_ANY, _("Settings"))
|
|
||||||
|
|
||||||
grid = wx.GridBagSizer(5, 5)
|
|
||||||
row = 0
|
|
||||||
|
|
||||||
lb_host = wx.StaticText(self, label=_("&Host:"))
|
|
||||||
grid.Add(lb_host, pos=(row, 0))
|
|
||||||
self.tc_host = wx.TextCtrl(self)
|
|
||||||
grid.Add(self.tc_host, pos=(row, 1), flag=wx.EXPAND)
|
|
||||||
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
lb_port = wx.StaticText(self, label=_("&Port:"))
|
|
||||||
grid.Add(lb_port, pos=(row, 0))
|
|
||||||
self.tc_port = wx.TextCtrl(self)
|
|
||||||
grid.Add(self.tc_port, pos=(row, 1), flag=wx.EXPAND)
|
|
||||||
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL)
|
|
||||||
if not sizer is None:
|
|
||||||
grid.Add((0, 0), pos=(row, 0), span=(1, 2))
|
|
||||||
row += 1
|
|
||||||
grid.Add(sizer, pos=(row, 0), span=(1, 2))
|
|
||||||
|
|
||||||
box = wx.BoxSizer(wx.VERTICAL)
|
|
||||||
box.Add(
|
|
||||||
grid, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL,
|
|
||||||
border=5, proportion=1)
|
|
||||||
|
|
||||||
self.SetSizerAndFit(box)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def host(self):
|
|
||||||
return self.tc_host.GetValue()
|
|
||||||
|
|
||||||
@host.setter
|
|
||||||
def host(self, host):
|
|
||||||
self.tc_host.SetValue(host)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def port(self):
|
|
||||||
return self.tc_port.GetValue()
|
|
||||||
|
|
||||||
@port.setter
|
|
||||||
def port(self, port):
|
|
||||||
self.tc_port.SetValue(port)
|
|
||||||
|
|
||||||
|
|
||||||
class BackupSettingsDialog(wx.Dialog):
|
|
||||||
# NOTE: keep order in sync with _update_interval_choices()
|
|
||||||
_INTERVAL_UNITS = ["second", "minute", "hour"]
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
super(BackupSettingsDialog, self).__init__(
|
|
||||||
parent, wx.ID_ANY, _("Database backup"))
|
|
||||||
|
|
||||||
self._interval_units = {}
|
|
||||||
|
|
||||||
grid = wx.GridBagSizer(5, 5)
|
|
||||||
row = 0
|
|
||||||
|
|
||||||
self.cb_backup = wx.CheckBox(
|
|
||||||
self, label=_("&Regularly backup database"))
|
|
||||||
self.cb_backup.SetValue(True)
|
|
||||||
self.cb_backup.Bind(wx.EVT_CHECKBOX, self.on_backup_checked)
|
|
||||||
grid.Add(self.cb_backup, pos=(row, 0), span=(1, 3))
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
lb_dest = wx.StaticText(self, label=_("&Destination:"))
|
|
||||||
grid.Add(lb_dest, pos=(row, 0))
|
|
||||||
style = wx.FLP_SAVE | wx.FLP_USE_TEXTCTRL
|
|
||||||
self.fp_dest = wx.FilePickerCtrl(self, style=style)
|
|
||||||
grid.Add(self.fp_dest, pos=(row, 1), span=(1, 2), flag=wx.EXPAND)
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
lb_interval = wx.StaticText(self, label=_("&Every"))
|
|
||||||
grid.Add(lb_interval, pos=(row, 0))
|
|
||||||
self.sb_interval = wx.SpinCtrl(self, min=1, initial=1)
|
|
||||||
self.sb_interval.Bind(wx.EVT_SPINCTRL, self.on_interval_changed)
|
|
||||||
grid.Add(self.sb_interval, pos=(row, 1))
|
|
||||||
self.ch_interval_unit = wx.Choice(self)
|
|
||||||
grid.Add(self.ch_interval_unit, pos=(row, 2))
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
grid.AddGrowableCol(1)
|
|
||||||
|
|
||||||
sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL)
|
|
||||||
if not sizer is None:
|
|
||||||
grid.Add((0, 0), pos=(row, 0), span=(1, 3))
|
|
||||||
row += 1
|
|
||||||
grid.Add(sizer, pos=(row, 0), span=(1, 3))
|
|
||||||
|
|
||||||
box = wx.BoxSizer(wx.VERTICAL)
|
|
||||||
box.Add(
|
|
||||||
grid, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL,
|
|
||||||
border=5, proportion=1)
|
|
||||||
|
|
||||||
self.SetSizerAndFit(box)
|
|
||||||
self._update_interval_choices()
|
|
||||||
self._update_backup_enabled()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def backupdb_enabled(self):
|
|
||||||
return self.cb_backup.GetValue()
|
|
||||||
|
|
||||||
@backupdb_enabled.setter
|
|
||||||
def backupdb_enabled(self, enabled):
|
|
||||||
self.cb_backup.SetValue(enabled)
|
|
||||||
self._update_backup_enabled()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def backupdb_destination(self):
|
|
||||||
return self.fp_dest.GetPath()
|
|
||||||
|
|
||||||
@backupdb_destination.setter
|
|
||||||
def backupdb_destination(self, path):
|
|
||||||
self.fp_dest.SetPath(path)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def interval(self):
|
|
||||||
return self.sb_interval.GetValue()
|
|
||||||
|
|
||||||
@interval.setter
|
|
||||||
def interval(self, value):
|
|
||||||
self.sb_interval.SetValue(value)
|
|
||||||
self._update_interval_choices()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def interval_unit(self):
|
|
||||||
return self._INTERVAL_UNITS[self.ch_interval_unit.GetSelection()]
|
|
||||||
|
|
||||||
@interval_unit.setter
|
|
||||||
def interval_unit(self, unit):
|
|
||||||
try:
|
|
||||||
idx = self._INTERVAL_UNITS.index(unit)
|
|
||||||
except IndexError:
|
|
||||||
raise ValueError("Unknown unit {0}".format(unit))
|
|
||||||
|
|
||||||
self.ch_interval_unit.SetSelection(idx)
|
|
||||||
|
|
||||||
def _update_interval_choices(self):
|
|
||||||
count = self.sb_interval.GetValue()
|
|
||||||
choices = [
|
|
||||||
ungettext("second", "seconds", count),
|
|
||||||
ungettext("minute", "minutes", count),
|
|
||||||
ungettext("hour", "hours", count),
|
|
||||||
]
|
|
||||||
|
|
||||||
current = self.ch_interval_unit.GetSelection()
|
|
||||||
if current == wx.NOT_FOUND:
|
|
||||||
current = 2 # default to hour
|
|
||||||
|
|
||||||
self.ch_interval_unit.Clear()
|
|
||||||
self.ch_interval_unit.AppendItems(choices)
|
|
||||||
self.ch_interval_unit.SetSelection(current)
|
|
||||||
|
|
||||||
def _update_backup_enabled(self):
|
|
||||||
checked = self.cb_backup.IsChecked()
|
|
||||||
self.fp_dest.Enable(checked)
|
|
||||||
self.sb_interval.Enable(checked)
|
|
||||||
self.ch_interval_unit.Enable(checked)
|
|
||||||
|
|
||||||
def on_backup_checked(self, evt):
|
|
||||||
self._update_backup_enabled()
|
|
||||||
|
|
||||||
def on_interval_changed(self, evt):
|
|
||||||
self._update_interval_choices()
|
|
||||||
|
|
||||||
# TODO: validate settings on close (e.g. non-empty path if backup is
|
|
||||||
# enabled)
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(wx.Frame):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(MainWindow, self).__init__(parent, title="OpenSlides")
|
|
||||||
icons = wx.IconBundleFromFile(
|
|
||||||
get_data_path("openslides.ico"),
|
|
||||||
wx.BITMAP_TYPE_ICO)
|
|
||||||
self.SetIcons(icons)
|
|
||||||
|
|
||||||
self.server_running = False
|
|
||||||
|
|
||||||
self.gui_settings_path = None
|
|
||||||
self.gui_initialized = False
|
|
||||||
|
|
||||||
self.backupdb_enabled = False
|
|
||||||
self.backupdb_destination = ""
|
|
||||||
self.backupdb_interval = 15
|
|
||||||
self.backupdb_interval_unit = "minute"
|
|
||||||
self.last_backup = None
|
|
||||||
|
|
||||||
self.backup_timer = wx.Timer(self)
|
|
||||||
self.Bind(wx.EVT_TIMER, self.on_backup_timer, self.backup_timer)
|
|
||||||
|
|
||||||
spacing = 5
|
|
||||||
|
|
||||||
panel = wx.Panel(self)
|
|
||||||
grid = wx.GridBagSizer(spacing, spacing)
|
|
||||||
|
|
||||||
# logo & about button
|
|
||||||
logo_box = wx.BoxSizer(wx.HORIZONTAL)
|
|
||||||
grid.Add(logo_box, pos=(0, 0), flag=wx.EXPAND)
|
|
||||||
row = 0
|
|
||||||
|
|
||||||
fp = get_data_path("openslides-logo_wide.png")
|
|
||||||
with open(fp, "rb") as f:
|
|
||||||
logo_wide_bmp = wx.ImageFromStream(f).ConvertToBitmap()
|
|
||||||
|
|
||||||
logo_wide = wx.StaticBitmap(panel, wx.ID_ANY, logo_wide_bmp)
|
|
||||||
logo_box.AddSpacer(2 * spacing)
|
|
||||||
logo_box.Add(logo_wide)
|
|
||||||
logo_box.AddStretchSpacer()
|
|
||||||
|
|
||||||
version_str = _("Version {0}").format(openslides.get_version())
|
|
||||||
lb_version = wx.StaticText(panel, label=version_str)
|
|
||||||
font = lb_version.GetFont()
|
|
||||||
font.SetPointSize(8)
|
|
||||||
lb_version.SetFont(font)
|
|
||||||
logo_box.Add(lb_version, flag=wx.ALIGN_CENTER_VERTICAL)
|
|
||||||
|
|
||||||
self.bt_about = wx.Button(panel, label=_("&About..."))
|
|
||||||
self.bt_about.Bind(wx.EVT_BUTTON, self.on_about_clicked)
|
|
||||||
grid.Add(self.bt_about, pos=(row, 1), flag=wx.ALIGN_CENTER_VERTICAL)
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
grid.Add((0, spacing), pos=(row, 0), span=(1, 2))
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
# server settings
|
|
||||||
server_settings = wx.StaticBox(panel, wx.ID_ANY, _("Server Settings"))
|
|
||||||
server_box = wx.StaticBoxSizer(server_settings, wx.VERTICAL)
|
|
||||||
grid.Add(server_box, pos=(row, 0), flag=wx.EXPAND)
|
|
||||||
|
|
||||||
self._host = None
|
|
||||||
self._port = None
|
|
||||||
hbox = wx.BoxSizer(wx.HORIZONTAL)
|
|
||||||
server_box.Add(hbox, flag=wx.EXPAND)
|
|
||||||
self.lb_host = wx.StaticText(panel)
|
|
||||||
hbox.Add(self.lb_host, flag=wx.ALIGN_CENTER_VERTICAL)
|
|
||||||
hbox.AddStretchSpacer()
|
|
||||||
self.lb_port = wx.StaticText(panel)
|
|
||||||
hbox.Add(self.lb_port, flag=wx.ALIGN_CENTER_VERTICAL)
|
|
||||||
hbox.AddStretchSpacer()
|
|
||||||
self.bt_settings = wx.Button(panel, label=_("S&ettings..."))
|
|
||||||
self.bt_settings.Bind(wx.EVT_BUTTON, self.on_settings_clicked)
|
|
||||||
hbox.Add(self.bt_settings)
|
|
||||||
|
|
||||||
server_box.AddSpacer(spacing)
|
|
||||||
self.cb_start_browser = wx.CheckBox(
|
|
||||||
panel, label=_("Automatically open &browser"))
|
|
||||||
self.cb_start_browser.SetValue(True)
|
|
||||||
server_box.Add(self.cb_start_browser)
|
|
||||||
server_box.AddStretchSpacer()
|
|
||||||
|
|
||||||
server_box.AddSpacer(spacing)
|
|
||||||
self.bt_server = wx.Button(panel, label=_("&Start server"))
|
|
||||||
self.bt_server.Bind(wx.EVT_BUTTON, self.on_start_server_clicked)
|
|
||||||
server_box.Add(self.bt_server, flag=wx.EXPAND)
|
|
||||||
|
|
||||||
self.host = "0.0.0.0"
|
|
||||||
self.port = unicode(get_port(self.host, 80))
|
|
||||||
|
|
||||||
# "action" buttons
|
|
||||||
action_vbox = wx.BoxSizer(wx.VERTICAL)
|
|
||||||
action_vbox.AddSpacer(3 * spacing)
|
|
||||||
grid.Add(action_vbox, pos=(row, 1))
|
|
||||||
self.bt_backup = wx.Button(panel, label=_("&Backup database..."))
|
|
||||||
self.bt_backup.Bind(wx.EVT_BUTTON, self.on_backup_clicked)
|
|
||||||
action_vbox.Add(self.bt_backup)
|
|
||||||
action_vbox.AddSpacer(spacing)
|
|
||||||
self.bt_sync_db = wx.Button(panel, label=_("S&ync database"))
|
|
||||||
self.bt_sync_db.Bind(wx.EVT_BUTTON, self.on_syncdb_clicked)
|
|
||||||
action_vbox.Add(self.bt_sync_db)
|
|
||||||
action_vbox.AddSpacer(spacing)
|
|
||||||
self.bt_reset_admin = wx.Button(panel, label=_("&Reset admin"))
|
|
||||||
self.bt_reset_admin.Bind(wx.EVT_BUTTON, self.on_reset_admin_clicked)
|
|
||||||
action_vbox.Add(self.bt_reset_admin)
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
# command output
|
|
||||||
self.cmd_run_ctrl = RunCommandControl(panel)
|
|
||||||
self.cmd_run_ctrl.Bind(EVT_RUN_CMD, self.on_run_cmd_changed)
|
|
||||||
grid.Add(
|
|
||||||
self.cmd_run_ctrl,
|
|
||||||
pos=(row, 0), span=(1, 2),
|
|
||||||
flag=wx.EXPAND)
|
|
||||||
|
|
||||||
grid.AddGrowableCol(0)
|
|
||||||
grid.AddGrowableRow(3)
|
|
||||||
|
|
||||||
box = wx.BoxSizer(wx.VERTICAL)
|
|
||||||
box.Add(
|
|
||||||
grid, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL,
|
|
||||||
border=spacing, proportion=1)
|
|
||||||
panel.SetSizerAndFit(box)
|
|
||||||
self.Fit()
|
|
||||||
self.SetMinSize(self.ClientToWindowSize(box.GetMinSize()))
|
|
||||||
self.SetInitialSize(wx.Size(500, 400))
|
|
||||||
|
|
||||||
self.Bind(wx.EVT_CLOSE, self.on_close)
|
|
||||||
|
|
||||||
def initialize_gui(self):
|
|
||||||
if self.gui_initialized:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# 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()
|
|
||||||
try:
|
|
||||||
default_user_data_path = get_default_user_data_path(openslides_type)
|
|
||||||
except PortableDirNotWritable:
|
|
||||||
wx.MessageBox(
|
|
||||||
_("The portable directory is not writable. Please copy the "
|
|
||||||
"openslides portable to a writeable location and start it "
|
|
||||||
"again from there"),
|
|
||||||
_("Error: Portable directory not writable"),
|
|
||||||
wx.OK | wx.ICON_ERROR)
|
|
||||||
return False
|
|
||||||
|
|
||||||
self.gui_settings_path = os.path.join(
|
|
||||||
default_user_data_path, 'openslides', 'gui_settings.json')
|
|
||||||
self.load_gui_settings()
|
|
||||||
self.apply_backup_settings()
|
|
||||||
|
|
||||||
self.gui_initialized = True
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def backup_interval_seconds(self):
|
|
||||||
if self.backupdb_interval_unit == "second":
|
|
||||||
factor = 1
|
|
||||||
elif self.backupdb_interval_unit == "minute":
|
|
||||||
factor = 60
|
|
||||||
elif self.backupdb_interval_unit == "hour":
|
|
||||||
factor = 3600
|
|
||||||
|
|
||||||
return self.backupdb_interval * factor
|
|
||||||
|
|
||||||
@property
|
|
||||||
def host(self):
|
|
||||||
return self._host
|
|
||||||
|
|
||||||
@host.setter
|
|
||||||
def host(self, host):
|
|
||||||
self._host = host
|
|
||||||
self.lb_host.SetLabel(_("Host: {0}").format(host))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def port(self):
|
|
||||||
return self._port
|
|
||||||
|
|
||||||
@port.setter
|
|
||||||
def port(self, port):
|
|
||||||
self._port = port
|
|
||||||
self.lb_port.SetLabel(_("Port: {0}").format(port))
|
|
||||||
|
|
||||||
def load_gui_settings(self):
|
|
||||||
if self.gui_settings_path is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
f = open(self.gui_settings_path, "rb")
|
|
||||||
except IOError as e:
|
|
||||||
if e.errno == errno.ENOENT:
|
|
||||||
return
|
|
||||||
raise
|
|
||||||
|
|
||||||
with f:
|
|
||||||
settings = json.load(f)
|
|
||||||
|
|
||||||
def setattr_unless_none(attr, value):
|
|
||||||
if not value is None:
|
|
||||||
setattr(self, attr, value)
|
|
||||||
|
|
||||||
backup_settings = settings.get("database_backup", {})
|
|
||||||
setattr_unless_none("backupdb_enabled", backup_settings.get("enabled"))
|
|
||||||
setattr_unless_none(
|
|
||||||
"backupdb_destination", backup_settings.get("destination"))
|
|
||||||
setattr_unless_none(
|
|
||||||
"backupdb_interval", backup_settings.get("interval"))
|
|
||||||
setattr_unless_none(
|
|
||||||
"backupdb_interval_unit", backup_settings.get("interval_unit"))
|
|
||||||
last_backup = backup_settings.get("last_backup")
|
|
||||||
if not last_backup is None:
|
|
||||||
self.last_backup = datetime.datetime.strptime(
|
|
||||||
last_backup, "%Y-%m-%d %H:%M:%S")
|
|
||||||
server_settings = settings.get("server_settings", {})
|
|
||||||
setattr_unless_none("host", server_settings.get("host"))
|
|
||||||
setattr_unless_none("port", server_settings.get("port"))
|
|
||||||
|
|
||||||
def save_gui_settings(self):
|
|
||||||
if self.last_backup is None:
|
|
||||||
last_backup = None
|
|
||||||
else:
|
|
||||||
last_backup = self.last_backup.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
settings = {
|
|
||||||
"database_backup": {
|
|
||||||
"enabled": self.backupdb_enabled,
|
|
||||||
"destination": self.backupdb_destination,
|
|
||||||
"internal": self.backupdb_interval,
|
|
||||||
"interval_unit": self.backupdb_interval_unit,
|
|
||||||
"last_backup": last_backup
|
|
||||||
},
|
|
||||||
"server_settings": {
|
|
||||||
"host": self.host,
|
|
||||||
"port": self.port,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
dp = os.path.dirname(self.gui_settings_path)
|
|
||||||
if not os.path.exists(dp):
|
|
||||||
os.makedirs(dp)
|
|
||||||
with open(self.gui_settings_path, "wb") as f:
|
|
||||||
json.dump(settings, f, ensure_ascii=False, indent=4)
|
|
||||||
|
|
||||||
def apply_backup_settings(self):
|
|
||||||
if self.backupdb_enabled and self.server_running:
|
|
||||||
now = datetime.datetime.utcnow()
|
|
||||||
delta = datetime.timedelta(seconds=self.backup_interval_seconds)
|
|
||||||
ref = self.last_backup
|
|
||||||
if ref is None:
|
|
||||||
ref = now
|
|
||||||
ref += delta
|
|
||||||
|
|
||||||
d = ref - now
|
|
||||||
seconds = d.days * 86400 + d.seconds
|
|
||||||
if seconds < 1:
|
|
||||||
seconds = 30 # avoid backup immediatly after start
|
|
||||||
self.backup_timer.Start(seconds * 1000, True)
|
|
||||||
else:
|
|
||||||
self.backup_timer.Stop()
|
|
||||||
|
|
||||||
def do_backup(self):
|
|
||||||
cmd = [
|
|
||||||
sys.executable, "-u", "-m", "openslides", "backupdb",
|
|
||||||
self.backupdb_destination,
|
|
||||||
]
|
|
||||||
p = subprocess.Popen(
|
|
||||||
cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.STDOUT)
|
|
||||||
p.stdin.close()
|
|
||||||
output = p.stdout.read().strip()
|
|
||||||
exitcode = p.wait()
|
|
||||||
if output:
|
|
||||||
self.cmd_run_ctrl.append_message(output)
|
|
||||||
|
|
||||||
time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
if exitcode == 0:
|
|
||||||
self.cmd_run_ctrl.append_message(
|
|
||||||
_("{0}: Database backup successful.").format(time))
|
|
||||||
else:
|
|
||||||
self.cmd_run_ctrl.append_message(
|
|
||||||
_("{0}: Database backup failed!").format(time))
|
|
||||||
|
|
||||||
self.last_backup = datetime.datetime.utcnow()
|
|
||||||
|
|
||||||
def on_syncdb_clicked(self, evt):
|
|
||||||
self.cmd_run_ctrl.append_message(_("Syncing database..."))
|
|
||||||
self.cmd_run_ctrl.run_command("syncdb")
|
|
||||||
|
|
||||||
def on_reset_admin_clicked(self, evt):
|
|
||||||
self.cmd_run_ctrl.append_message(_("Resetting admin user..."))
|
|
||||||
self.cmd_run_ctrl.run_command("createsuperuser")
|
|
||||||
|
|
||||||
def on_about_clicked(self, evt):
|
|
||||||
info = wx.AboutDialogInfo()
|
|
||||||
info.SetName("OpenSlides")
|
|
||||||
info.SetVersion(openslides.get_version())
|
|
||||||
info.SetDescription(_(
|
|
||||||
"OpenSlides is a free web based presentation and "
|
|
||||||
"assembly system.\n"
|
|
||||||
"OpenSlides is free software; licensed under the MIT license."
|
|
||||||
).replace(u" ", u"\u00a0"))
|
|
||||||
info.SetCopyright(_(u"\u00a9 2011-2015 by OpenSlides team"))
|
|
||||||
info.SetWebSite(("http://www.openslides.org/", "www.openslides.org"))
|
|
||||||
|
|
||||||
# XXX: at least on wxgtk this has no effect
|
|
||||||
info.SetIcon(self.GetIcon())
|
|
||||||
wx.AboutBox(info)
|
|
||||||
|
|
||||||
def on_start_server_clicked(self, evt):
|
|
||||||
if self.server_running:
|
|
||||||
self.cmd_run_ctrl.cancel_command()
|
|
||||||
return
|
|
||||||
|
|
||||||
if self._host == "0.0.0.0":
|
|
||||||
args = ["--port", self._port]
|
|
||||||
else:
|
|
||||||
args = ["--address", self._host, "--port", self._port]
|
|
||||||
|
|
||||||
if not self.cb_start_browser.GetValue():
|
|
||||||
args.append("--no-browser")
|
|
||||||
|
|
||||||
self.server_running = True
|
|
||||||
self.cmd_run_ctrl.run_command("start", *args)
|
|
||||||
|
|
||||||
# initiate backup_timer if backup is enabled
|
|
||||||
self.apply_backup_settings()
|
|
||||||
|
|
||||||
self.bt_server.SetLabel(_("&Stop server"))
|
|
||||||
|
|
||||||
def on_settings_clicked(self, evt):
|
|
||||||
dlg = SettingsDialog(self)
|
|
||||||
dlg.host = self._host
|
|
||||||
dlg.port = self._port
|
|
||||||
|
|
||||||
if dlg.ShowModal() == wx.ID_OK:
|
|
||||||
self.host = dlg.host
|
|
||||||
self.port = dlg.port
|
|
||||||
|
|
||||||
def on_backup_clicked(self, evt):
|
|
||||||
dlg = BackupSettingsDialog(self)
|
|
||||||
dlg.backupdb_enabled = self.backupdb_enabled
|
|
||||||
dlg.backupdb_destination = self.backupdb_destination
|
|
||||||
dlg.interval = self.backupdb_interval
|
|
||||||
dlg.interval_unit = self.backupdb_interval_unit
|
|
||||||
if dlg.ShowModal() == wx.ID_OK:
|
|
||||||
self.backupdb_enabled = dlg.backupdb_enabled
|
|
||||||
self.backupdb_destination = dlg.backupdb_destination
|
|
||||||
self.backupdb_interval = dlg.interval
|
|
||||||
self.backupdb_interval_unit = dlg.interval_unit
|
|
||||||
self.apply_backup_settings()
|
|
||||||
|
|
||||||
def on_run_cmd_changed(self, evt):
|
|
||||||
show_completion_msg = not evt.running
|
|
||||||
if self.server_running and not evt.running:
|
|
||||||
self.bt_server.SetLabel(_("&Start server"))
|
|
||||||
self.server_running = False
|
|
||||||
|
|
||||||
self.backup_timer.Stop()
|
|
||||||
if self.backupdb_enabled:
|
|
||||||
self.do_backup()
|
|
||||||
|
|
||||||
# no operation completed msg when stopping server
|
|
||||||
show_completion_msg = False
|
|
||||||
|
|
||||||
self.bt_settings.Enable(not evt.running)
|
|
||||||
self.bt_backup.Enable(not evt.running)
|
|
||||||
self.bt_sync_db.Enable(not evt.running)
|
|
||||||
self.bt_reset_admin.Enable(not evt.running)
|
|
||||||
self.bt_server.Enable(self.server_running or not evt.running)
|
|
||||||
|
|
||||||
if show_completion_msg:
|
|
||||||
if evt.exitcode == 0:
|
|
||||||
text = _("Operation successfully completed.")
|
|
||||||
else:
|
|
||||||
text = _("Operation failed (exit code = {0})").format(
|
|
||||||
evt.exitcode)
|
|
||||||
self.cmd_run_ctrl.append_message(text)
|
|
||||||
|
|
||||||
def on_backup_timer(self, evt):
|
|
||||||
if not self.backupdb_enabled:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.do_backup()
|
|
||||||
self.backup_timer.Start(1000 * self.backup_interval_seconds, True)
|
|
||||||
|
|
||||||
def on_close(self, ev):
|
|
||||||
self.cmd_run_ctrl.cancel_command()
|
|
||||||
self.save_gui_settings()
|
|
||||||
self.Destroy()
|
|
||||||
|
|
||||||
class OpenslidesApp(wx.App):
|
|
||||||
def __init__(self):
|
|
||||||
super(OpenslidesApp, self).__init__(False)
|
|
||||||
|
|
||||||
def OnInit(self):
|
|
||||||
window = MainWindow()
|
|
||||||
self.SetTopWindow(window)
|
|
||||||
|
|
||||||
if not window.initialize_gui():
|
|
||||||
self.Exit()
|
|
||||||
return False
|
|
||||||
|
|
||||||
window.Show()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def main():
|
|
||||||
locale.setlocale(locale.LC_ALL, "")
|
|
||||||
lang = locale.getdefaultlocale()[0]
|
|
||||||
if lang:
|
|
||||||
global _translations
|
|
||||||
localedir = filesystem2unicode(openslides.__file__)
|
|
||||||
localedir = os.path.dirname(localedir)
|
|
||||||
localedir = os.path.join(localedir, "locale")
|
|
||||||
_translations = gettext.translation(
|
|
||||||
"django", localedir, [lang], fallback=True)
|
|
||||||
|
|
||||||
app = OpenslidesApp()
|
|
||||||
app.MainLoop()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,38 +0,0 @@
|
|||||||
How to create a new portable Windows distribution of OpenSlides:
|
|
||||||
----------------------------------------------------------------
|
|
||||||
|
|
||||||
1. Install Python 2.7.x and Setuptools
|
|
||||||
Follow the instructions in the README, section III (Windows installation), step 1.
|
|
||||||
|
|
||||||
|
|
||||||
2. Install all required python packages from requirements_production.txt:
|
|
||||||
(Note: You have to use 'easy_install -Z $PACKAGENAME')
|
|
||||||
|
|
||||||
python install-requirements.py
|
|
||||||
|
|
||||||
|
|
||||||
3. Install pywin32 from binary installer:
|
|
||||||
http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win32-py2.7.exe/download
|
|
||||||
|
|
||||||
Pywin32 is used to update the version resource of the prebuild openslides.exe.
|
|
||||||
It is not strictly required but at least for published releases it is highly advisable.
|
|
||||||
|
|
||||||
|
|
||||||
4. Install wxPython from binary installer:
|
|
||||||
http://sourceforge.net/projects/wxpython/files/wxPython/2.8.12.1/wxPython2.8-win32-unicode-2.8.12.1-py27.exe/download
|
|
||||||
|
|
||||||
WxPython is required to build the OpenSlides GUI frontend.
|
|
||||||
|
|
||||||
|
|
||||||
5. Run in the main directory of the OpenSlides checkout:
|
|
||||||
|
|
||||||
python extras\win32-portable\prepare_portable.py
|
|
||||||
|
|
||||||
|
|
||||||
=> The portable OpenSlides distribution is created as a zip archive in
|
|
||||||
the 'dist' directory of OpenSlides checkout.
|
|
||||||
|
|
||||||
|
|
||||||
NOTE: Creating the portable Windows distribution of OpenSlides is not possible
|
|
||||||
if Python is installed in 64-bit(!) version.
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
f = open("../../requirements_production.txt")
|
|
||||||
reqs = f.read().split("\n")
|
|
||||||
|
|
||||||
for req in reqs:
|
|
||||||
# ignore comments or pip options
|
|
||||||
if req.startswith('--') or req.startswith('#'):
|
|
||||||
continue
|
|
||||||
# ignore blank lines
|
|
||||||
if len(req) > 0:
|
|
||||||
os.system('easy_install -Z -U "%s"' % req)
|
|
@ -1,51 +0,0 @@
|
|||||||
Python License (Python-2.0)
|
|
||||||
|
|
||||||
Python License, Version 2 (Python-2.0)
|
|
||||||
|
|
||||||
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
|
||||||
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
|
||||||
otherwise using this software ("Python") in source or binary form and
|
|
||||||
its associated documentation.
|
|
||||||
|
|
||||||
2. Subject to the terms and conditions of this License Agreement, PSF
|
|
||||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
|
||||||
license to reproduce, analyze, test, perform and/or display publicly,
|
|
||||||
prepare derivative works, distribute, and otherwise use Python
|
|
||||||
alone or in any derivative version, provided, however, that PSF's
|
|
||||||
License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
|
|
||||||
2001-2013 Python Software Foundation; All Rights Reserved" are retained in
|
|
||||||
Python alone or in any derivative version prepared by Licensee.
|
|
||||||
|
|
||||||
3. In the event Licensee prepares a derivative work that is based on
|
|
||||||
or incorporates Python or any part thereof, and wants to make
|
|
||||||
the derivative work available to others as provided herein, then
|
|
||||||
Licensee hereby agrees to include in any such work a brief summary of
|
|
||||||
the changes made to Python.
|
|
||||||
|
|
||||||
4. PSF is making Python available to Licensee on an "AS IS"
|
|
||||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
|
||||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
|
||||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
|
||||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
|
||||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
|
||||||
|
|
||||||
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
|
||||||
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
|
||||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
|
||||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
|
||||||
|
|
||||||
6. This License Agreement will automatically terminate upon a material
|
|
||||||
breach of its terms and conditions.
|
|
||||||
|
|
||||||
7. Nothing in this License Agreement shall be deemed to create any
|
|
||||||
relationship of agency, partnership, or joint venture between PSF and
|
|
||||||
Licensee. This License Agreement does not grant permission to use PSF
|
|
||||||
trademarks or trade name in a trademark sense to endorse or promote
|
|
||||||
products or services of Licensee, or any third party.
|
|
||||||
|
|
||||||
8. By copying, installing or otherwise using Python, Licensee
|
|
||||||
agrees to be bound by the terms and conditions of this License
|
|
||||||
Agreement.
|
|
@ -1,26 +0,0 @@
|
|||||||
Beautiful Soup is made available under the MIT license:
|
|
||||||
|
|
||||||
Copyright (c) 2004-2012 Leonard Richardson
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
||||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE, DAMMIT.
|
|
||||||
|
|
||||||
Beautiful Soup incorporates code from the html5lib library, which is
|
|
||||||
also made available under the MIT license.
|
|
@ -1,27 +0,0 @@
|
|||||||
Copyright (c) Django Software Foundation and individual contributors.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of Django nor the names of its contributors may be used
|
|
||||||
to endorse or promote products derived from this software without
|
|
||||||
specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,24 +0,0 @@
|
|||||||
Copyright (c) Shaun Sephton
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of Shaun Sephton nor the
|
|
||||||
names of its contributors may be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL SHAUN SEPHTON BE LIABLE FOR ANY
|
|
||||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,31 +0,0 @@
|
|||||||
Copyright (c) 2009-2013, Daniel Lindsley.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of Haystack nor the names of its contributors may be used
|
|
||||||
to endorse or promote products derived from this software without
|
|
||||||
specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Prior to April 17, 2009, this software was released under the MIT license.
|
|
@ -1,18 +0,0 @@
|
|||||||
Copyright (c) 2007, Jonathan Buchanan
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,20 +0,0 @@
|
|||||||
Copyright (c) 2006-2013 James Graham and other contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,20 +0,0 @@
|
|||||||
Copyright (c) 2012 Brad Jasper
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2012 Seth M. Morton
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2011-2015 OpenSlides Team
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
@ -1,29 +0,0 @@
|
|||||||
#####################################################################################
|
|
||||||
#
|
|
||||||
# Copyright (c) 2000-2010, ReportLab Inc.
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
# are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# * Redistributions of source code must retain the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
# * Neither the name of the company nor the names of its contributors may be
|
|
||||||
# used to endorse or promote products derived from this software without
|
|
||||||
# specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
||||||
# IN NO EVENT SHALL THE OFFICERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
||||||
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
||||||
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
# SUCH DAMAGE.
|
|
||||||
#
|
|
||||||
#####################################################################################
|
|
@ -1,18 +0,0 @@
|
|||||||
Copyright (c) 2010-2014 Benjamin Peterson
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,19 +0,0 @@
|
|||||||
Copyright (C) 2011 Serge S. Koval
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,4 +0,0 @@
|
|||||||
Tornado is one of `Facebook's open source technologies
|
|
||||||
<http://developers.facebook.com/opensource/>`_. It is available under
|
|
||||||
the `Apache License, Version 2.0
|
|
||||||
<http://www.apache.org/licenses/LICENSE-2.0.html>`_.
|
|
@ -1,26 +0,0 @@
|
|||||||
Copyright 2011 Matt Chaput. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY MATT CHAPUT ``AS IS'' AND ANY EXPRESS OR
|
|
||||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
EVENT SHALL MATT CHAPUT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
||||||
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
The views and conclusions contained in the software and documentation are
|
|
||||||
those of the authors and should not be interpreted as representing official
|
|
||||||
policies, either expressed or implied, of Matt Chaput.
|
|
@ -1,46 +0,0 @@
|
|||||||
The wxWindows Library Licence
|
|
||||||
|
|
||||||
Copyright (c) 1998 Julian Smart, Robert Roebling [, ...]
|
|
||||||
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies of this licence
|
|
||||||
document, but changing it is not allowed.
|
|
||||||
|
|
||||||
WXWINDOWS LIBRARY LICENCE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
|
|
||||||
MODIFICATION
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU Library General Public Licence as published by the Free
|
|
||||||
Software Foundation; either version 2 of the Licence, or (at your option) any
|
|
||||||
later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. See the GNU Library General Public Licence for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public Licence along
|
|
||||||
with this software, usually in a file named COPYING.LIB. If not, write to the
|
|
||||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
||||||
02111-1307 USA.
|
|
||||||
|
|
||||||
EXCEPTION NOTICE
|
|
||||||
|
|
||||||
1. As a special exception, the copyright holders of this library give permission
|
|
||||||
for additional uses of the text contained in this release of the library as
|
|
||||||
licenced under the wxWindows Library Licence, applying either version 3 of the
|
|
||||||
Licence, or (at your option) any later version of the Licence as published by
|
|
||||||
the copyright holders of version 3 of the Licence document.
|
|
||||||
|
|
||||||
2. The exception is that you may use, copy, link, modify and distribute under
|
|
||||||
the user's own terms, binary object code versions of works based on the Library.
|
|
||||||
|
|
||||||
3. If you copy code from files distributed under the terms of the GNU General
|
|
||||||
Public Licence or the GNU Library General Public Licence into a copy of this
|
|
||||||
library, as this licence permits, the exception does not apply to the code that
|
|
||||||
you add in this way. To avoid misleading anyone as to the status of such
|
|
||||||
modified files, you must delete this exception notice from such code and/or
|
|
||||||
adjust the licensing conditions notice accordingly.
|
|
||||||
|
|
||||||
4. If you write modifications of your own for this library, it is your choice
|
|
||||||
whether to permit this exception to apply to your modifications. If you do not
|
|
||||||
wish that, you must delete the exception notice from such code and/or adjust the
|
|
||||||
licensing conditions notice accordingly.
|
|
@ -1,212 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define _WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.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 =
|
|
||||||
"import openslides_gui.gui;"
|
|
||||||
"openslides_gui.gui.main()";
|
|
||||||
|
|
||||||
/* determine the path to the executable
|
|
||||||
* NOTE: Py_GetFullProgramPath() can't be used because
|
|
||||||
* this would trigger pythons search-path initialization
|
|
||||||
* But we need this to initialize PYTHONHOME before this happens
|
|
||||||
*/
|
|
||||||
static char *
|
|
||||||
_get_module_name()
|
|
||||||
{
|
|
||||||
size_t size = 1;
|
|
||||||
char *name = NULL;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* a path > 40k would be insane, it is more likely something
|
|
||||||
* else has gone very wrong on the system
|
|
||||||
*/
|
|
||||||
for (i = 0;i < 10; i++)
|
|
||||||
{
|
|
||||||
DWORD res;
|
|
||||||
char *n;
|
|
||||||
|
|
||||||
n = realloc(name, size);
|
|
||||||
if (!n)
|
|
||||||
{
|
|
||||||
free(name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
name = n;
|
|
||||||
|
|
||||||
res = GetModuleFileNameA(NULL, name, size);
|
|
||||||
if (res != 0 && res < size)
|
|
||||||
{
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
else if (res == size)
|
|
||||||
{
|
|
||||||
/* NOTE: Don't check GetLastError() == ERROR_INSUFFICIENT_BUFFER
|
|
||||||
* here, it isn't set consistently across all platforms
|
|
||||||
*/
|
|
||||||
|
|
||||||
size += 4096;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DWORD err = GetLastError();
|
|
||||||
fprintf(stderr, "WARNING: GetModuleFileName() failed "
|
|
||||||
"(res = %d, err = %d)", res, err);
|
|
||||||
free(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
|
|
||||||
_run()
|
|
||||||
{
|
|
||||||
if (py_run_simple_string_flags(run_openslides_code, NULL) != 0)
|
|
||||||
_fatal_error("Failed to execute openslides");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int WINAPI
|
|
||||||
WinMain(HINSTANCE inst, HINSTANCE prev_inst, LPSTR cmdline, int show)
|
|
||||||
{
|
|
||||||
int returncode;
|
|
||||||
int run_py_main = __argc > 1;
|
|
||||||
char *py_home, *sep = NULL;
|
|
||||||
|
|
||||||
py_home = _get_module_name();
|
|
||||||
if (!py_home)
|
|
||||||
_fatal_error("Could not determine portable root directory");
|
|
||||||
|
|
||||||
sep = strrchr(py_home, '\\');
|
|
||||||
/* should always be the true */
|
|
||||||
if (sep)
|
|
||||||
*sep = '\0';
|
|
||||||
|
|
||||||
_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)
|
|
||||||
{
|
|
||||||
/* we where given extra arguments, behave like python.exe */
|
|
||||||
returncode = py_main(__argc, __argv);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* no arguments given => start openslides gui */
|
|
||||||
py_initialize();
|
|
||||||
py_sys_set_argv_ex(__argc, __argv, 0);
|
|
||||||
|
|
||||||
returncode = _run();
|
|
||||||
py_finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(py_home);
|
|
||||||
|
|
||||||
return returncode;
|
|
||||||
}
|
|
Binary file not shown.
@ -1,542 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import errno
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
import zlib
|
|
||||||
zlib.Z_DEFAULT_COMPRESSION = zlib.Z_BEST_COMPRESSION
|
|
||||||
import zipfile
|
|
||||||
|
|
||||||
import distutils.ccompiler
|
|
||||||
import distutils.sysconfig
|
|
||||||
|
|
||||||
import pkg_resources
|
|
||||||
|
|
||||||
import wx
|
|
||||||
|
|
||||||
sys.path.insert(0, os.getcwd())
|
|
||||||
sys.path.insert(1, os.path.join(os.getcwd(), "extras"))
|
|
||||||
import openslides
|
|
||||||
import openslides_gui
|
|
||||||
|
|
||||||
COMMON_EXCLUDE = [
|
|
||||||
r".pyc$",
|
|
||||||
r".pyo$",
|
|
||||||
r".po$",
|
|
||||||
r".egg-info",
|
|
||||||
r"\blocale/(?!de/|en/|fr/)[^/]+/"
|
|
||||||
]
|
|
||||||
|
|
||||||
LIBEXCLUDE = [
|
|
||||||
r"^site-packages/",
|
|
||||||
r"^test/",
|
|
||||||
r"^curses/",
|
|
||||||
r"^idlelib/",
|
|
||||||
r"^lib2to3/",
|
|
||||||
r"^lib-tk/",
|
|
||||||
r"^msilib/",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
SITE_PACKAGES = {
|
|
||||||
"backports.ssl_match_hostname": {
|
|
||||||
"copy": ["backports"],
|
|
||||||
},
|
|
||||||
"beautifulsoup4": {
|
|
||||||
"copy": ["bs4"],
|
|
||||||
},
|
|
||||||
"html5lib": {
|
|
||||||
"copy": ["html5lib"],
|
|
||||||
},
|
|
||||||
"django": {
|
|
||||||
"copy": ["django"],
|
|
||||||
"exclude": [
|
|
||||||
r"^django/contrib/admindocs/",
|
|
||||||
r"^django/contrib/comments/",
|
|
||||||
r"^django/contrib/databrowse/",
|
|
||||||
r"^django/contrib/flatpages/",
|
|
||||||
r"^django/contrib/formtools/",
|
|
||||||
r"^django/contrib/gis/",
|
|
||||||
r"^django/contrib/localflavor/",
|
|
||||||
r"^django/contrib/markup/",
|
|
||||||
r"^django/contrib/redirects/",
|
|
||||||
r"^django/contrib/sitemaps/",
|
|
||||||
r"^django/contrib/syndication/",
|
|
||||||
r"^django/contrib/webdesign/",
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"django_ckeditor_updated": {
|
|
||||||
"copy": ["ckeditor"],
|
|
||||||
},
|
|
||||||
"django-haystack": {
|
|
||||||
"copy": ["haystack"],
|
|
||||||
},
|
|
||||||
"jsonfield": {
|
|
||||||
"copy": ["jsonfield"],
|
|
||||||
},
|
|
||||||
"reportlab": {
|
|
||||||
"copy": [
|
|
||||||
"reportlab",
|
|
||||||
"_renderPM.pyd",
|
|
||||||
"_rl_accel.pyd",
|
|
||||||
"pyHnj.pyd",
|
|
||||||
"sgmlop.pyd",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"roman": {
|
|
||||||
"copy": ["roman.py"],
|
|
||||||
},
|
|
||||||
"setuptools": {
|
|
||||||
"copy": [
|
|
||||||
"setuptools",
|
|
||||||
"easy_install.py",
|
|
||||||
"pkg_resources.py"
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"six": {
|
|
||||||
"copy": ["six.py"],
|
|
||||||
},
|
|
||||||
"sockjs-tornado": {
|
|
||||||
"copy": ["sockjs"],
|
|
||||||
},
|
|
||||||
"tornado": {
|
|
||||||
"copy": ["tornado"],
|
|
||||||
},
|
|
||||||
"natsort": {
|
|
||||||
"copy": ["natsort"],
|
|
||||||
},
|
|
||||||
"whoosh": {
|
|
||||||
"copy": ["whoosh"],
|
|
||||||
},
|
|
||||||
"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 = [
|
|
||||||
"unicodedata.pyd",
|
|
||||||
"sqlite3.dll",
|
|
||||||
"_sqlite3.pyd",
|
|
||||||
"_socket.pyd",
|
|
||||||
"select.pyd",
|
|
||||||
"_ctypes.pyd",
|
|
||||||
"_ssl.pyd",
|
|
||||||
"_multiprocessing.pyd",
|
|
||||||
"pyexpat.pyd",
|
|
||||||
]
|
|
||||||
|
|
||||||
MSVCR_PUBLIC_KEY = "1fc8b3b9a1e18e3b"
|
|
||||||
MSVCR_VERSION = "9.0.21022.8"
|
|
||||||
MSVCR_NAME = "Microsoft.VC90.CRT"
|
|
||||||
|
|
||||||
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-2015\\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):
|
|
||||||
expr = "|".join("(?:{0})".format(x) for x in patterns)
|
|
||||||
return re.compile(expr)
|
|
||||||
|
|
||||||
|
|
||||||
def relpath(base, path, addslash=False):
|
|
||||||
b = os.path.normpath(os.path.abspath(base))
|
|
||||||
p = os.path.normpath(os.path.abspath(path))
|
|
||||||
if p == b:
|
|
||||||
p = "."
|
|
||||||
if addslash:
|
|
||||||
p += "/"
|
|
||||||
return p
|
|
||||||
|
|
||||||
b += os.sep
|
|
||||||
if not p.startswith(b):
|
|
||||||
raise ValueError("{0!r} is not relative to {1!r}".format(path, base))
|
|
||||||
p = p[len(b):].replace(os.sep, "/")
|
|
||||||
if addslash:
|
|
||||||
p += "/"
|
|
||||||
|
|
||||||
return p
|
|
||||||
|
|
||||||
|
|
||||||
def filter_excluded_dirs(exclude_pattern, basedir, dirpath, dnames):
|
|
||||||
i, l = 0, len(dnames)
|
|
||||||
while i < l:
|
|
||||||
rp = relpath(basedir, os.path.join(dirpath, dnames[i]), True)
|
|
||||||
if exclude_pattern.search(rp):
|
|
||||||
del dnames[i]
|
|
||||||
l -= 1
|
|
||||||
else:
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
|
|
||||||
def copy_dir_exclude(exclude, basedir, srcdir, destdir):
|
|
||||||
for dp, dnames, fnames in os.walk(srcdir):
|
|
||||||
filter_excluded_dirs(exclude, basedir, dp, dnames)
|
|
||||||
|
|
||||||
rp = relpath(basedir, dp)
|
|
||||||
target_dir = os.path.join(destdir, rp)
|
|
||||||
if not os.path.exists(target_dir):
|
|
||||||
os.makedirs(target_dir)
|
|
||||||
|
|
||||||
for fn in fnames:
|
|
||||||
fp = os.path.join(dp, fn)
|
|
||||||
rp = relpath(basedir, fp)
|
|
||||||
if exclude.search(rp):
|
|
||||||
continue
|
|
||||||
|
|
||||||
shutil.copyfile(fp, os.path.join(destdir, rp))
|
|
||||||
|
|
||||||
|
|
||||||
def collect_lib(libdir, odir):
|
|
||||||
exclude = compile_re_list(COMMON_EXCLUDE + LIBEXCLUDE)
|
|
||||||
copy_dir_exclude(exclude, libdir, libdir, os.path.join(odir, "Lib"))
|
|
||||||
|
|
||||||
|
|
||||||
def get_pkg_exclude(name, extra=()):
|
|
||||||
exclude = COMMON_EXCLUDE[:]
|
|
||||||
exclude.extend(SITE_PACKAGES.get(name, {}).get("exclude", []))
|
|
||||||
exclude.extend(extra)
|
|
||||||
return compile_re_list(exclude)
|
|
||||||
|
|
||||||
|
|
||||||
def copy_package(name, info, odir):
|
|
||||||
copy_things = info.get("copy", [])
|
|
||||||
if not copy_things:
|
|
||||||
return
|
|
||||||
|
|
||||||
dist = pkg_resources.get_distribution(name)
|
|
||||||
exclude = get_pkg_exclude(name)
|
|
||||||
|
|
||||||
site_dir = dist.location
|
|
||||||
for thing in copy_things:
|
|
||||||
fp = os.path.join(site_dir, thing)
|
|
||||||
if not os.path.isdir(fp):
|
|
||||||
rp = relpath(site_dir, fp)
|
|
||||||
ofp = os.path.join(odir, rp)
|
|
||||||
shutil.copyfile(fp, ofp)
|
|
||||||
else:
|
|
||||||
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):
|
|
||||||
if not os.path.exists(odir):
|
|
||||||
os.makedirs(odir)
|
|
||||||
|
|
||||||
for name, info in SITE_PACKAGES.iteritems():
|
|
||||||
copy_package(name, info, odir)
|
|
||||||
|
|
||||||
assert "wx" in SITE_PACKAGES
|
|
||||||
copy_wx(odir)
|
|
||||||
|
|
||||||
|
|
||||||
def compile_openslides_launcher():
|
|
||||||
try:
|
|
||||||
cc = distutils.ccompiler.new_compiler()
|
|
||||||
if not cc.initialized:
|
|
||||||
cc.initialize()
|
|
||||||
except distutils.errors.DistutilsError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
cc.add_include_dir(distutils.sysconfig.get_python_inc())
|
|
||||||
cc.define_macro("_CRT_SECURE_NO_WARNINGS")
|
|
||||||
|
|
||||||
gui_data_dir = os.path.dirname(openslides_gui.__file__)
|
|
||||||
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", "/nodefaultlib:python27.lib"],
|
|
||||||
libraries=["user32"]
|
|
||||||
)
|
|
||||||
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-2015",
|
|
||||||
"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):
|
|
||||||
dll_src = os.path.join(sys.exec_prefix, "DLLs")
|
|
||||||
dll_dest = os.path.join(odir, "DLLs")
|
|
||||||
if not os.path.exists(dll_dest):
|
|
||||||
os.makedirs(dll_dest)
|
|
||||||
|
|
||||||
for dll_name in PY_DLLS:
|
|
||||||
src = os.path.join(dll_src, dll_name)
|
|
||||||
dest = os.path.join(dll_dest, dll_name)
|
|
||||||
shutil.copyfile(src, dest)
|
|
||||||
|
|
||||||
pydllname = "python{0}{1}.dll".format(*sys.version_info[:2])
|
|
||||||
src = os.path.join(os.environ["WINDIR"], "System32", pydllname)
|
|
||||||
dest = os.path.join(dll_dest, pydllname)
|
|
||||||
shutil.copyfile(src, dest)
|
|
||||||
|
|
||||||
|
|
||||||
def copy_msvcr(odir):
|
|
||||||
candidates = glob.glob("{0}/x86_*{1}_{2}*".format(
|
|
||||||
os.path.join(os.environ["WINDIR"], "winsxs"),
|
|
||||||
MSVCR_NAME, MSVCR_PUBLIC_KEY))
|
|
||||||
|
|
||||||
msvcr_local_name = None
|
|
||||||
msvcr_dll_dir = None
|
|
||||||
for dp in candidates:
|
|
||||||
bn = os.path.basename(dp)
|
|
||||||
if MSVCR_VERSION in bn:
|
|
||||||
msvcr_local_name = bn
|
|
||||||
msvcr_dll_dir = dp
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
sys.stderr.write(
|
|
||||||
"Warning could not determine msvcr runtime location\n"
|
|
||||||
"Private asssembly for VC runtime must be added manually\n")
|
|
||||||
return
|
|
||||||
|
|
||||||
msvcr_dest_dir = os.path.join(odir, MSVCR_NAME)
|
|
||||||
if not os.path.exists(msvcr_dest_dir):
|
|
||||||
os.makedirs(msvcr_dest_dir)
|
|
||||||
|
|
||||||
for fn in os.listdir(msvcr_dll_dir):
|
|
||||||
src = os.path.join(msvcr_dll_dir, fn)
|
|
||||||
dest = os.path.join(msvcr_dest_dir, fn)
|
|
||||||
shutil.copyfile(src, dest)
|
|
||||||
|
|
||||||
src = os.path.join(
|
|
||||||
os.environ["WINDIR"], "winsxs", "Manifests",
|
|
||||||
"{0}.manifest".format(msvcr_local_name))
|
|
||||||
dest = os.path.join(msvcr_dest_dir, "{0}.manifest".format(MSVCR_NAME))
|
|
||||||
shutil.copyfile(src, dest)
|
|
||||||
|
|
||||||
|
|
||||||
def write_package_info_content(outfile):
|
|
||||||
"""
|
|
||||||
Writes a list of all included packages into outfile.
|
|
||||||
"""
|
|
||||||
text = ['Included Packages\n', 17 * '=' + '\n', '\n']
|
|
||||||
for pkg in sorted(SITE_PACKAGES):
|
|
||||||
if pkg == "wx":
|
|
||||||
# wxpython comes from an installer and has no distribution
|
|
||||||
# --> handle it separately
|
|
||||||
text.append("wxpython-{0}\n".format(wx.__version__))
|
|
||||||
else:
|
|
||||||
dist = pkg_resources.get_distribution(pkg)
|
|
||||||
text.append("{0}-{1}\n".format(dist.project_name, dist.version))
|
|
||||||
with open(outfile, "w") as f:
|
|
||||||
f.writelines(text)
|
|
||||||
|
|
||||||
|
|
||||||
def write_metadatafile(infile, outfile):
|
|
||||||
"""
|
|
||||||
Writes content from metadata files like README, AUTHORS and LICENSE into
|
|
||||||
outfile.
|
|
||||||
"""
|
|
||||||
with open(infile, "rU") as f:
|
|
||||||
text = [l for l in f]
|
|
||||||
with open(outfile, "w") as f:
|
|
||||||
f.writelines(text)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
prefix = os.path.dirname(sys.executable)
|
|
||||||
libdir = os.path.join(prefix, "Lib")
|
|
||||||
sitedir = os.path.join(libdir, "site-packages")
|
|
||||||
odir = "dist/openslides-{0}-portable".format(openslides.get_version())
|
|
||||||
|
|
||||||
try:
|
|
||||||
shutil.rmtree(odir)
|
|
||||||
except OSError as e:
|
|
||||||
if e.errno != errno.ENOENT:
|
|
||||||
raise
|
|
||||||
|
|
||||||
os.makedirs(odir)
|
|
||||||
out_site_packages = os.path.join(odir, "Lib", "site-packages")
|
|
||||||
|
|
||||||
collect_lib(libdir, odir)
|
|
||||||
collect_site_packages(sitedir, out_site_packages)
|
|
||||||
|
|
||||||
exclude = get_pkg_exclude("openslides")
|
|
||||||
copy_dir_exclude(exclude, ".", "openslides", out_site_packages)
|
|
||||||
|
|
||||||
if not compile_openslides_launcher():
|
|
||||||
sys.stdout.write("Using prebuild openslides.exe\n")
|
|
||||||
openslides_launcher_update_version_resource()
|
|
||||||
|
|
||||||
shutil.copyfile(
|
|
||||||
"extras/win32-portable/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_msvcr(odir)
|
|
||||||
|
|
||||||
# Info on included packages
|
|
||||||
shutil.copytree(
|
|
||||||
"extras/win32-portable/licenses",
|
|
||||||
os.path.join(odir, "packages-info"))
|
|
||||||
write_package_info_content(os.path.join(odir, 'packages-info', 'PACKAGES.txt'))
|
|
||||||
|
|
||||||
# Create plugins directory with README.txt
|
|
||||||
plugindir = os.path.join(odir, "openslides", "plugins")
|
|
||||||
os.makedirs(plugindir)
|
|
||||||
readmetext = ["Please copy your plugin directory into this directory.\n", "\n",
|
|
||||||
"For more information about OpenSlides plugins see:\n",
|
|
||||||
"https://github.com/OpenSlides/OpenSlides/wiki/De%3APlugins\n"]
|
|
||||||
with open(os.path.join(plugindir, 'README.txt'), "w") as readme:
|
|
||||||
readme.writelines(readmetext)
|
|
||||||
|
|
||||||
# AUTHORS, LICENSE, README
|
|
||||||
write_metadatafile('AUTHORS', os.path.join(odir, 'AUTHORS.txt'))
|
|
||||||
write_metadatafile('LICENSE', os.path.join(odir, 'LICENSE.txt'))
|
|
||||||
write_metadatafile('README.rst', os.path.join(odir, 'README.txt'))
|
|
||||||
|
|
||||||
zip_fp = os.path.join(
|
|
||||||
"dist", "openslides-{0}-portable.zip".format(
|
|
||||||
openslides.get_version()))
|
|
||||||
|
|
||||||
|
|
||||||
with zipfile.ZipFile(zip_fp, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
||||||
for dp, dnames, fnames in os.walk(odir):
|
|
||||||
for fn in fnames:
|
|
||||||
fp = os.path.join(dp, fn)
|
|
||||||
rp = relpath(odir, fp)
|
|
||||||
zf.write(fp, rp)
|
|
||||||
|
|
||||||
print("Successfully build {0}".format(zip_fp))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
Loading…
Reference in New Issue
Block a user