Skip to content
Snippets Groups Projects
Commit 80facd74 authored by Ingo Meyer's avatar Ingo Meyer
Browse files

Merge branch 'feature-miniconda_support' into develop

parents 9862d676 2663f090
No related branches found
No related tags found
No related merge requests found
......@@ -13,6 +13,7 @@ import shutil
import subprocess
from jinja2 import Template
from .util import command
from .util.binary_replace import binary_replace
__author__ = 'Ingo Heimbach'
......@@ -23,6 +24,32 @@ PY_PRE_STARTUP_CONDA_SETUP = '''
#!/bin/bash
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
cd ${SCRIPT_DIR}
function fix_prefix {
local SAVED_PREFIX
local REAL_PREFIX
SAVED_PREFIX=$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <../Resources/application_path_prefix)
REAL_PREFIX=$(cd ../.. && pwd | tr -d '\\n')
if [ "${SAVED_PREFIX}" != "${REAL_PREFIX}" ]; then
if [ -w "../Resources/application_path_prefix" ]; then
>&2 echo "INFO: Replacing application prefix ${SAVED_PREFIX} with ${REAL_PREFIX} ..."
while read -r MATCHING_FILE ; do
if file --mime "${MATCHING_FILE}" | grep -q "charset=binary"; then
../Resources/binary_replace.py "${MATCHING_FILE}" "${SAVED_PREFIX}" "${REAL_PREFIX}"
else
sed -i '' "s!${SAVED_PREFIX}!${REAL_PREFIX}!g" "${MATCHING_FILE}"
fi
done < <(grep -rl --exclude='*.pyc' "${SAVED_PREFIX}" ../Resources/conda_env)
echo "${REAL_PREFIX}">../Resources/application_path_prefix
else
>&2 echo "WARNING: The app has no write permissions to change location prefixes!"
fi
fi
}
fix_prefix
source ../Resources/conda_env/bin/activate ../Resources/conda_env
python __startup__.py
'''.strip()
......@@ -80,6 +107,7 @@ _create_conda_env = False
_requirements_file = None
_conda_channels = None
_extension_makefile = None
_conda_gr_included = False
class CondaError(Exception):
......@@ -112,7 +140,12 @@ def get_command_line_arguments():
def parse_command_line_arguments(args):
global _create_conda_env, _requirements_file, _conda_channels, _extension_makefile
global _create_conda_env, _requirements_file, _conda_channels, _extension_makefile, _conda_gr_included
def is_gr_in_conda_requirements(requirements_file):
with open(requirements_file, 'r') as f:
found_gr = any((line.startswith('gr=') for line in f))
return found_gr
checked_args = {}
if args.conda_req_file is not None:
......@@ -123,6 +156,7 @@ def parse_command_line_arguments(args):
_conda_channels = args.conda_channels
if args.extension_makefile is not None:
_extension_makefile = args.extension_makefile
_conda_gr_included = is_gr_in_conda_requirements(_requirements_file)
return checked_args
......@@ -180,7 +214,7 @@ def setup_startup(app_path, executable_path, app_executable_path, executable_roo
def make_conda_portable(env_path):
CONDA_BIN_PATH = 'bin/conda'
CONDA_ACTIVATE_PATH = 'bin/activate'
CONDA_MISSING_PACKAGES = ('conda', )
CONDA_MISSING_PACKAGES = ('conda', 'enum', 'ruamel_yaml', 'requests')
def fix_links_to_system_files():
for root_path, dirnames, filenames in os.walk(env_path):
......@@ -200,19 +234,32 @@ def setup_startup(app_path, executable_path, app_executable_path, executable_roo
shutil.copy(real_filepath, os.path.join(root_path, os.path.basename(link_filepath)))
def fix_activate_script():
SEARCHED_LINE_START = '_THIS_DIR='
INSERT_LINE = 'export PATH=${_THIS_DIR}:${PATH}'
DELETE_LINE_PART = 'checkenv'
DELETE_LINE_COUNT = 5
REPLACE_LINE_PART = '_NEW_PART='
REPLACE_LINE_INSERT = '_NEW_PART=$_CONDA_DIR'
full_conda_activate_path = '{env_path}/{conda_activate_path}'.format(env_path=env_path,
conda_activate_path=CONDA_ACTIVATE_PATH)
found_line = False
found_line_to_delete = False
found_line_to_replace = False
skip_line_num = 0
new_lines = []
with open(full_conda_activate_path, 'r') as f:
for line in f:
if skip_line_num > 0:
skip_line_num -= 1
continue
if not found_line_to_delete:
if DELETE_LINE_PART in line:
found_line_to_delete = True
skip_line_num = DELETE_LINE_COUNT - 1
continue
if not found_line_to_replace:
if REPLACE_LINE_PART in line:
found_line_to_replace = True
new_lines.append('{}\n'.format(REPLACE_LINE_INSERT))
continue
new_lines.append(line)
if not found_line:
if line.startswith(SEARCHED_LINE_START):
new_lines.append(INSERT_LINE)
found_line = True
with open(full_conda_activate_path, 'w') as f:
f.writelines(new_lines)
......@@ -250,10 +297,44 @@ def setup_startup(app_path, executable_path, app_executable_path, executable_roo
shutil.copytree('{system_anaconda_packages_root_path}/{package}'.format(system_anaconda_packages_root_path=full_anaconda_python_packages_path, package=package),
'{condaenv_packages_root_path}/{package}'.format(condaenv_packages_root_path=full_condaenv_python_packages_path, package=package))
def fix_application_path_prefix():
app_name = os.path.splitext(os.path.basename(app_path))[0]
target_application_path_prefix = '/Applications/{app_name}.app'.format(app_name=app_name)
current_application_path_prefix = os.path.abspath('{env_path}/../../..'.format(env_path=env_path))
matching_files = subprocess.check_output(['grep', '-rl', "--exclude='*.pyc'", current_application_path_prefix, env_path]).strip().split('\n')
text_files = []
binary_files = []
for matching_file in matching_files:
if 'charset=binary' in subprocess.check_output(['file', '--mime', matching_file]):
binary_files.append(matching_file)
else:
text_files.append(matching_file)
for text_file in text_files:
sed_pattern = 's!{current_prefix}!{target_prefix}!g'.format(current_prefix=current_application_path_prefix,
target_prefix=target_application_path_prefix)
subprocess.check_call(['sed', '-i', '', sed_pattern, text_file])
for binary_file in binary_files:
binary_replace(binary_file, current_application_path_prefix, target_application_path_prefix)
with open('{env_path}/../application_path_prefix'.format(env_path=env_path), 'w') as f:
f.write(target_application_path_prefix)
fix_links_to_system_files()
fix_activate_script()
fix_conda_shebang()
copy_missing_conda_packages()
fix_application_path_prefix()
def fix_conda_gr(env_path):
def create_missing_library_links():
library_directory = '{env_path}/lib'.format(env_path=env_path)
site_package_directory = '{env_path}/lib/python2.7/site-packages'.format(env_path=env_path)
for rel_lib_path in ('gr/libGR.so', 'gr3/libGR3.so'):
os.symlink(os.path.relpath('{site_packages}/{lib}'.format(site_packages=site_package_directory,
lib=rel_lib_path),
library_directory),
'{lib}/{name}'.format(lib=library_directory, name=os.path.basename(rel_lib_path)))
create_missing_library_links()
def build_extension_modules(env_path):
def get_makefile_path():
......@@ -285,11 +366,15 @@ def setup_startup(app_path, executable_path, app_executable_path, executable_roo
if _create_conda_env:
env_path = create_conda_env()
make_conda_portable(env_path)
if _conda_gr_included:
fix_conda_gr(env_path)
if _extension_makefile is not None:
build_extension_modules(env_path)
env_startup_script = PY_PRE_STARTUP_CONDA_SETUP
with open('{macos}/{startup}'.format(macos=macos_path, startup=_ENV_STARTUP_SCRIPT_NAME), 'w') as f:
f.writelines(env_startup_script.encode('utf-8'))
shutil.copy('{base_dir}/util/binary_replace.py'.format(base_dir=os.path.dirname(__file__)),
'{resources}/binary_replace.py'.format(resources=resources_path))
new_executable_path = _ENV_STARTUP_SCRIPT_NAME
else:
new_executable_path = _PY_STARTUP_SCRIPT_NAME
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import re
import sys
def binary_replace(file_path, old, new):
def replace(match):
old_text = match.group()
new_text = old_text.replace(old, new)
if len(new) > len(old):
new_text = new_text[:len(old_text)]
padding = 0
else:
padding = len(old_text) - len(new_text)
return new_text + b'\0' * padding
if isinstance(old, unicode):
old = old.encode('utf-8')
if isinstance(new, unicode):
new = new.encode('utf-8')
with open(file_path, 'rb') as f:
data = f.read()
unpatched_data_len = len(data)
fill_len = max(0, len(new) - len(old))
pattern = re.compile(re.escape(old) + b'([^\0]*?)\0' + ('.{%d}' % fill_len))
data = pattern.sub(replace, data)
assert(unpatched_data_len == len(data))
with open(file_path, 'wb') as f:
f.write(data)
def main():
if len(sys.argv) < 4:
print('Usage: {name} file_path old_string new_string'.format(name=sys.argv[0]))
print(' Opens a binary file and replaces every occurance of old_string with new_string.')
sys.exit(0)
file_path, old_string, new_string = sys.argv[1:4]
binary_replace(file_path, old_string, new_string)
if __name__ == '__main__':
main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment