Attempt to make single binary build with pyinstaller

This commit is contained in:
Dmytro Aleksandrov
2016-08-15 23:19:14 +03:00
committed by Dmytro Aleksandrov
parent 5b9411b9da
commit e86cf9a722
6 changed files with 65 additions and 15 deletions
+1
View File
@@ -6,6 +6,7 @@ data/*
.coverage .coverage
.eggs/ .eggs/
build/ build/
dist/
coverage.xml coverage.xml
junit.xml junit.xml
pgpass pgpass
Executable
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
set -e
pip install --ignore-installed -r requirements-bin.txt
pyinstaller --clean --onefile patroni.spec
+29
View File
@@ -0,0 +1,29 @@
# -*- mode: python -*-
block_cipher = None
a = Analysis(['patroni/__main__.py', 'patroni/dcs/consul.py', 'patroni/dcs/etcd.py', 'patroni/dcs/exhibitor.py', 'patroni/dcs/zookeeper.py'],
pathex=[],
binaries=None,
datas=None,
hiddenimports=['patroni.dcs.consul', 'patroni.dcs.etcd', 'patroni.dcs.exhibitor', 'patroni.dcs.zookeeper'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='patroni',
debug=False,
strip=False,
upx=True,
console=True)
+1 -1
View File
@@ -64,7 +64,7 @@ class Config(object):
print('Usage: {0} config.yml'.format(sys.argv[0])) print('Usage: {0} config.yml'.format(sys.argv[0]))
print('\tPatroni may also read the configuration from the {0} environment variable'. print('\tPatroni may also read the configuration from the {0} environment variable'.
format(self.PATRONI_CONFIG_VARIABLE)) format(self.PATRONI_CONFIG_VARIABLE))
exit(1) sys.exit(1)
self.__effective_configuration = self._build_effective_configuration({}, self._local_configuration) self.__effective_configuration = self._build_effective_configuration({}, self._local_configuration)
self._data_dir = self.__effective_configuration['postgresql']['data_dir'] self._data_dir = self.__effective_configuration['postgresql']['data_dir']
+27 -14
View File
@@ -6,6 +6,7 @@ import json
import os import os
import pkgutil import pkgutil
import six import six
import sys
from collections import namedtuple from collections import namedtuple
from patroni.exceptions import PatroniException from patroni.exceptions import PatroniException
@@ -31,22 +32,34 @@ def parse_connection_string(value):
return conn_url, api_url return conn_url, api_url
def dcs_modules():
"""Get names of DCS modules, depending on execution environment. If being packaged with PyInstaller,
modules aren't discoverable dynamically by scanning source directory. Thus, when running in bundle,
a predefined list of dcs modules is returned. See:
https://pyinstaller.readthedocs.io/en/stable/runtime-information.html#run-time-information"""
if getattr(sys, 'frozen', False):
return ['consul', 'etcd', 'zookeeper', 'exhibitor']
else:
module_names = (name for _, name, is_pkg in pkgutil.iter_modules([os.path.dirname(__file__)]) if not is_pkg)
return module_names
def get_dcs(config): def get_dcs(config):
available_implementations = set() available_implementations = set()
for _, module_name, is_pkg in pkgutil.iter_modules([os.path.dirname(__file__)]): for module_name in dcs_modules():
if not is_pkg: module = importlib.import_module(__package__ + '.' + module_name)
module = importlib.import_module(__package__ + '.' + module_name) for name in filter(lambda name: not name.startswith('__'), dir(module)): # iterate through module content
for name in filter(lambda name: not name.startswith('__'), dir(module)): # iterate through module content value = getattr(module, name)
value = getattr(module, name) name = name.lower()
name = name.lower() # try to find implementation of AbstractDCS interface, class name must match with module_name
# try to find implementation of AbstractDCS interface, class name must match with module_name if inspect.isclass(value) and issubclass(value, AbstractDCS) and name == module_name:
if inspect.isclass(value) and issubclass(value, AbstractDCS) and name == module_name: available_implementations.add(name)
available_implementations.add(name) if name in config: # which has configuration section in the config file
if name in config: # which has configuration section in the config file # propagate some parameters
# propagate some parameters config[name].update({p: config[p] for p in ('namespace', 'name', 'scope',
config[name].update({p: config[p] for p in ('namespace', 'name', 'scope', 'loop_wait', 'ttl', 'retry_timeout') if p in config})
'loop_wait', 'ttl', 'retry_timeout') if p in config}) return value(config[name])
return value(config[name])
raise PatroniException("""Can not find suitable configuration of distributed configuration store raise PatroniException("""Can not find suitable configuration of distributed configuration store
Available implementations: """ + ', '.join(available_implementations)) Available implementations: """ + ', '.join(available_implementations))
+2
View File
@@ -0,0 +1,2 @@
setuptools==19.2
pyinstaller