From 0a5d24d64b5f637038a15b01bbe1b3d4bf4108f2 Mon Sep 17 00:00:00 2001 From: Paixu Aabuizia Date: Sun, 10 Jan 2016 15:40:35 +0100 Subject: [pkg] reproducible windows installer for bitmask_client provide a environment that allows automated builds of windows installers - prepare dockerized environment with wine, python, openssl, zlib and mingw to build windows binaries from python sourcecode - prepare dockerized environment with nullsoft installer to build installers from binaries - configure pyinstaller to build binaries - configure nsis to build distributable executables for bitmask - configure make all in pkg/windows that results in installers - add documentation - ico conversion from data/images - avoid polluting / in docker image - install dirspec and copy to wine env - remove obsolete comments - fix python path - figure out that pip install leap.a and pyinstalling a leap.b does not work - so the build script fixes that - rename dependencies to pyinstaller and move nsis code to installer - build openvpn, export the binaries for further processing - correct openvpn dependencies, fetch tap installer compatible with openvpn just built - install tap-driver with nsis - pyinstaller-build: fix mixed mkdir / show errors if there are some - installer-build: prepare rw-copy, do not expose nsh files - add openvpn_leap.exe to install directory so it gets picked up by nsis - use setup.py to install bitmask to site-packages to have a version - separate build directories for granular make - copy all openvpn dlls to installer - die to signal failure to parent makefile - cache installDependencies for quick turn-arround times - share openssl version between openvpn and pysqlcipher/other pip builds - collect files during prepare for installer - default to eip:false, mail:true - configuration in pyinstaller-build.sh - win64 tap drivers need special care getting removed from 32bit nsis - correct registry key that identifies if we installed TAP - extract version from git-tree, expose to wine python - create nsh with version for build installer - allow clean/dirty version with patches - cleanup / indent / remove comments - die when pysqlchipher patch failed - add psutil in mingw compatible version --- pkg/pyinst/bitmask.spec | 30 ++- pkg/pyinst/qt.conf | 2 + pkg/windows/Makefile | 25 ++ pkg/windows/README.rst | 144 +++++++++++ pkg/windows/TODO | 15 ++ pkg/windows/bitmask.nis | 2 + pkg/windows/bitmask.nsh | 115 +++++++++ pkg/windows/bitmask_client_product.nsh | 8 + pkg/windows/bitmask_client_registry_install.nsh | 17 ++ pkg/windows/docker-compose.yml | 42 +++ pkg/windows/installer-build.sh | 119 +++++++++ pkg/windows/installer/Dockerfile | 17 ++ pkg/windows/openvpn-build.sh | 62 +++++ pkg/windows/openvpn/Dockerfile | 17 ++ pkg/windows/pyinstaller-build.sh | 287 +++++++++++++++++++++ pkg/windows/pyinstaller/Dockerfile | 105 ++++++++ pkg/windows/pyinstaller/pysqlcipher_setup.py.patch | 14 + pkg/windows/pyinstaller/zlib-mingw-shared.patch | 10 + 18 files changed, 1024 insertions(+), 7 deletions(-) create mode 100644 pkg/pyinst/qt.conf create mode 100644 pkg/windows/Makefile create mode 100644 pkg/windows/README.rst create mode 100644 pkg/windows/TODO create mode 100644 pkg/windows/bitmask.nis create mode 100644 pkg/windows/bitmask.nsh create mode 100644 pkg/windows/bitmask_client_product.nsh create mode 100644 pkg/windows/bitmask_client_registry_install.nsh create mode 100644 pkg/windows/docker-compose.yml create mode 100755 pkg/windows/installer-build.sh create mode 100644 pkg/windows/installer/Dockerfile create mode 100755 pkg/windows/openvpn-build.sh create mode 100644 pkg/windows/openvpn/Dockerfile create mode 100755 pkg/windows/pyinstaller-build.sh create mode 100644 pkg/windows/pyinstaller/Dockerfile create mode 100644 pkg/windows/pyinstaller/pysqlcipher_setup.py.patch create mode 100644 pkg/windows/pyinstaller/zlib-mingw-shared.patch diff --git a/pkg/pyinst/bitmask.spec b/pkg/pyinst/bitmask.spec index a76ccb17..cd207816 100644 --- a/pkg/pyinst/bitmask.spec +++ b/pkg/pyinst/bitmask.spec @@ -3,17 +3,32 @@ import sys block_cipher = None - -a = Analysis([os.path.join('bitmask.py')], +a = Analysis(['bitmask.py'], hiddenimports=[ - 'zope.interface', 'zope.proxy', - 'PySide.QtCore', 'PySide.QtGui', 'PySide.QtWebKit'], + 'zope.interface', 'zope.proxy', + 'PySide.QtCore', 'PySide.QtGui', + 'pysqlcipher', 'service_identity', + 'leap.common', 'leap.bitmask' + ], + binaries=None, + datas=None, hookspath=None, runtime_hooks=None, excludes=None, + win_no_prefer_redirects=None, + win_private_assemblies=None, cipher=block_cipher) -pyz = PYZ(a.pure, +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +# Binary files you need to include in the form of: +# (, , '') + +# Data files you want to include, in the form of: +# (, , '') +data = [ + ('qt.conf', 'qt.conf', 'DATA') +] exe = EXE(pyz, a.scripts, exclude_binaries=True, @@ -21,12 +36,13 @@ exe = EXE(pyz, debug=False, strip=False, upx=True, - console=False ) + console=False, + icon='../../data/images/mask-icon.ico') coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, - strip=False, + strip=None, upx=True, name='bitmask') if sys.platform.startswith("darwin"): diff --git a/pkg/pyinst/qt.conf b/pkg/pyinst/qt.conf new file mode 100644 index 00000000..7eecd342 --- /dev/null +++ b/pkg/pyinst/qt.conf @@ -0,0 +1,2 @@ +[Paths] +Plugins=qt4_plugins \ No newline at end of file diff --git a/pkg/windows/Makefile b/pkg/windows/Makefile new file mode 100644 index 00000000..5d19353e --- /dev/null +++ b/pkg/windows/Makefile @@ -0,0 +1,25 @@ +.PHONY: all pkg installer openvpn pyinstaller +all: + docker-compose build + $(MAKE) pkg + +pkg: + $(MAKE) openvpn + $(MAKE) pyinstaller + $(MAKE) installer + +pyinstaller: + docker-compose run --rm pyinstaller + +openvpn: + docker-compose run --rm openvpn + +installer: + docker-compose run --rm installer + +clean: + docker rmi windows_pyinstaller + docker rmi windows_openvpn + docker rmi windows_installer + rm -rf ../../dist/*.exe + rm -rf ../../build/* \ No newline at end of file diff --git a/pkg/windows/README.rst b/pkg/windows/README.rst new file mode 100644 index 00000000..0bdfb1d1 --- /dev/null +++ b/pkg/windows/README.rst @@ -0,0 +1,144 @@ +Environment setup in debian:jessie +================================== + +basically you need this to setup your environment: + +# apt-get install mingw-w64 +# apt-get install wine +# apt-get install nsis + +this is a incomplete list of dependencies, review the pyinstaller/Dockerfile +to get a understanding of what needs to be setup in order to have a +environment that builds the installer + +Requirements +============ + +docker-compose + +Building the package +==================== + +make pkg + + +Reproducible builds +=================== + +please run the binary and installer builds on a clean machine eg +using docker or any virtual environment that can easily be prepared +by a third party to verify that the binaries are actually what the +sourcecode suggests. + +to use reproducible build you need to install docker which then installs +a clean debian:jessie to install nsis or the mingw environment + + +Installer +========= + +NSIS was choosen because it provided a out of the box toolchain to build +installers for the windows platform with minimal dependencies. The downside +of nsis is that it does not produce msi binaries + +to build the binary dependencies run: + +``` +docker-compose run --rm openvpn +docker-compose run --rm pyinstaller +``` + +the produced binaries will be stored in ${ROOT}/build + +to build the installer run: + +``` +docker-compose run --rm installer +``` + +the produced installer will be stored in ${ROOT}/dist + + +Pyinstaller +=========== + +Pyinstaller is a docker image based on debian:jessie with a cross-compile +toolchain (gcc) for building zlib and openssl in linux and wine (staging) +with installed python and mingw32 for pip/wheel compiling. +All pip installed dependencies are +part of the pyinstaller-build.sh script so they can be re-executed when the +dependencies of the project change. The image should be rebuild when openssl, +python or pyinstaller is updated: + +``` +docker-compose build pyinstaller +``` + +To debug or fine-tune the compile process it may be useful to setup the +following software on the development machine: + +``` +X :1 -listen tcp +DISPLAY=:1 xhost + +docker-compose run --rm pyinstaller /bin/bash +root@0fa19215321f:/# export DISPLAY=${YOUR_LOCAL_IP}:1 +root@0fa19215321f:/# wine cmd +Z:\>python +>>> +``` + +the configured volumes are: + +- the (read-only) sourcecode of the bitmask project in /var/src/bitmask +- the result of the builds in /var/build + +pyinstaller-build.sh +==================== + +Contains all steps to build the win32 executables. The project relies on +a read-write source tree which will pollute the development environment and +make it hard to reproduce 'clean' builds. therefore it expects that the source +is freshly checked out and not used to run in the host-environment. Otherwise +pyc and ui elements will mess up the binary in unpredictable ways. + +* copy the /var/src/bitmask sources to a read-write location (/var/build) +* execute ```make all``` in wine to build the qt ui and other resources +* execute ```pip install $dependencies``` to have all dependencies available +* execute ```pyinstaller``` in wine to compile the executable for +** bitmask (src/leap/bitmask/app.py) +* cleanup +** remove the read-write copy +** remove wine-dlls from the installer + +As the step 'install dependencies' may take long on slow internet connections +during development it is advised to recycle the container and share the +build/executables path with a windows-vm to test the result in short cycles +instead of make pkg, uninstall, install. + +``` +docker-compose run --rm --entrypoint=/bin/bash pyinstalle +root@0fa19215321f:/# cd /var/src/bitmask/pkg/windows +root@0fa19215321f:/var/src/bitmask/pkg/windows# ./pyinstaller-build.sh +root@0fa19215321f:/var/src/bitmask/pkg/windows# ./pyinstaller-build.sh +root@0fa19215321f:/var/src/bitmask/pkg/windows# ./pyinstaller-build.sh +.... +``` + +and test the result binary (accessible in bitmask/build in a separate vm. + +OpenVPN +======= + +OpenVPN is a straight forward cross compile image that builds the openvpn +sourcecode from the git-repository to a windows executable that can be +used by bitmask_root to launch eip. +It needs to be rebuild regulary as openssl gets a new version about every +month. PyInstaller uses the openssl that is compiled by this image + +Installer +========= + +Installer is a straight forward debian image with makensis installed. The +installer-build script lists the previously built files from pyinstaller and +openvpn to pass it as nsh file to makensis. bitmask.nis controls what will +be displayed to the user and how the components are installed and uninstalled \ No newline at end of file diff --git a/pkg/windows/TODO b/pkg/windows/TODO new file mode 100644 index 00000000..49c6bac1 --- /dev/null +++ b/pkg/windows/TODO @@ -0,0 +1,15 @@ +TODO +==== + +fix python-code (0.9.1) that fails on windows: +- fix the race condition for the backend/frontend startup. + spawning the backend takes time. with a introduced 15s timeout + it was possible to ensure the backend is up. It would be ideal + if the backend could signal the app to continue loading the frontend +- fix the ~/leap/events/zmq_certificates/public_keys/server.key +- fix logger (& remove hack in pyinstaller-build.sh:228) +- fix pysqlcipher (/LIB:,https get not working in setup.py, remove hack + in pyinstaller-build:164) +- merge bitmask_root from https://github.com/alirezamirzaeiyan/bitmask-root + +create similar infrastructure for osx dmg, preferably run on osx for compressed dmg \ No newline at end of file diff --git a/pkg/windows/bitmask.nis b/pkg/windows/bitmask.nis new file mode 100644 index 00000000..8705c058 --- /dev/null +++ b/pkg/windows/bitmask.nis @@ -0,0 +1,2 @@ +!define PKGNAME bitmask +!include .\bitmask.nsh \ No newline at end of file diff --git a/pkg/windows/bitmask.nsh b/pkg/windows/bitmask.nsh new file mode 100644 index 00000000..fe02f84e --- /dev/null +++ b/pkg/windows/bitmask.nsh @@ -0,0 +1,115 @@ +# pwd is a ro-mounted source-tree that had all dependencies build into +# package-name directories +!define PKGNAMEPATH ..\..\build\executables\${PKGNAME} +!include ${PKGNAMEPATH}_version.nsh +!include .\bitmask_client_product.nsh +!include ${PKGNAMEPATH}_install_files_size.nsh + +RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on) + +InstallDir "$PROGRAMFILES\${APPNAME}" + +LicenseData "..\..\LICENSE" +Name "${COMPANYNAME} - ${APPNAME}" +Icon "..\..\build\executables\mask-icon.ico" + +# /var/dist is a rw mounted volume +outFile "/var/dist/${PKGNAME}-${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}${VERSIONSUFFIX}.exe" +!include LogicLib.nsh + +# Just three pages - license agreement, install location, and installation +page license +page directory +Page instfiles + +!macro VerifyUserIsAdmin +UserInfo::GetAccountType +pop $0 +${If} $0 != "admin" ;Require admin rights on NT4+ + messageBox mb_iconstop "Administrator rights required!" + setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED + quit +${EndIf} +!macroend + +function .onInit + setShellVarContext all + !insertmacro VerifyUserIsAdmin +functionEnd + +section "TAP Virtual Ethernet Adapter" SecTAP + SetOverwrite on + SetOutPath "$TEMP" + File /oname=tap-windows.exe "..\..\build\executables\openvpn\tap-windows.exe" + + DetailPrint "Installing TAP (may need confirmation)..." + nsExec::ExecToLog '"$TEMP\tap-windows.exe" /S /SELECT_UTILITIES=1' + Pop $R0 # return value/error/timeout + + Delete "$TEMP\tap-windows.exe" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "tap" "installed" +sectionEnd + +section "install" + setOutPath $INSTDIR + + !include ${PKGNAMEPATH}_install_files.nsh + + # Uninstaller - See function un.onInit and section "uninstall" for configuration + writeUninstaller "$INSTDIR\uninstall.exe" + + # Start Menu + createDirectory "$SMPROGRAMS\${COMPANYNAME}" + createShortCut "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" "$INSTDIR\bitmask.exe" "" "$INSTDIR\bitmask.exe" + + !include bitmask_client_registry_install.nsh +sectionEnd + +# Uninstaller + +function un.onInit + SetShellVarContext all + !insertmacro VerifyUserIsAdmin +functionEnd + +section "uninstall" + + delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" + # Try to remove the Start Menu folder - this will only happen if it is empty + rmDir "$SMPROGRAMS\${COMPANYNAME}" + + # Remove files + !include ${PKGNAMEPATH}_uninstall_files.nsh + + # Remove TAP Drivers + ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "tap" + ${If} $R0 == "installed" + DetailPrint "Uninstalling TAP as we installed it..." + ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\TAP-Windows" "UninstallString" + ${If} $R0 != "" + DetailPrint "Uninstalling TAP..." + nsExec::ExecToLog '"$R0" /S' + Pop $R0 # return value/error/timeout + ${Else} + # on x64 windows the uninstall location needs to be accessed using WOW + SetRegView 64 + ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\TAP-Windows" "UninstallString" + SetRegView 32 + ${If} $R0 != "" + DetailPrint "Uninstalling TAP 64..." + nsExec::ExecToLog '"$R0" /S' + Pop $R0 # return value/error/timeout + ${EndIf} + ${EndIf} + DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "tap" + ${EndIf} + + # Always delete uninstaller as the last action + delete $INSTDIR\uninstall.exe + + # Try to remove the install directory - this will only happen if it is empty + rmDir $INSTDIR + + # Remove uninstaller information from the registry + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" +sectionEnd \ No newline at end of file diff --git a/pkg/windows/bitmask_client_product.nsh b/pkg/windows/bitmask_client_product.nsh new file mode 100644 index 00000000..64f59ac7 --- /dev/null +++ b/pkg/windows/bitmask_client_product.nsh @@ -0,0 +1,8 @@ +!define APPNAME "Bitmask" +!define COMPANYNAME "leap.se" +!define DESCRIPTION "With Bitmask VPN, all your traffic is securely routed through your provider before it is decrypted and sent on to the open internet." +# These will be displayed by the "Click here for support information" link in "Add/Remove Programs" +# It is possible to use "mailto:" links in here to open the email client +!define HELPURL "https://bitmask.net/en/help" # "Support Information" link +!define UPDATEURL "https://bitmask.net/en/install" # "Product Updates" link +!define ABOUTURL "https://bitmask.net/" # "Publisher" link \ No newline at end of file diff --git a/pkg/windows/bitmask_client_registry_install.nsh b/pkg/windows/bitmask_client_registry_install.nsh new file mode 100644 index 00000000..5bf04045 --- /dev/null +++ b/pkg/windows/bitmask_client_registry_install.nsh @@ -0,0 +1,17 @@ +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayName" "${COMPANYNAME} - ${APPNAME} - ${DESCRIPTION}" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "InstallLocation" "$\"$INSTDIR$\"" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\bitmask.exe$\"" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "Publisher" "${COMPANYNAME}" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "HelpLink" "${HELPURL}" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLUpdateInfo" "$\"${UPDATEURL}$\"" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\"" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}${VERSIONSUFFIX}" +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMajor" ${VERSIONMAJOR} +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMinor" ${VERSIONMINOR} +# There is no option for modifying or repairing the install +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoModify" 1 +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoRepair" 1 +# Set the INSTALLSIZE constant (!defined at the top of this script) so Add/Remove Programs can accurately report the size +WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "EstimatedSize" ${INSTALLSIZE} \ No newline at end of file diff --git a/pkg/windows/docker-compose.yml b/pkg/windows/docker-compose.yml new file mode 100644 index 00000000..92b310c8 --- /dev/null +++ b/pkg/windows/docker-compose.yml @@ -0,0 +1,42 @@ +# mingw environment to build dependency binaries in a reproducible environment +# https://wiki.debian.org/ReproducibleBuilds +# service to build a windows executable using pyinstaller +# utilizes wine and pyinstaller-build.sh to produce +# build/executables/pyinstaller/bitmask/* +# usage: docker-compose run --rm pyinstaller +# non-zero exit code on failure +pyinstaller: + build: pyinstaller + volumes: +# bitmask sources + - ../../:/var/src/bitmask:ro +# produced binaries + - ../../build:/var/build +# service to build a windows-executable from openvpn sources +# uses the openvpn-build infrastructure to produce +# build/executables/openvpn/* +# produces the openvpn.exe and provides openssl that is to be +# used by pyinsaller +# usage: docker-compose run --rm openvpn +# non-zero exit code on failure +openvpn: + build: openvpn + volumes: +# bitmask sources + - ../../:/var/src/bitmask:ro +# produced binaries + - ../../build:/var/build +# service to compile a installer using nullsoft installer +# nsis environment to build installer (exe) that contains all required binaries +# for a clean, just installed windows machine +# utilizes the debian makensis and installer-build to produce +# dist/bitmask-VERSION.exe +# usage: docker-compose run --rm installer +# non-zero exit code on failure +installer: + build: installer + volumes: +# bitmask sources + - ../../:/var/src/bitmask:ro +# produced installers - configured in bitmask.nsh + - ../../dist:/var/dist diff --git a/pkg/windows/installer-build.sh b/pkg/windows/installer-build.sh new file mode 100755 index 00000000..cf664200 --- /dev/null +++ b/pkg/windows/installer-build.sh @@ -0,0 +1,119 @@ +#!/bin/bash + +# build installer +# =============== +# +# builds several installers from previously compiled binaries + +product=bitmask +# the location of the nsis installer nis files dictates the path of the files +relative_executable_path=../../build/executables +source_ro_path=/var/src/${product} +temporary_build_path=/var/tmp/installer + +setups=($(ls -1 ${source_ro_path}/pkg/windows | grep '.nis$' | sed 's|.nis$||')) + +# generate nsis file references for installer for single directory +# appends File and Remove to files that are later included by makensis +# separate files for install and uninstall statements +# +# directory_root: the tree root that is currently generated +# subdir: any directory in the tree +# setup_name: the name of the setup this nsh entries are generated for +function generateDirectoryNSISStatements() { + directory_root=$1 + subdir=$2 + setup_name=$3 + find ${subdir} -maxdepth 1 -type f -exec echo 'File "'${relative_executable_path}'/{}"' \;>> ${setup_name}_install_files.nsh + find ${subdir} -maxdepth 1 -type f -exec echo 'Delete "$INSTDIR/{}"' \; >> ${setup_name}_uninstall_files.nsh +} +# generate a tree of files into nsis installer definitions +# directory_root: the tree root that is currently generated +# setup_name: the name of the setup this nsh entries are generated for +function generateDirectoryNSISStatementsTree() { + directory_root=$1 + setup_name=$2 + subdirs=$(find ${directory_root} -type d | sort) + for subdir in ${subdirs[@]} + do + if [ "${directory_root}" != "${subdir}" ]; then + echo 'SetOutPath "$INSTDIR/'${subdir}'"' >> ${setup_name}_install_files.nsh + fi + generateDirectoryNSISStatements ${directory_root} ${subdir} ${setup_name} + done + # again to remove emptied directories on uninstall so reverse + subdirs=$(find ${directory_root} -type d | sort | tac) + for subdir in ${subdirs[@]} + do + if [ "${directory_root}" != "${subdir}" ]; then + echo 'RMDir "$INSTDIR/'${subdir}'"' >> ${setup_name}_uninstall_files.nsh + fi + done +} +# generate installer files for the available setups +# those files include install and uninstall statements and are +# modified (backslashes/source_path) to generate a sane target +# structure +function generateNSISStatements() { + pushd ${temporary_build_path}/build/executables + for setup in "${setups[@]}" + do + echo "setup:" ${setup} + echo "# auto generated by pkg/windows/installer-build.sh please do not modify" > ${setup}_install_files.nsh + echo "# auto generated by pkg/windows/installer-build.sh please do not modify" > ${setup}_uninstall_files.nsh + setup_source_path=${setup} + generateDirectoryNSISStatementsTree ${setup_source_path} ${setup} + # remove the setup_source_path from the nsh files + sed -i "s|INSTDIR/${setup_source_path}/|INSTDIR/|" ${setup}_install_files.nsh + sed -i "s|/${setup_source_path}/|/|" ${setup}_uninstall_files.nsh + # make backslashes + sed -i "s|/|\\\\|g" ${setup}_install_files.nsh ${setup}_uninstall_files.nsh + # make install size + installed_size=$(du -s --block-size=1000 ${setup} | awk '{print $1}') + echo "!define INSTALLSIZE ${installed_size}" > ${setup}_install_files_size.nsh + done + popd +} +# makensis to produce a installer.exe +# the result is placed in /var/dist +function buildInstaller() { + pushd ${temporary_build_path}/pkg/windows + for setup in ${setups[@]} + do + makensis ${setup}.nis || die 'build setup "'${setup}'" failed' + done + popd +} +# prepare build path +# copies files that have been produced by other containers +# merges the product so the nsis files are correct +function prepareBuildPath() { + mkdir -p ${temporary_build_path}/pkg/windows + mkdir -p ${temporary_build_path}/build + cp -r ${source_ro_path}/pkg/windows/* ${temporary_build_path}/pkg/windows + cp -r ${source_ro_path}/build/* ${temporary_build_path}/build + cp -r ${source_ro_path}/LICENSE ${temporary_build_path}/LICENSE + + test -d ${temporary_build_path}/build/executables/bitmask || die 'bitmask not available run docker-compose run --rm pyinstaller' + test -d ${temporary_build_path}/build/executables/openvpn || die 'openvpn not available run docker-compose run --rm openvpn' + pushd ${temporary_build_path}/build/executables + cp openvpn/bin/openvpn.exe bitmask + cp openvpn/bin/*.dll bitmask + popd +} +# remove build files to ensure subsequent builds +function cleanup() { + rm -r ${temporary_build_path} +} +# display failure message and emit non-zero exit code +function die() { + echo "die:" $@ + exit 1 +} +function main() { + prepareBuildPath + generateNSISStatements + buildInstaller + cleanup +} +main $@ \ No newline at end of file diff --git a/pkg/windows/installer/Dockerfile b/pkg/windows/installer/Dockerfile new file mode 100644 index 00000000..ae46acb6 --- /dev/null +++ b/pkg/windows/installer/Dockerfile @@ -0,0 +1,17 @@ +FROM debian:jessie +MAINTAINER paixu@0xn0.de +RUN apt-get update + +###### +# install packages required to build + +RUN apt-get -y install \ + nsis +WORKDIR /var/src/bitmask/pkg/windows + +###### +# set a specific user +# needs external tuning of the /var/dist rights! +# RUN useradd installer +# USER installer +ENTRYPOINT ["/var/src/bitmask/pkg/windows/installer-build.sh"] \ No newline at end of file diff --git a/pkg/windows/openvpn-build.sh b/pkg/windows/openvpn-build.sh new file mode 100755 index 00000000..3f470f55 --- /dev/null +++ b/pkg/windows/openvpn-build.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# render openvpn prepared for installer +# ================================================ +# +# requires +# - a linux host with mingw installed +# - a rw directory mounted to /var/build +# returns nonzero exit code when failed +# +# clone openvpn-build repository +# runs cross-compile build +# - downloads openvpn dependencies +# - compiles +# copy files to executables so they can be installed +# cleans up (remove read-write copy) + +# the location where the openvpn binaries are placed +absolute_executable_path=/var/build/executables +temporary_build_path=/var/build/openvpn + +# cleanup the temporary build path for subsequent executes +function cleanup() { + rm -r ${temporary_build_path} 2>/dev/null +} +# build openvpn source +function buildSource() { + pushd ${temporary_build_path}/openvpn-build/generic + CHOST=i686-w64-mingw32 \ + CBUILD=i686-pc-linux-gnu \ + ./build \ + || die 'build openvpn from source failed' + cp -r image/openvpn ${absolute_executable_path}/openvpn + popd +} +# fetch tap-windows.exe as defined in the openvpn vars +function fetchTapWindows() { + pushd ${temporary_build_path}/openvpn-build + source windows-nsis/build-complete.vars + wget ${TAP_WINDOWS_INSTALLER_URL} -O ${absolute_executable_path}/openvpn/tap-windows.exe || die 'tap-windows.exe could not be fetched' + popd +} +# prepare read-write copy +function prepareBuildPath() { + cleanup + mkdir -p ${temporary_build_path} + pushd ${temporary_build_path} + git clone https://github.com/OpenVPN/openvpn-build || die 'openvpn-build could not be cloned' + popd +} +# display failure message and emit non-zero exit code +function die() { + echo "die:" $@ + exit 1 +} +function main() { + prepareBuildPath + buildSource + fetchTapWindows + cleanup +} +main $@ \ No newline at end of file diff --git a/pkg/windows/openvpn/Dockerfile b/pkg/windows/openvpn/Dockerfile new file mode 100644 index 00000000..471685a1 --- /dev/null +++ b/pkg/windows/openvpn/Dockerfile @@ -0,0 +1,17 @@ +FROM debian:jessie +MAINTAINER paixu@0xn0.de + +###### +# install packages required to build +# https-transport: winehq deb +# winbind: pip install keyring (requirements.pip) needs this somehow +# git-core: clone rw copy of repo and build specific commit +# imagemagick: convert png to ico-files +RUN apt-get update && apt-get -y install \ + unzip bzip2 \ + curl wget \ + apt-transport-https \ + man2html \ + git-core \ + build-essential autoconf mingw-w64 +ENTRYPOINT ["/var/src/bitmask/pkg/windows/openvpn-build.sh"] \ No newline at end of file diff --git a/pkg/windows/pyinstaller-build.sh b/pkg/windows/pyinstaller-build.sh new file mode 100755 index 00000000..06db8d54 --- /dev/null +++ b/pkg/windows/pyinstaller-build.sh @@ -0,0 +1,287 @@ +#!/bin/bash + +# render dependencies into separate subdirectories +# ================================================ +# +# requires +# - a linux host with wine, wine with python and mingw installed +# - the sourcecode mounted to /var/src/ +# - a rw directory mounted to /var/build +# returns nonzero exit code when pyinstaller failed +# +# prepares a read-write copy of the sourcecode +# executes qt-uic and qt-rcc for gui dialogs +# installs dependencies from pkg/dependencies-windows.pip +# runs pyinstaller +# cleans up (remove wine-dlls, remove read-write copy) +# creates nsis install/uninstall scripts for the files for each package +# if $1 is set it is expected to be a branch/git-tag + +product=bitmask +# the location where the pyinstaller results are placed +absolute_executable_path=/var/build/executables +# the location of the nsis installer nis files dictates the path of the files +relative_executable_path=../../build/executables +source_ro_path=/var/src/${product} +temporary_build_path=/var/build/pyinstaller +git_tag=HEAD +version_prefix=leap.bitmask +git_version=unknown +# option that is changed when a dependency-cache is found +install_dependencies=true +# default options for components +with_eip=false +with_mail=true + +setups=($(ls -1 ${source_ro_path}/pkg/windows | grep '.nis$' | sed 's|.nis$||')) +# add mingw dlls that are build in other steps +function addMingwDlls() { + root=$1 + cp /usr/lib/gcc/i686-w64-mingw32/4.9-win32/libgcc_s_sjlj-1.dll ${root} + cp /root/.wine/drive_c/Python27/Lib/site-packages/zmq/libzmq.pyd ${root} + cp /root/.wine/drive_c/Python27/Lib/site-packages/zmq/libzmq.pyd ${root} + mkdir -p ${root}/pysqlcipher + cp /var/build/pyinstaller/pkg/pyinst/build/bitmask/pysqlcipher-2.6.4-py2.7-win32.egg/pysqlcipher/_sqlite.pyd ${root}/pysqlcipher + cp ~/.wine/drive_c/openssl/bin/*.dll ${root} +} +# cleanup the temporary build path for subsequent executes +function cleanup() { + rm -r ${temporary_build_path} 2>/dev/null +} +# create files that are not part of the repository but are needed +# in the windows environment: +# - license with \r\n +# - ico from png (multiple sizes for best results on high-res displays) +function createInstallablesDependencies() { + pushd ${temporary_build_path} > /dev/null + cat LICENSE | sed 's|\n|\r\n|g' > LICENSE.txt + convert data/images/mask-icon.png -filter Cubic -scale 256x256! data/images/mask-icon-256.png + convert data/images/mask-icon-256.png -define icon:auto-resize data/images/mask-icon.ico + # execute qt-uic / qt-rcc + wine mingw32-make all || die 'qt-uic / qt-rcc failed' + # get version using git (only available in host) + git_version=$(python setup.py version| grep 'Version is currently' | awk -F': ' '{print $2}') + # run setup.py in a path with the version contained so versioneer can + # find the information and put it into the egg + versioned_build_path=/var/tmp/${version_prefix}-${git_version} + mkdir -p ${versioned_build_path} + cp -r ${temporary_build_path}/* ${versioned_build_path} + # apply patches to the source that are required for working code + # should not be required in the future as it introduces possible + # hacks that are hard to debug + applyPatches ${versioned_build_path} + pushd ${versioned_build_path} > /dev/null + wine python setup.py update_files || die 'setup.py update_files failed' + wine python setup.py build || die 'setup.py build failed' + wine python setup.py install || die 'setup.py install failed' + popd + rm -rf ${versioned_build_path} + popd +} +# create installer version that may be used by installer-build.sh / makensis +# greps the version-parts from the previously extracted git_version and stores +# the result in a setup_version.nsh +# when the git_version does provide a suffix it is prefixed with a dash so the +# installer output needs no conditional for this +function createInstallerVersion() { + setup=$1 + # [0-9]*.[0-9]*.[0-9]*-[0-9]*_g[0-9a-f]*_dirty + VERSIONMAJOR=$(echo ${git_version} | sed 's|^\([0-9]*\)\..*$|\1|') + VERSIONMINOR=$(echo ${git_version} | sed 's|^[0-9]*\.\([0-9]*\).*$|\1|') + VERSIONBUILD=$(echo ${git_version} | sed 's|^[0-9]*\.[0-9]*\.\([0-9]*\).*$|\1|') + VERSIONSUFFIX=$(echo ${git_version} | sed 's|^[0-9]*\.[0-9]*\.[0-9]*-\(.*\)$|\1|') + echo "!define VERSIONMAJOR ${VERSIONMAJOR}" > ${absolute_executable_path}/${setup}_version.nsh + echo "!define VERSIONMINOR ${VERSIONMINOR}" >> ${absolute_executable_path}/${setup}_version.nsh + echo "!define VERSIONBUILD ${VERSIONBUILD}" >> ${absolute_executable_path}/${setup}_version.nsh + if [ ${VERSIONSUFFIX} != "" ]; then + VERSIONSUFFIX="-${VERSIONSUFFIX}" + fi + echo "!define VERSIONSUFFIX ${VERSIONSUFFIX}" >> ${absolute_executable_path}/${setup}_version.nsh +} +# create installable binaries with dlls +function createInstallables() { + mkdir -p ${absolute_executable_path} + pushd ${temporary_build_path}/pkg/pyinst + # build install directories (contains multiple files with pyd,dll, some of + # them look like windows WS_32.dll but are from wine) + for setup in ${setups[@]} + do + # --clean do not cache anything and overwrite everything --noconfirm + # --distpath to place on correct location + # --debug to see what may be wrong with the result + # --paths=c:\python\lib\site-packages;c:\python27\lib\site-packages + wine pyinstaller \ + --clean \ + --noconfirm \ + --distpath=.\\installables \ + --paths=Z:\\var\\build\\pyinstaller\\src\\ \ + --paths=C:\\Python27\\Lib\\site-packages\\ \ + --debug \ + ${setup}.spec \ + || die 'pyinstaller for "'${setup}'" failed' + removeWineDlls installables/${setup} + addMingwDlls installables/${setup} + rm -r ${absolute_executable_path}/${setup} + cp -r installables/${setup} ${absolute_executable_path} + cp ${absolute_executable_path}/cacert.pem ${absolute_executable_path}/${setup} + rm -r installables + createInstallerVersion ${setup} + done + popd + pushd ${temporary_build_path} + cp data/images/mask-icon.ico ${absolute_executable_path}/ + popd +} +# install (windows)dependencies of project +function installProjectDependencies() { + pushd ${temporary_build_path} > /dev/null + unsupported_packages="dirspec" + pip_flags="--find-links=Z:${temporary_build_path}/wheels" + for unsupported_package in ${unsupported_packages} + do + pip_flags="${pip_flags} --allow-external ${unsupported_package} --allow-unverified ${unsupported_package}" + done + pip_flags="${pip_flags} -r" + + # install dependencies + mkdir -p ${temporary_build_path}/wheels + wine pip install ${pip_flags} pkg/requirements-leap.pip || die 'requirements-leap.pip could not be installed' + # fix requirements + # python-daemon breaks windows build + sed -i 's|^python-daemon|#python-daemon|' pkg/requirements.pip + wine pip install ${pip_flags} pkg/requirements.pip || die 'requirements.pip could not be installed' + git checkout pkg/requirements.pip + popd + cp -r /root/.wine/drive_c/Python27/Lib/site-packages ${absolute_executable_path} + curl https://curl.haxx.se/ca/cacert.pem > ${absolute_executable_path}/cacert.pem || die 'cacert.pem could not be fetched - would result in bad ssl in installer' +} +# workaround for broken dependencies +# runs before pip install requirements +# fixes failure for pysqlcipher as this requests a https file that the +# windows-python fails to request +function installProjectDependenciesBroken() { + pushd ${temporary_build_path} > /dev/null + curl https://pypi.python.org/packages/source/p/pysqlcipher/pysqlcipher-2.6.4.tar.gz \ + > pysqlcipher-2.6.4.tar.gz \ + || die 'fetch pysqlcipher failed' + tar xzf pysqlcipher-2.6.4.tar.gz + pushd pysqlcipher-2.6.4 + curl https://downloads.leap.se/libs/pysqlcipher/amalgamation-sqlcipher-2.1.0.zip \ + > amalgamation-sqlcipher-2.1.0.zip \ + || die 'fetch amalgamation for pysqlcipher failed' + unzip -o amalgamation-sqlcipher-2.1.0.zip || die 'unzip amalgamation failed' + mv sqlcipher amalgamation + patch -p0 < ${source_ro_path}/pkg/windows/pyinstaller/pysqlcipher_setup.py.patch \ + || die 'patch pysqlcipher setup.py failed' + wine python setup.py build install || die 'setup.py for pysqlcipher failed' + popd + popd # temporary_build_path +} +# prepare read-write copy +function prepareBuildPath() { + cleanup + # ensure shared openssl for all pip builds + test -d ${absolute_executable_path}/openvpn || die 'openvpn not available run docker-compose run --rm openvpn' + cp -r ${absolute_executable_path}/openvpn /root/.wine/drive_c/openssl + if [ -d ${absolute_executable_path}/site-packages ]; then + # use pip install cache for slow connections + rm -r /root/.wine/drive_c/Python27/Lib/site-packages + cp -r ${absolute_executable_path}/site-packages /root/.wine/drive_c/Python27/Lib/ + install_dependencies=false + fi + if [ ! -z $1 ]; then + git_tag=$1 + fi + if [ ${git_tag} != "HEAD" ]; then + echo "using ${git_tag} as source for the project" + git clone ${source_ro_path} ${temporary_build_path} + pushd ${temporary_build_path} + git checkout ${git_tag} || die 'checkout "'${git_tag}'" failed' + popd + else + echo "using current source tree for build" + mkdir -p ${temporary_build_path}/data + mkdir -p ${temporary_build_path}/docs + mkdir -p ${temporary_build_path}/pkg + mkdir -p ${temporary_build_path}/src + mkdir -p ${temporary_build_path}/.git + cp -r ${source_ro_path}/data/* ${temporary_build_path}/data + cp -r ${source_ro_path}/data/* ${temporary_build_path}/docs + cp -r ${source_ro_path}/pkg/* ${temporary_build_path}/pkg + cp -r ${source_ro_path}/src/* ${temporary_build_path}/src + cp -r ${source_ro_path}/.git/* ${temporary_build_path}/.git + cp ${source_ro_path}/* ${temporary_build_path}/ + fi +} +# add patches to the sourcetree +# this function should do nothing some day and should be run after +# the version has been evaluated +function applyPatches() { + root_path=$1 + # disable eip + if [ !${with_eip} ]; then + sed -i "s|HAS_EIP = True|HAS_EIP = False|" ${root_path}/src/leap/bitmask/_components.py + fi + # disable mail + if [ !${with_mail} ]; then + sed -i "s|HAS_MAIL = True|HAS_MAIL = False|" ${root_path}/src/leap/bitmask/_components.py + fi + # hack the logger + sed -i "s|'bitmask.log'|str(random.random()) + '_bitmask.log'|;s|import sys|import sys\nimport random|" ${root_path}/src/leap/bitmask/logs/utils.py + sed -i "s|perform_rollover=True|perform_rollover=False|" ${root_path}/src/leap/bitmask/app.py + # fix requirements + # python-daemon breaks windows build + sed -i 's|^python-daemon|#python-daemon|' ${root_path}/pkg/requirements.pip +} +# remove wine dlls that should not be in the installer +# root: path that should be cleaned from dlls +function removeWineDlls() { + root=$1 + declare -a wine_dlls=(\ + advapi32.dll \ + comctl32.dll \ + comdlg32.dll \ + gdi32.dll \ + imm32.dll \ + iphlpapi.dll \ + ktmw32.dll \ + msvcp90.dll \ + msvcrt.dll \ + mswsock.dll \ + mpr.dll \ + netapi32.dll \ + ole32.dll \ + oleaut32.dll \ + opengl32.dll \ + psapi.dll \ + rpcrt4.dll \ + shell32.dll \ + user32.dll \ + version.dll \ + winmm.dll \ + winspool.drv \ + ws2_32.dll \ + wtsapi32.dll \ + ) + for wine_dll in "${wine_dlls[@]}" + do + # not all of the listed dlls are in all directories + rm ${root}/${wine_dll} 2>/dev/null + done +} +# display failure message and emit non-zero exit code +function die() { + echo "die:" $@ + exit 1 +} +function main() { + prepareBuildPath $@ + if [ ${install_dependencies} == true ]; then + installProjectDependenciesBroken + installProjectDependencies + fi + createInstallablesDependencies + createInstallables + cleanup +} +main $@ \ No newline at end of file diff --git a/pkg/windows/pyinstaller/Dockerfile b/pkg/windows/pyinstaller/Dockerfile new file mode 100644 index 00000000..2da0da3a --- /dev/null +++ b/pkg/windows/pyinstaller/Dockerfile @@ -0,0 +1,105 @@ +FROM debian:jessie +MAINTAINER paixu@0xn0.de + +ENV PYTHON_VERSION=2.7.11 +ENV OPENSSL_VERSION=1.0.2f +ENV ZLIB_VERSION=1.2.8 +ENV MINGW_VERSION=0.6.2-beta-20131004-1 +ENV MINGW_BIN_VERSION=0.6.2-mingw32-beta-20131004-1-bin +ENV WINEDEBUG=fixme-all + +###### +# install packages required to build +# https-transport: winehq deb +# winbind: pip install keyring (requirements.pip) needs this somehow +# git-core: clone rw copy of repo and build specific commit +# imagemagick: convert png to ico-files +RUN apt-get update && apt-get -y install \ + unzip curl apt-transport-https \ + winbind \ + build-essential autoconf bison gperf flex libtool mingw-w64 \ + git-core \ + imagemagick \ + pkg-config + +# install wine > 1.6.2 (debian:jessie version fails with pip) +RUN dpkg --add-architecture i386 \ + && curl https://dl.winehq.org/wine-builds/Release.key | apt-key add - \ + && echo 'deb https://dl.winehq.org/wine-builds/debian/ jessie main' >> /etc/apt/sources.list.d/wine.list \ + && apt-get update + +RUN curl https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}.msi > /tmp/python-${PYTHON_VERSION}.msi +RUN curl -L http://sourceforge.net/projects/mingw/files/Installer/mingw-get/mingw-get-${MINGW_VERSION}/mingw-get-${MINGW_BIN_VERSION}.zip/download > /tmp/mingw-get.zip + +# alternative with messy python afterwards +# RUN curl -L http://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi > /tmp/msvcforpython27.msi + +RUN curl -L http://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz > /tmp/openssl-${OPENSSL_VERSION}.tar.gz +RUN apt-get install -y winehq-staging + +RUN curl -L http://sourceforge.net/projects/mingw/files/Installer/mingw-get/mingw-get-${MINGW_VERSION}/mingw-get-${MINGW_BIN_VERSION}.zip/download > /tmp/mingw-get.zip +RUN mkdir -p /root/.wine/drive_c/mingw \ + && unzip -d /root/.wine/drive_c/mingw /tmp/mingw-get.zip + +####### +# Build python dependency +# using the 'host' (linux) xcompiler instead of fiddeling in wine +# zlib - needs a update every 5 years +# adds a patch that makes a shared lib - default is static +RUN curl -L http://zlib.net/zlib-${ZLIB_VERSION}.tar.gz > /tmp/zlib-${ZLIB_VERSION}.tar.gz +ADD zlib-mingw-shared.patch /zlib-mingw-shared.patch +RUN mkdir -p /root/.wine/drive_c/zlib/src \ + && mv /tmp/zlib-${ZLIB_VERSION}.tar.gz /root/.wine/drive_c/zlib/src \ + && cd /root/.wine/drive_c/zlib/src \ + && tar xzf zlib-${ZLIB_VERSION}.tar.gz \ + && cd zlib-${ZLIB_VERSION} \ + && patch -p0 < /zlib-mingw-shared.patch \ + && make -f win32/Makefile.gcc PREFIX=/usr/bin/i686-w64-mingw32- \ + && make -f win32/Makefile.gcc INCLUDE_PATH=/root/.wine/drive_c/zlib/include LIBRARY_PATH=/root/.wine/drive_c/zlib/lib BINARY_PATH=/root/.wine/drive_c/zlib/bin install + +###### +# install gcc for most pip builds +# install g++ for pycryptopp +# this is mingw in wine, not to get confused with mingw-w64 in container-host +RUN wine msiexec -i /tmp/python-${PYTHON_VERSION}.msi -q \ + && wine c:/mingw/bin/mingw-get.exe install gcc g++ mingw32-make \ + && rm -r /tmp/.wine-0 + +#### +# pip configuration +# set wine mingw compiler to be used by "python setup build" +# set default include dirs, libraries and library paths +# the libraries=crypto is added because srp will only link using -lssl but links to BN_* (libcrypto) code +# 'install' zlib to mingw so python may find its dlls +# pyside-rcc fix (https://srinikom.github.io/pyside-bz-archive/670.html) +RUN printf "[build]\ncompiler=mingw32\n\n[build_ext]\ninclude_dirs=c:\\openssl\\include;c:\\zlib\\include\nlibraries=crypto\nlibrary_dirs=c:\\openssl\\lib;c:\\openssl\\bin;c:\\zlib\\lib;c:\\zlib\\bin" > /root/.wine/drive_c/Python27/Lib/distutils/distutils.cfg \ + && printf 'REGEDIT4\n\n[HKEY_CURRENT_USER\\Environment]\n"PATH"="C:\\\\python27;C:\\\\python27\\\\Scripts;C:\\\\python27\\\\Lib\\\\site-packages\\\\PySide;C:\\\\mingw\\\\bin;c:\\\\windows;c:\\\\windows\\\\system"' > /root/.wine/drive_c/path.reg \ + && printf 'REGEDIT4\n\n[HKEY_CURRENT_USER\\Environment]\n"OPENSSL_CONF"="C:\\\\openssl"' > /root/.wine/drive_c/openssl_conf.reg \ + && printf 'REGEDIT4\n\n[HKEY_CURRENT_USER\\Environment]\n"PYTHONPATH"="C:\\\\python27\\\\lib\\\\site-packages;Z:\\\\var\\\\build\\\\bitmask_rw\\\\src"' > /root/.wine/drive_c/pythonpath.reg \ + && cp /root/.wine/drive_c/zlib/bin/zlib1.dll /root/.wine/drive_c/mingw/bin \ + && cp /root/.wine/drive_c/zlib/lib/libz.dll.a /root/.wine/drive_c/mingw/lib + +#### +# prepare the environment with all python dependencies installed +# inject dirspec from distribution +# +RUN apt-get install -y python-dirspec \ + && cp -r /usr/lib/python2.7/dist-packages/dirspec* /root/.wine/drive_c/Python27/Lib/site-packages/ +RUN apt-get install -y python-setuptools +RUN wine regedit /root/.wine/drive_c/path.reg \ + && wine regedit /root/.wine/drive_c/openssl_conf.reg \ + && wine regedit /root/.wine/drive_c/pythonpath.reg \ + && wine pip install virtualenv pyinstaller \ + && wine pip install wheel \ + && wine pip install -U setuptools-scm \ + && wine pip install -U setuptools_scm \ + && wine pip install -U pyside python-qt \ + && wine pip install -I psutil==3.4.2 \ + && rm -r /tmp/.wine-0 + +# alternative msvc: after python is installed (or before?) +# && wine msiexec -i /tmp/msvcforpython27.msi -q \ + +RUN apt-get -y install \ + mc +ENTRYPOINT ["/var/src/bitmask/pkg/windows/pyinstaller-build.sh"] \ No newline at end of file diff --git a/pkg/windows/pyinstaller/pysqlcipher_setup.py.patch b/pkg/windows/pyinstaller/pysqlcipher_setup.py.patch new file mode 100644 index 00000000..dcec54fa --- /dev/null +++ b/pkg/windows/pyinstaller/pysqlcipher_setup.py.patch @@ -0,0 +1,14 @@ +--- setup.py.org 2014-11-12 16:38:07.000000000 +0000 ++++ setup.py 2016-01-23 14:08:13.255261595 +0000 +@@ -192,10 +192,7 @@ + ext.define_macros.append(("inline", "__inline")) + + # Configure the linker +- ext.extra_link_args.append("libeay32.lib") +- ext.extra_link_args.append( +- "/LIBPATH:" + os.path.join(openssl, "lib") +- ) ++ ext.extra_link_args.append("-lcrypto") + else: + ext.extra_link_args.append("-lcrypto") + diff --git a/pkg/windows/pyinstaller/zlib-mingw-shared.patch b/pkg/windows/pyinstaller/zlib-mingw-shared.patch new file mode 100644 index 00000000..1b980cb8 --- /dev/null +++ b/pkg/windows/pyinstaller/zlib-mingw-shared.patch @@ -0,0 +1,10 @@ +diff -Naur ../zlib-1.2.8-org/win32/Makefile.gcc ./win32/Makefile.gcc +--- ../zlib-1.2.8-org/win32/Makefile.gcc 2008-10-23 17:44:36.000000000 +0000 ++++ ./win32/Makefile.gcc 2015-12-06 19:20:00.449471787 +0000 +@@ -37,6 +37,6 @@ + # Set to 1 if shared object needs to be installed + # +-SHARED_MODE=0 ++SHARED_MODE=1 + + #LOC = -DASMV \ No newline at end of file -- cgit v1.2.3