Merge pull request #1744 from emanuelschuetze/readme

Updated Readme.
This commit is contained in:
Norman Jäckel 2015-12-07 21:54:08 +01:00
commit 1415461141
29 changed files with 54 additions and 1989 deletions

View File

@ -10,6 +10,8 @@ Version 2.0.0 (unreleased)
Agenda:
- 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.
Assignments:
- Renamed app from assignment to assignments.
@ -25,6 +27,7 @@ Users:
- Used authentication frontend via AngularJS.
Other:
- New OpenSlides logo.
- New design for web interface.
- Added multiple countdown support.
- Changed supported Python version to >= 3.3.
- Used Django 1.7 as lowest requirement.
@ -53,6 +56,8 @@ Other:
- Used setup.cfg for development tools.
- Removed code for Windows portable version with GUI. Used new repository for
this.
Translations:
- Added DE and FR translations.
Version 1.7 (2015-02-16)

View File

@ -3,6 +3,7 @@ include CHANGELOG
include LICENSE
include README.rst
include requirements_production.txt
include bower.json
recursive-include openslides *.*
recursive-exclude openslides *.pyc
recursive-exclude openslides *.swp

View File

@ -131,15 +131,14 @@ To start OpenSlides simply run on command line::
openslides
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:
`admin`) after first login!
(Username: `admin`, Password: `admin`) will be created. Please change the password
after first login!
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 listen on the local ip address on port 80 or port 8000 if you do not
have admin permissions. That means that the server will be available to
everyone on your local network (at least for commonly used network
configurations).
try to listen on the local ip address on port 8000. That means that the server
will be available to everyone on your local network (at least for commonly used
network configurations).
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
@ -242,22 +241,23 @@ VI. Used software
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
* `Beautiful Soup <http://www.crummy.com/software/BeautifulSoup/>`_,
License: MIT
* `Bootstrap <http://getbootstrap.com/2.3.2/>`_, License: Apache
License v2.0
* `Django <https://www.djangoproject.com>`_, License: BSD
* `Django CKEditor <https://github.com/riklaunim/django-ckeditor>`_, 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/>`_,
License: BSD
@ -270,24 +270,46 @@ OpenSlides uses the following projects or parts of them:
* `sockjs-tornado <https://github.com/mrjoes/sockjs-tornado>`_,
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
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)
* `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
========================

View File

@ -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

View File

@ -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()

View File

@ -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.

View File

@ -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)

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.
#
#####################################################################################

View File

@ -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.

View File

@ -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.

View File

@ -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>`_.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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()