From d4de2118eb3b1be51f46ce62d3e17426181d6c09 Mon Sep 17 00:00:00 2001 From: Nicholas Chammas Date: Sat, 30 Jan 2016 22:19:00 -0500 Subject: [PATCH] add PyInstaller hooks --- .gitignore | 1 + .travis.yml | 7 +++++++ flintrock/core.py | 9 ++++++++- flintrock/flintrock.py | 7 ++++++- flintrock/services.py | 8 +++++++- generate-standalone-package.py | 30 +++++++++++++++++++++++++++++ hook-flintrock.py | 5 +++++ requirements/maintainer.pip | 1 + requirements/user.pip | 5 ++++- standalone.py | 11 +++++++++++ tests/test_pyinstaller_packaging.py | 20 +++++++++++++++++++ 11 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 generate-standalone-package.py create mode 100644 hook-flintrock.py create mode 100644 standalone.py create mode 100644 tests/test_pyinstaller_packaging.py diff --git a/.gitignore b/.gitignore index 4d4f91fc..46ce2889 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ venv/ flintrock-logo/ .hypothesis/ *.prf +.DS_Store # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/.travis.yml b/.travis.yml index 0b320326..9dbf26d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,13 @@ python: - "3.5" install: - "pip install -r requirements/developer.pip" + - "curl -L -o pandoc.deb https://github.com/jgm/pandoc/releases/download/1.16.0.2/pandoc-1.16.0.2-1-amd64.deb && sudo dpkg -i pandoc.deb" script: - "py.test ./tests/test_static.py" - "py.test ./tests/test_flintrock.py" + - "py.test ./tests/test_pyinstaller_packaging.py" +addons: + artifacts: + paths: + - "dist/*.zip" + s3_region: "us-east-1" diff --git a/flintrock/core.py b/flintrock/core.py index 08b01c5a..fc6868b5 100644 --- a/flintrock/core.py +++ b/flintrock/core.py @@ -5,13 +5,20 @@ import os import posixpath import shlex +import sys import time # Flintrock modules from .exceptions import SSHError, NodeError from .ssh import get_ssh_client, ssh_check_output, ssh -THIS_DIR = os.path.dirname(os.path.realpath(__file__)) +FROZEN = getattr(sys, 'frozen', False) + +if FROZEN: + THIS_DIR = sys._MEIPASS +else: + THIS_DIR = os.path.dirname(os.path.realpath(__file__)) + SCRIPTS_DIR = os.path.join(THIS_DIR, 'scripts') diff --git a/flintrock/flintrock.py b/flintrock/flintrock.py index 0729a8b7..e5144e75 100644 --- a/flintrock/flintrock.py +++ b/flintrock/flintrock.py @@ -21,7 +21,12 @@ from flintrock import __version__ from .services import HDFS, Spark # TODO: Remove this dependency. -THIS_DIR = os.path.dirname(os.path.realpath(__file__)) +FROZEN = getattr(sys, 'frozen', False) + +if FROZEN: + THIS_DIR = sys._MEIPASS +else: + THIS_DIR = os.path.dirname(os.path.realpath(__file__)) def format_message(*, message: str, indent: int=4, wrap: int=70): diff --git a/flintrock/services.py b/flintrock/services.py index 6e7db60b..42ffe2e7 100644 --- a/flintrock/services.py +++ b/flintrock/services.py @@ -12,7 +12,13 @@ from .core import FlintrockCluster from .ssh import ssh_check_output -THIS_DIR = os.path.dirname(os.path.realpath(__file__)) +FROZEN = getattr(sys, 'frozen', False) + +if FROZEN: + THIS_DIR = sys._MEIPASS +else: + THIS_DIR = os.path.dirname(os.path.realpath(__file__)) + SCRIPTS_DIR = os.path.join(THIS_DIR, 'scripts') diff --git a/generate-standalone-package.py b/generate-standalone-package.py new file mode 100644 index 00000000..690e209d --- /dev/null +++ b/generate-standalone-package.py @@ -0,0 +1,30 @@ +import os +import platform +import shutil +import subprocess + +from flintrock import __version__ as flintrock_version + +THIS_DIR = os.path.dirname(os.path.realpath(__file__)) + +if __name__ == '__main__': + operating_system = platform.system() + machine_type = platform.machine() + + subprocess.run([ + 'pyinstaller', + '--noconfirm', + '--name', 'flintrock', + '--additional-hooks-dir', '.', + 'standalone.py'], + check=True) + + shutil.make_archive( + base_name=os.path.join( + THIS_DIR, 'dist', + 'flintrock-{v}-{os}-{m}'.format( + v=flintrock_version, + os=operating_system, + m=machine_type)), + format='zip', + root_dir=os.path.join(THIS_DIR, 'dist', 'flintrock')) diff --git a/hook-flintrock.py b/hook-flintrock.py new file mode 100644 index 00000000..5478cf84 --- /dev/null +++ b/hook-flintrock.py @@ -0,0 +1,5 @@ +datas=[ + ('flintrock/scripts', './scripts'), + ('flintrock/templates', './templates'), + ('flintrock/config.yaml.template', './'), +] diff --git a/requirements/maintainer.pip b/requirements/maintainer.pip index 0e23a1d9..700071c7 100644 --- a/requirements/maintainer.pip +++ b/requirements/maintainer.pip @@ -2,3 +2,4 @@ wheel >= 0.26.0 twine >= 1.6.4 pypandoc >= 1.1.2 +PyInstaller >= 3.1 diff --git a/requirements/user.pip b/requirements/user.pip index 925ca1c9..1faf84bf 100644 --- a/requirements/user.pip +++ b/requirements/user.pip @@ -1,7 +1,10 @@ # NOTE: Run pip from Flintrock's root directory, not from the directory containing # this file. + +# Due to: https://github.com/pyinstaller/pyinstaller/issues/1781 +setuptools >= 19.0, <= 19.2 + # NOTE: The `-e .` syntax lets us reuse the requirements already specified under # `install_requires` in setup.py. # See: https://caremad.io/2013/07/setup-vs-requirement/ -setuptools >= 18.8.1 -e . diff --git a/standalone.py b/standalone.py new file mode 100644 index 00000000..f53bc6b0 --- /dev/null +++ b/standalone.py @@ -0,0 +1,11 @@ +""" +A standalone script for use by PyInstaller. + +Users should not be running this script. +""" + +import sys +from flintrock.flintrock import main + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tests/test_pyinstaller_packaging.py b/tests/test_pyinstaller_packaging.py new file mode 100644 index 00000000..859a97c1 --- /dev/null +++ b/tests/test_pyinstaller_packaging.py @@ -0,0 +1,20 @@ +import glob +import subprocess +import sys + +# External modules +import pytest + + +@pytest.mark.skipif(sys.version_info < (3, 5), reason="Python 3.5+ is required") +def test_pyinstaller_packaging(): + subprocess.run( + ['pip', 'install', '-r', 'requirements/maintainer.pip'], + check=True) + subprocess.run( + ['python', 'generate-standalone-package.py'], + check=True) + subprocess.run( + ['./dist/flintrock/flintrock'], + check=True) + assert glob.glob('./dist/*.zip')