diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7a98f73 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,37 @@ +# To build the image: +# docker build --tag vasl-templates . +# Add "--build-arg ENABLE_TESTS=1" to allow the test suite to be run against a container. +# +# To run a container: +# docker run --rm -it --name vasl-templates \ +# -p 5010:5010 \ +# -v .../vasl-6.4.3.vmod:/data/vasl.vmod \ +# vasl-templates + +FROM python:alpine3.6 + +# NOTE: pillow needs zlib and jpeg, lxml needs libxslt, we need build-base for gcc, etc. +RUN apk add --no-cache build-base zlib-dev jpeg-dev libxslt-dev +ENV LIBRARY_PATH=/lib:/usr/lib + +WORKDIR /app + +ARG ENABLE_TESTS + +# install the Python requirements +COPY requirements.txt requirements-dev.txt ./ +RUN pip install -r requirements.txt ; \ + if [ "$ENABLE_TESTS" ]; then pip install -r requirements-dev.txt ; fi + +# install the application +ADD vasl_templates vasl_templates +COPY setup.py LICENSE.txt ./ +RUN pip install -e . + +# copy the config files +COPY docker/config/* vasl_templates/webapp/config/ +RUN if [ "$ENABLE_TESTS" ]; then echo "ENABLE_REMOTE_TEST_CONTROL = 1" >>vasl_templates/webapp/config/debug.cfg ; fi + +EXPOSE 5010 +COPY docker/run.sh . +CMD ./run.sh diff --git a/docker/config/debug.cfg b/docker/config/debug.cfg new file mode 100644 index 0000000..bbc32f9 --- /dev/null +++ b/docker/config/debug.cfg @@ -0,0 +1,3 @@ +[Debug] + +TEST_VASL_MODS = /test-data/vasl-vmods diff --git a/docker/config/logging.yaml b/docker/config/logging.yaml new file mode 100644 index 0000000..a0f8cc5 --- /dev/null +++ b/docker/config/logging.yaml @@ -0,0 +1,31 @@ +version: 1 + +formatters: + standard: + format: "%(asctime)s.%(msecs)03d | %(message)s" + datefmt: "%H:%M:%S" + +handlers: + console: + class: "logging.StreamHandler" + formatter: "standard" + stream: "ext://sys.stdout" + file: + class: "logging.FileHandler" + formatter: "standard" + filename: "/tmp/vasl-templates.log" + mode: "w" + +loggers: + werkzeug: + level: "WARNING" + handlers: [ "console" ] + vasl_mod: + level: "WARNING" + handlers: [ "console", "file" ] + update_vsav: + level: "WARNING" + handlers: [ "console", "file" ] + control_tests: + level: "DEBUG" + handlers: [ "console", "file" ] diff --git a/docker/config/site.cfg b/docker/config/site.cfg new file mode 100644 index 0000000..27869ca --- /dev/null +++ b/docker/config/site.cfg @@ -0,0 +1,5 @@ +[Site Config] + +FLASK_HOST = 0.0.0.0 + +VASL_MOD = /data/vasl.vmod diff --git a/docker/run.sh b/docker/run.sh new file mode 100755 index 0000000..81e55ff --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +python /app/vasl_templates/webapp/run_server.py diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..1edd884 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,6 @@ +pytest==3.6.0 +tabulate==0.8.2 +lxml==4.2.4 +pylint==1.9.2 +pytest-pylint==0.9.0 +pyinstaller==3.4 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..0eb6260 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +flask==1.0.2 +pyyaml==3.13 +pillow==5.3.0 +selenium==3.12.0 +click==6.7 diff --git a/setup.py b/setup.py index 8e04a84..a6dd432 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,30 @@ """ Setup the package. Install this module in development mode to get the tests to work: - pip install --editable .[dev] + pip install --editable .[dev] """ +import os from setuptools import setup, find_packages +# --------------------------------------------------------------------- + +# NOTE: We break the requirements out into separate files so that we can load them early +# into a Docker image, where they can be cached, instead of having to re-install them every time. + +def parse_requirements( fname ): + """Parse a requirements file.""" + lines = [] + fname = os.path.join( os.path.split(__file__)[0], fname ) + for line in open(fname,"r"): + line = line.strip() + if line == "" or line.startswith("#"): + continue + lines.append( line ) + return lines + +# --------------------------------------------------------------------- + setup( name = "vasl_templates", version = "0.6", # nb: also update constants.py @@ -13,27 +32,15 @@ setup( license = "AGPLv3", url = "https://github.com/pacman-ghost/vasl-templates", packages = find_packages(), - install_requires = [ - # Python 3.6.5 - "flask==1.0.2", - # NOTE: PyQt5 requirements: https://doc.qt.io/qt-5/linux.html - # Linux: mesa-libGL-devel ; @"C Development Tools and Libraries" - # nb: WebEngine seems to be broken in 5.10.1 :-/ - "PyQT5==5.10.0", - "pyyaml==3.13", - "pillow==5.3.0", - "selenium==3.12.0", - "click==6.7", - ], + install_requires = parse_requirements( "requirements.txt" ), extras_require = { - "dev": [ - "pytest==3.6.0", - "tabulate==0.8.2", - "lxml==4.2.4", - "pylint==1.9.2", - "pytest-pylint==0.9.0", - "PyInstaller==3.4", + "gui": [ + # NOTE: PyQt5 requirements: https://doc.qt.io/qt-5/linux.html + # Linux: mesa-libGL-devel ; @"C Development Tools and Libraries" + # nb: WebEngine seems to be broken in 5.10.1 :-/ + "PyQT5==5.10.0", ], + "dev": parse_requirements( "requirements-dev.txt" ), }, include_package_data = True, data_files = [ diff --git a/vasl_templates/webapp/static/help/index.html b/vasl_templates/webapp/static/help/index.html index e360d4a..3fb1441 100644 --- a/vasl_templates/webapp/static/help/index.html +++ b/vasl_templates/webapp/static/help/index.html @@ -54,7 +54,7 @@

While not essential, it is strongly recommended that you set up a virtual environment first. Then, install the requirements:

-pip install . +pip install .[gui]

Running the desktop application

@@ -316,6 +316,28 @@ export JSHINT_RHINO=~/bin/jshint-2.6.3/dist/jshint-rhino.js Note that both of these are run as part of a normal pytest run. +

Docker

+ +

The webapp can be run using Docker. To create an image, cd to the project root and build the image e.g. +

+docker build --tag vasl-templates . +
+NOTE: To allow the test suite to be run against the container, add --build-arg ENABLE_TESTS=1 to the command. + +

Then run the container: +

+docker run --rm -it --name vasl-templates \ + -p 5010:5010 \ + -v /home/pacman-ghost/vasl/vasl-6.4.3.vmod:/data/vasl.vmod \ + vasl-templates +
+NOTE: The "Update VASL scenario" feature is currently not working in a container.. + +

Note that if you have SElinux enabled, it may prevent the container from accessing the VASL .vmod file, in which case, you can allow access like this: +

+chcon -Rt svirt_sandbox_file_t /home/pacman-ghost/vasl/vasl-6.4.3.vmod +
+

Creating a pre-compiled package

It is possible to compile the desktop application down to a single binary. This is typically done for the benefit of Windows users, but also works for other platforms. From the root directory of the repo: diff --git a/vasl_templates/webapp/static/vassal.js b/vasl_templates/webapp/static/vassal.js index 2acfb15..253d167 100644 --- a/vasl_templates/webapp/static/vassal.js +++ b/vasl_templates/webapp/static/vassal.js @@ -83,7 +83,7 @@ function do_update_vsav( vsav_data, fname ) $( "#vassal-shim-error .message" ).html( data.error ) ; var log = "" ; if ( data.stdout && data.stderr ) - log = "=== STDOUT ===" + data.stdout + "\n=== STDERR ===\n" + data.stderr ; + log = "=== STDOUT ===\n" + data.stdout + "\n=== STDERR ===\n" + data.stderr ; else if ( data.stdout ) log = data.stdout ; else if ( data.stderr ) diff --git a/vasl_templates/webapp/vassal.py b/vasl_templates/webapp/vassal.py index 5bac5e1..3702110 100644 --- a/vasl_templates/webapp/vassal.py +++ b/vasl_templates/webapp/vassal.py @@ -246,11 +246,13 @@ class VassalShim: raise SimpleError( "Can't find VASL module: {}".format( self.vasl_mod ) ) # locate the VASSAL shim JAR - if IS_FROZEN: - meipass = sys._MEIPASS #pylint: disable=no-member,protected-access - self.shim_jar = os.path.join( meipass, "vasl_templates/webapp/vassal-shim.jar" ) - else: - self.shim_jar = os.path.join( os.path.split(__file__)[0], "../../vassal-shim/release/vassal-shim.jar" ) + self.shim_jar = app.config.get( "VASSAL_SHIM" ) + if not self.shim_jar: + if IS_FROZEN: + meipass = sys._MEIPASS #pylint: disable=no-member,protected-access + self.shim_jar = os.path.join( meipass, "vasl_templates/webapp/vassal-shim.jar" ) + else: + self.shim_jar = os.path.join( os.path.split(__file__)[0], "../../vassal-shim/release/vassal-shim.jar" ) if not os.path.isfile( self.shim_jar ): raise SimpleError( "Can't find the VASSAL shim JAR." )