1
0
mirror of https://gitlab.com/openlp/packaging.git synced 2024-12-22 21:12:50 +00:00
This commit is contained in:
Tomas Groth 2019-02-15 21:19:31 +01:00
commit eb853ebff9
5 changed files with 129 additions and 47 deletions

View File

@ -160,6 +160,8 @@ class Builder(object):
parser.add_argument('--skip-translations', action='store_true', default=False, parser.add_argument('--skip-translations', action='store_true', default=False,
help='Do NOT update the language translation files') help='Do NOT update the language translation files')
parser.add_argument('--debug', action='store_true', default=False, help='Create a debug build') parser.add_argument('--debug', action='store_true', default=False, help='Create a debug build')
parser.add_argument('--tag-override', metavar='<tag>-bzr<revision>', default=None,
help='Override tag and revision, should be in format <tag>-bzr<revision>')
self.add_extra_args(parser) self.add_extra_args(parser)
self.args = parser.parse_args() self.args = parser.parse_args()
@ -216,7 +218,7 @@ class Builder(object):
else: else:
self.version = None self.version = None
self.work_path = self.branch_path self.work_path = self.branch_path
self.openlp_script = os.path.abspath(os.path.join(self.work_path, 'openlp-run.py')) self.openlp_script = os.path.abspath(os.path.join(self.work_path, 'run_openlp.py'))
self.source_path = os.path.join(self.work_path, 'openlp') self.source_path = os.path.join(self.work_path, 'openlp')
self.manual_path = os.path.join(self.documentation_path, 'manual') self.manual_path = os.path.join(self.documentation_path, 'manual')
self.manual_build_path = os.path.join(self.manual_path, 'build') self.manual_build_path = os.path.join(self.manual_path, 'build')
@ -273,7 +275,6 @@ class Builder(object):
Run PyInstaller on the branch to build an executable. Run PyInstaller on the branch to build an executable.
""" """
self._print('Running PyInstaller...') self._print('Running PyInstaller...')
copy(os.path.join(self.work_path, 'openlp.py'), self.openlp_script)
os.chdir(self.work_path) os.chdir(self.work_path)
cmd = [self.python, cmd = [self.python,
self.pyinstaller_exe, self.pyinstaller_exe,
@ -304,6 +305,9 @@ class Builder(object):
""" """
self._print('Writing version file...') self._print('Writing version file...')
if not self.args.release: if not self.args.release:
if self.args.tag_override:
self.version = self.args.tag_override
else:
# This is a development build, get the tag and revision # This is a development build, get the tag and revision
output = self._bzr('tags', self.branch_path, err_msg='Error running bzr tags') output = self._bzr('tags', self.branch_path, err_msg='Error running bzr tags')
lines = output.splitlines() lines = output.splitlines()
@ -314,7 +318,7 @@ class Builder(object):
tag, revision = lines[-1].split() tag, revision = lines[-1].split()
output = self._bzr('log', self.branch_path, ['--line', '-r', '-1'], 'Error running bzr log') output = self._bzr('log', self.branch_path, ['--line', '-r', '-1'], 'Error running bzr log')
revision = output.split(':')[0] revision = output.split(':')[0]
self.version = '{tag}-bzr{revision}'.format(tag=tag, revision=revision) self.version = '{tag}.dev{revision}'.format(tag=tag, revision=revision)
# Write the version to the version file # Write the version to the version file
with open(os.path.join(self.dist_path, '.version'), 'w') as version_file: with open(os.path.join(self.dist_path, '.version'), 'w') as version_file:
version_file.write(str(self.version)) version_file.write(str(self.version))
@ -430,7 +434,8 @@ class Builder(object):
rmtree(self.manual_build_path) rmtree(self.manual_build_path)
os.chdir(self.manual_path) os.chdir(self.manual_path)
sphinx_build = self.get_sphinx_build() sphinx_build = self.get_sphinx_build()
command = [self.sphinx_exe, '-b', sphinx_build, '-d', 'build/doctrees', 'source', 'build/{}'.format(sphinx_build)] command = [self.sphinx_exe, '-b', sphinx_build, '-d', 'build/doctrees', 'source',
'build/{}'.format(sphinx_build)]
self._run_command(command, 'Error running Sphinx') self._run_command(command, 'Error running Sphinx')
self.after_run_sphinx() self.after_run_sphinx()
@ -479,5 +484,3 @@ class Builder(object):
self._print('Done.') self._print('Done.')
raise SystemExit() raise SystemExit()

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
############################################################################### ###############################################################################
# OpenLP - Open Source Lyrics Projection # # OpenLP - Open Source Lyrics Projection #
@ -94,15 +94,15 @@ You may need to install chardet via pip::
""" """
import os import os
import plistlib from pathlib import Path
import signal from shutil import copy, copytree, move, rmtree
from shutil import copy, copytree
from macholib.MachO import MachO from macholib.MachO import MachO
from macholib.util import flipwritable, in_system_path from macholib.util import in_system_path
from builder import Builder from builder import Builder
class MacOSXBuilder(Builder): class MacOSXBuilder(Builder):
""" """
The :class:`MacosxBuilder` class encapsulates everything that is needed The :class:`MacosxBuilder` class encapsulates everything that is needed
@ -119,6 +119,99 @@ class MacOSXBuilder(Builder):
dir_size += os.path.getsize(filename) dir_size += os.path.getsize(filename)
return dir_size return dir_size
def _create_symlink(self, folder):
"""
Create the appropriate symlink in the MacOS folder pointing to the Resources folder.
"""
sibling = Path(str(folder).replace('MacOS', ''))
# PyQt5/Qt/qml/QtQml/Models.2
root = str(sibling).partition('Contents')[2].lstrip('/')
# ../../../../
backward = '../' * len(root.split('/'))
# ../../../../Resources/PyQt5/Qt/qml/QtQml/Models.2
good_path = f'{backward}Resources/{root}'
folder.symlink_to(good_path)
def _fix_qt_dll(self, dll):
"""
Fix the DLL lookup paths to use relative ones for Qt dependencies.
Inspiration: PyInstaller/depend/dylib.py:mac_set_relative_dylib_deps()
Currently one header is pointing to (we are in the Resources folder):
@loader_path/../../../../QtCore (it is referencing to the old MacOS folder)
It will be converted to:
@loader_path/../../../../../../MacOS/QtCore
"""
def match_func(pth):
"""
Callback function for MachO.rewriteLoadCommands() that is
called on every lookup path setted in the DLL headers.
By returning None for system libraries, it changes nothing.
Else we return a relative path pointing to the good file
in the MacOS folder.
"""
basename = os.path.basename(pth)
if not basename.startswith('Qt'):
return None
return f'@loader_path{good_path}/{basename}'
# Resources/PyQt5/Qt/qml/QtQuick/Controls.2/Fusion
root = str(dll.parent).partition('Contents')[2][1:]
# /../../../../../../..
backward = '/..' * len(root.split('/'))
# /../../../../../../../MacOS
good_path = f'{backward}/MacOS'
# Rewrite Mach headers with corrected @loader_path
dll = MachO(dll)
dll.rewriteLoadCommands(match_func)
with open(dll.filename, 'rb+') as f:
for header in dll.headers:
f.seek(0)
dll.write(f)
f.seek(0, 2)
f.flush()
def _find_problematic_qt_folders(self, folder):
"""
Recursively yields problematic folders (containing a dot in their name).
"""
for path in folder.iterdir():
if not path.is_dir() or path.is_symlink():
# Skip simlinks as they are allowed (even with a dot)
continue
if '.' in path.name:
yield path
else:
yield from self._find_problematic_qt_folders(path)
def _move_contents_to_resources(self, folder):
"""
Recursively move any non symlink file from a problematic folder to the sibling one in Resources.
"""
for path in folder.iterdir():
if path.is_symlink():
continue
if path.is_dir():
yield from self._move_contents_to_resources(path)
else:
sibling = Path(str(path).replace('MacOS', 'Resources'))
move(path, sibling)
yield sibling
def _fix_qt_paths(self):
"""
Fix the Qt paths
"""
app_path = Path(self.dist_app_path) / 'Contents' / 'MacOS'
for folder in self._find_problematic_qt_folders(app_path):
for problematic_file in self._move_contents_to_resources(folder):
self._fix_qt_dll(problematic_file)
rmtree(folder)
self._create_symlink(folder)
def _relink_mupdf(self, bin_name): def _relink_mupdf(self, bin_name):
""" """
Relink mupdf to bundled libraries Relink mupdf to bundled libraries
@ -181,7 +274,8 @@ class MacOSXBuilder(Builder):
""" """
Copy Info.plist and OpenLP.icns to app bundle. Copy Info.plist and OpenLP.icns to app bundle.
""" """
copy(self.icon_path, os.path.join(self.dist_app_path, 'Contents', 'Resources', os.path.basename(self.icon_path))) copy(self.icon_path, os.path.join(self.dist_app_path, 'Contents', 'Resources',
os.path.basename(self.icon_path)))
# Add OpenLP version to Info.plist and put it to app bundle. # Add OpenLP version to Info.plist and put it to app bundle.
fr = open(self.bundle_info_path, 'r') fr = open(self.bundle_info_path, 'r')
fw = open(os.path.join(self.dist_app_path, 'Contents', os.path.basename(self.bundle_info_path)), 'w') fw = open(os.path.join(self.dist_app_path, 'Contents', os.path.basename(self.bundle_info_path)), 'w')
@ -238,7 +332,8 @@ class MacOSXBuilder(Builder):
os.chdir(os.path.dirname(self.dmg_settings_path)) os.chdir(os.path.dirname(self.dmg_settings_path))
self._run_command([self.dmgbuild_exe, '-s', self.dmg_settings_path, '-D', 'size={size}M'.format(size=size), self._run_command([self.dmgbuild_exe, '-s', self.dmg_settings_path, '-D', 'size={size}M'.format(size=size),
'-D', 'icon={icon_path}'.format(icon_path=self.icon_path), '-D', 'icon={icon_path}'.format(icon_path=self.icon_path),
'-D', 'app={dist_app_path}'.format(dist_app_path=self.dist_app_path), dmg_title, self.dmg_file], '-D', 'app={dist_app_path}'.format(dist_app_path=self.dist_app_path), dmg_title,
self.dmg_file],
'Unable to run dmgbuild') 'Unable to run dmgbuild')
# Dmg done. # Dmg done.
@ -299,6 +394,7 @@ class MacOSXBuilder(Builder):
""" """
Build the actual DMG Build the actual DMG
""" """
self._fix_qt_paths()
self._code_sign() self._code_sign()
self._create_dmg() self._create_dmg()

View File

@ -26,7 +26,7 @@ Windows Build Script
This script is used to build the Windows binary and the accompanying installer. This script is used to build the Windows binary and the accompanying installer.
For this script to work out of the box, it depends on a number of things: For this script to work out of the box, it depends on a number of things:
Python 3.6 Python 3.7
PyQt5 PyQt5
You should already have this installed, OpenLP doesn't work without it. The You should already have this installed, OpenLP doesn't work without it. The
@ -57,10 +57,6 @@ OpenLP
shared repository directory. This means your code should be in a directory shared repository directory. This means your code should be in a directory
structure like this: "openlp\\branch-name". structure like this: "openlp\\branch-name".
Visual C++ 2008 Express Edition
This is to build pptviewlib.dll, the library for controlling the
PowerPointViewer.
windows-builder.py windows-builder.py
This script, of course. It should be in the "windows-installer" directory This script, of course. It should be in the "windows-installer" directory
at the same level as OpenLP trunk. at the same level as OpenLP trunk.
@ -125,17 +121,6 @@ class WindowsBuilder(Builder):
The :class:`WindowsBuilder` class encapsulates everything that is needed The :class:`WindowsBuilder` class encapsulates everything that is needed
to build a Windows installer. to build a Windows installer.
""" """
def _build_pptviewlib(self):
"""
Build the PowerPoint Viewer DLL using Visual Studio.
"""
self._print('Building PPTVIEWLIB.DLL...')
if not os.path.exists(self.vcbuild_exe):
self._print('... WARNING: vcbuild.exe was not found, skipping building pptviewlib.dll')
return
self._run_command([self.vcbuild_exe, '/rebuild', os.path.join(self.pptviewlib_path, 'pptviewlib.vcproj'),
'Release|Win32'], 'Error building pptviewlib.dll')
copy(os.path.join(self.pptviewlib_path, 'Release', 'pptviewlib.dll'), self.pptviewlib_path)
def _create_innosetup_file(self): def _create_innosetup_file(self):
""" """
@ -345,7 +330,7 @@ class WindowsBuilder(Builder):
""" """
parameters = [] parameters = []
# Finds the UCRT DDLs available from the Windows 10 SDK # Finds the UCRT DDLs available from the Windows 10 SDK
for binary in glob.glob('C:\\Program Files (x86)\\Windows Kits\\10\\Redist\\ucrt\\DLLs\\x86\\*.dll'): for binary in glob.glob('C:\\Program Files (x86)\\Windows Kits\\10\\Redist\\ucrt\\DLLs\\x64\\*.dll'):
parameters.append('--add-binary') parameters.append('--add-binary')
parameters.append(binary + ";.") parameters.append(binary + ";.")
return parameters return parameters

View File

@ -2,17 +2,16 @@
innosetup = %(progfiles)s\Inno Setup 5\ISCC.exe innosetup = %(progfiles)s\Inno Setup 5\ISCC.exe
sphinx = %(pyroot)s\Scripts\sphinx-build.exe sphinx = %(pyroot)s\Scripts\sphinx-build.exe
pyinstaller = %(pyroot)s\Scripts\pyinstaller-script.py pyinstaller = %(pyroot)s\Scripts\pyinstaller-script.py
vcbuild = %(progfiles)s\Microsoft Visual Studio 9.0\VC\vcpackages\vcbuild.exe
htmlhelp = %(progfiles)s\HTML Help Workshop\hhc.exe htmlhelp = %(progfiles)s\HTML Help Workshop\hhc.exe
psvince = %(here)s\psvince.dll psvince = %(here)s\psvince.dll
lrelease = C:\Qt\5.9\msvc2015\bin\lrelease.exe lrelease = C:\Qt\5.12\msvc2017\bin\lrelease.exe
portablelauncher = %(here)s\..\..\PortableApps.comLauncher\PortableApps.comLauncherGenerator.exe portablelauncher = %(here)s\..\..\PortableApps.comLauncher\PortableApps.comLauncherGenerator.exe
portableinstaller = %(here)s\..\..\PortableApps.comInstaller\PortableApps.comInstaller.exe portableinstaller = %(here)s\..\..\PortableApps.comInstaller\PortableApps.comInstaller.exe
mutool = %(here)s\..\..\mupdf-1.9a-windows\mutool.exe mutool = %(project)s\openlp-branch\mutool.exe
mediainfo = %(here)s\..\..\MediaInfo\MediaInfo.exe mediainfo = %(project)s\openlp-branch\MediaInfo.exe
[paths] [paths]
branch = %(projects)s\trunk branch = %(projects)s\openlp-branch
documentation = %(projects)s\documentation documentation = %(projects)s\documentation
icon = %(here)s\OpenLP.ico icon = %(here)s\OpenLP.ico
hooks = %(here)s\..\pyinstaller-hooks hooks = %(here)s\..\pyinstaller-hooks

View File

@ -2,7 +2,6 @@
innosetup = %(progfiles)s\Inno Setup 5\ISCC.exe innosetup = %(progfiles)s\Inno Setup 5\ISCC.exe
sphinx = %(pyroot)s\Scripts\sphinx-build.exe sphinx = %(pyroot)s\Scripts\sphinx-build.exe
pyinstaller = %(here)s\..\pyinstaller\pyinstaller.py pyinstaller = %(here)s\..\pyinstaller\pyinstaller.py
vcbuild = %(progfiles)s\Microsoft Visual Studio 9.0\VC\vcpackages\vcbuild.exe
htmlhelp = %(progfiles)s\HTML Help Workshop\hhc.exe htmlhelp = %(progfiles)s\HTML Help Workshop\hhc.exe
psvince = %(here)s\psvince.dll psvince = %(here)s\psvince.dll
lrelease = %(sitepackages)s\PyQt5\bin\lrelease.exe lrelease = %(sitepackages)s\PyQt5\bin\lrelease.exe