Merge branch 'fix-msi-pyinstaller' into 'master'

Fix MSI and PyInstaller builds

Closes #2

See merge request openlp/packaging!3
merge-requests/5/head
Tomas Groth 2019-11-13 21:34:04 +00:00
commit 2a26e6c03d
5 changed files with 90 additions and 90 deletions

View File

@ -161,7 +161,7 @@ class Builder(object):
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>.dev<revision-count>+<commit-hash>', default=None, parser.add_argument('--tag-override', metavar='<tag>.dev<revision-count>+<commit-hash>', default=None,
help='Override tag and revision, should be in format <tag>.dev<revision-count>+<commit-hash>') help='Override tag and revision, should be in format <tag>.dev<revision-count>+<commit-hash>') # noqa
self.add_extra_args(parser) self.add_extra_args(parser)
self.args = parser.parse_args() self.args = parser.parse_args()
@ -218,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, 'run_openlp.py')) self.openlp_script = os.path.abspath(os.path.join(self.work_path, 'openlp', '__main__.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')
@ -507,6 +507,7 @@ class Builder(object):
self._print('') self._print('')
self._print('WARNING: Documentation trunk not found') self._print('WARNING: Documentation trunk not found')
self._print(' Help file will not be included in build') self._print(' Help file will not be included in build')
self._print(' Manual path: %s', self.manual_path)
self._print('') self._print('')
self.copy_extra_files() self.copy_extra_files()
if not self.args.skip_translations: if not self.args.skip_translations:

View File

@ -102,8 +102,9 @@ from distutils import dir_util
from hashlib import md5 from hashlib import md5
from shutil import copy, copytree, move, rmtree from shutil import copy, copytree, move, rmtree
from lxml.etree import fromstring, parse, tostring from lxml.etree import ElementTree
from lxml.builder import E, ElementMaker from lxml.builder import E, ElementMaker
from lxml.objectify import fromstring
from builder import Builder from builder import Builder
@ -128,63 +129,81 @@ class WindowsBuilder(Builder):
else: else:
return None return None
def _get_fragments_from_files(self, start_dir): def _get_dirs_and_files(self, install_dir, start_dir):
""" """
Walk down a directory recursively and build up the XML for WiX Walk down a directory recursively and build up the XML for WiX
""" """
self._openlp_id = None
start_base, start_path = os.path.split(start_dir) start_base, start_path = os.path.split(start_dir)
element = E.DirectoryRef(Id='INSTALLDIR') element = install_dir
directories = {start_path: {'__dir__': element}} directories = {start_path: {'__dir__': element}}
components = [] components = []
component_ids = []
FxE = ElementMaker(namespace='http://schemas.microsoft.com/wix/FirewallExtension', FxE = ElementMaker(namespace='http://schemas.microsoft.com/wix/FirewallExtension',
nsmap={'fw': 'http://schemas.microsoft.com/wix/FirewallExtension'}) nsmap={'fw': 'http://schemas.microsoft.com/wix/FirewallExtension'})
for root, _, files in os.walk(start_dir): for root, _, files in os.walk(start_dir):
parent = os.sep.join(root.replace(os.path.join(start_base, ''), '').split(os.sep)[:-1]) parent = os.sep.join(root.replace(os.path.join(start_base, ''), '').split(os.sep)[:-1])
if root == start_dir:
path = ''
else:
path = root.replace(os.path.join(start_dir, ''), '')
base = os.path.basename(root) base = os.path.basename(root)
if root != start_dir: if root != start_dir:
dir_id = 'dir_{parent}_{base}'.format(parent=parent.replace(os.sep, '_'), base=base) dir_id = 'd_{}'.format(md5(os.path.join(parent, base).encode('utf8')).hexdigest())
element = E.Directory(Id=dir_id, Name=base) new_element = E.Directory(Id=dir_id, Name=base)
element.append(new_element)
element = new_element
new_dir = {'__dir__': element} new_dir = {'__dir__': element}
parent_dir = self._walk_dirs(directories, parent) parent_dir = self._walk_dirs(directories, parent)
parent_dir[base] = new_dir parent_dir[base] = new_dir
parent_dir['__dir__'].append(element) parent_dir['__dir__'].append(element)
for fname in files: for fname in files:
source = os.path.join(path, fname) if path else fname source = os.path.join(root, fname)
source_id = md5(source.encode('utf8')).hexdigest() source_id = 'f_{}'.format(md5(source.encode('utf8')).hexdigest())
file_id = 'file_{source_id}'.format(source_id=source_id) component_ids.append(source_id)
component_id = 'cmp_{source_id}'.format(source_id=source_id)
if self.arch == 'x64': if self.arch == 'x64':
file_ = E.File(Id=file_id, KeyPath='yes', Source=source, ProcessorArchitecture='x64') file_ = E.File(Id=source_id, Name=fname, Source=source, ProcessorArchitecture='x64')
component = E.Component(file_, Id=component_id, Guid='*', Win64='yes') component = E.Component(file_, Id=source_id, Guid='*', DiskId='1', Win64='yes')
else: else:
file_ = E.File(Id=file_id, KeyPath='yes', Source=source) file_ = E.File(Id=source_id, Name=fname, Source=source)
component = E.Component(file_, Id=component_id, Guid='*') component = E.Component(file_, Id=source_id, Guid='*', DiskId='1')
if source.endswith('OpenLP.exe'): if source.endswith('OpenLP.exe'):
description = 'Firewall exception for OpenLP\'s remote interface (UDP)' self._openlp_id = source_id
program = '[#file_e368869eb54b01e2288a3359b1cf51f8]' file_.set('KeyPath', 'yes')
component.append(FxE.FirewallException(Id='OpenLP_TCP', Name='OpenLP', fw_program = '[#{}]'.format(source_id)
Description=description, IgnoreFailure='yes', component.append(FxE.FirewallException(Id='OpenLP_TCP', Name='$(var.ProductName)',
Program=program, Protocol='tcp', Scope='any')) IgnoreFailure='yes', Program=fw_program,
component.append(FxE.FirewallException(Id='OpenLP_UDP', Name='OpenLP', Protocol='tcp', Scope='any'))
Description=description, IgnoreFailure='yes', component.append(FxE.FirewallException(Id='OpenLP_UDP', Name='$(var.ProductName)',
Program=program, Protocol='udp', Scope='any')) IgnoreFailure='yes', Program=fw_program,
# Add the file association XML Protocol='udp', Scope='any'))
config_dir = os.path.dirname(self.config_path) component.append(E.Shortcut(Id='ApplicationStartMenuShortcut', Name='$(var.ProductName)',
with open(os.path.join(config_dir, 'file-associations.xml')) as assoc_file: Description='$(var.Description)', Directory='ProgramMenuDir',
file_assoc = parse(assoc_file) Icon='OpenLP.ico', Advertise='yes', WorkingDirectory='INSTALLDIR'))
component.append(file_assoc.getroot()) component.append(E.Shortcut(Id='DebugStartMenuShortcut', Name='$(var.ProductName) (Debug)',
Description='Run $(var.ProductName) with debug logging enabled',
Directory='ProgramMenuDir', Arguments='--log-level debug',
Icon='OpenLP.ico', Advertise='yes', WorkingDirectory='INSTALLDIR'))
component.append(E.ProgId(
E.Extension(
E.Verb(Id="Open", Command="Open", Argument=" &quot;%1&quot;"),
E.MIME(Advertise="yes", ContentType="application/-x-openlp-service", Default="yes"),
Id="osz"
),
E.Extension(
E.Verb(Id="Open", Command="Open", Argument=" &quot;%1&quot;"),
E.MIME(Advertise="yes", ContentType="application/-x-openlp-service-lite", Default="yes"),
Id="oszl"
),
Id="OpenLP.Service",
Description="OpenLP Service File",
Icon="service_file.ico",
Advertise="yes"
))
elif source.endswith('OpenLP.chm'):
component.append(E.Shortcut(Id='HelpStartMenuShortcut', Name='$(var.ProductName) Help',
Description='Help file for $(var.ProductName)',
Target='[#{}]'.format(source_id), WorkingDirectory='INSTALLDIR'))
element.append(component) element.append(component)
components.append(component) components.append(component)
return component_ids
files_fragment = E.Fragment(directories[start_path]['__dir__'])
comps_fragment = E.Fragment(E.ComponentGroup(*[E.ComponentRef(Id=c.attrib['Id']) for c in components],
Id='Files'))
return files_fragment, comps_fragment
def _create_wix_file(self): def _create_wix_file(self):
""" """
@ -195,27 +214,40 @@ class WindowsBuilder(Builder):
self._print_verbose('Reading base WiX file') self._print_verbose('Reading base WiX file')
with open(os.path.join(config_dir, 'OpenLP-base.wxs'), 'rt') as base_file: with open(os.path.join(config_dir, 'OpenLP-base.wxs'), 'rt') as base_file:
xml = base_file.read() xml = base_file.read()
progfilefolder = 'ProgramFiles64Folder' if self.arch == 'x64' else 'ProgramFilesFolder'
# convert the version string to format x.x.x if needed # convert the version string to format x.x.x if needed
if '.dev' in self.version: if '.dev' in self.version:
windows_version = self.version.replace('.dev', '.') windows_version = self.version.replace('.dev', '.')
windows_version = windows_version.rsplit('+', 1)[0] windows_version = windows_version.rsplit('+', 1)[0]
else: else:
windows_version = self.version windows_version = self.version
xml = xml % dict(dialog=os.path.join(config_dir, 'WizardMain.bmp'), xml = xml % {
banner=os.path.join(config_dir, 'WizardBanner.bmp'), 'dialog': os.path.join(config_dir, 'WizardMain.bmp'),
platform=self.arch, 'banner': os.path.join(config_dir, 'WizardBanner.bmp'),
progfilefolder=progfilefolder, 'license': os.path.join(config_dir, 'LICENSE.rtf'),
version=windows_version) 'platform': self.arch,
tree = fromstring(xml.encode('utf8')) 'progfilefolder': 'ProgramFiles64Folder' if self.arch == 'x64' else 'ProgramFilesFolder',
'systemfolder': 'System64Folder' if self.arch == 'x64' else 'SystemFolder',
'version': windows_version
}
root = fromstring(xml.encode('utf8'))
# Find the INSTALLDIR directory component and populate it with our files and folders
install_dir = root.xpath('//wix:Directory[@Id="INSTALLDIR"]',
namespaces={'wix': 'http://schemas.microsoft.com/wix/2006/wi'})[0]
self._print_verbose('Creating XML fragments from files and directories') self._print_verbose('Creating XML fragments from files and directories')
fragments = self._get_fragments_from_files(self.dist_path) component_ids = self._get_dirs_and_files(install_dir, self.dist_path)
self._print_verbose('Inserting XML fragments into base WiX file') # Write the property for the "Run OpenLP" checkbox
for fragment in fragments: product = root.xpath('//wix:Product',
tree.append(fragment) namespaces={'wix': 'http://schemas.microsoft.com/wix/2006/wi'})[0]
product.append(E.Property(Id='WixShellExecTarget', Value='[#{}]'.format(self._openlp_id)))
# Set the component ids for the feature
feature = root.xpath('//wix:Feature',
namespaces={'wix': 'http://schemas.microsoft.com/wix/2006/wi'})[0]
for component_id in component_ids:
feature.append(E.ComponentRef(Id=component_id))
self._print_verbose('Writing new WiX file') self._print_verbose('Writing new WiX file')
tree = ElementTree(root)
with open(os.path.join(config_dir, 'OpenLP.wxs'), 'wb') as f: with open(os.path.join(config_dir, 'OpenLP.wxs'), 'wb') as f:
f.write(tostring(tree, encoding='utf-8', xml_declaration=True, pretty_print=True)) tree.write(f, encoding='utf-8', xml_declaration=True, pretty_print=True)
def _run_wix_tools(self): def _run_wix_tools(self):
""" """

View File

@ -29,5 +29,6 @@ hiddenimports = [
'openlp.plugins.custom.customplugin', 'openlp.plugins.custom.customplugin',
'openlp.plugins.songusage.songusageplugin', 'openlp.plugins.songusage.songusageplugin',
'openlp.plugins.remotes.remoteplugin', 'openlp.plugins.remotes.remoteplugin',
'openlp.plugins.alerts.alertsplugin' 'openlp.plugins.alerts.alertsplugin',
'openlp.plugins.planningcenter.planningcenterplugin'
] ]

View File

@ -10,16 +10,14 @@
<?define UpgradeCode="8C5881AC-8F1E-4937-BB99-B823FABF18F0"?> <?define UpgradeCode="8C5881AC-8F1E-4937-BB99-B823FABF18F0"?>
<?define Platform="%(platform)s"?> <?define Platform="%(platform)s"?>
<Product Name="$(var.ProductName)" Manufacturer="$(var.Manufacturer)" Id="$(var.ProductCode)" <Product Name="$(var.ProductName)" Manufacturer="$(var.Manufacturer)" Id="$(var.ProductCode)"
UpgradeCode="$(var.UpgradeCode)" Language="1033" Codepage="1252" Version="$(var.ProductVersion)"> UpgradeCode="$(var.UpgradeCode)" Language="1033" Version="$(var.ProductVersion)">
<Package Id="*" Keywords="Installer" Description="$(var.Description)" Comments="$(var.Comments)" <Package Id="*" Keywords="Installer" Description="$(var.Description)" Comments="$(var.Comments)"
Manufacturer="$(var.Manufacturer)" InstallerVersion="251" Languages="1033" Compressed="yes" Manufacturer="$(var.Manufacturer)" InstallerVersion="400" Compressed="yes" Platform="$(var.Platform)"/>
SummaryCodepage="1252" Platform="$(var.Platform)"/>
<Condition Message="You need to be an administrator to install this product.">Privileged</Condition> <Condition Message="You need to be an administrator to install this product.">Privileged</Condition>
<Media Id="1" Cabinet="openlp.cab" EmbedCab="yes" CompressionLevel="high"/> <Media Id="1" Cabinet="OpenLP.cab" EmbedCab="yes"/>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" /> <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
<Property Id="ARPPRODUCTICON" Value="OpenLP.ico" /> <Property Id="ARPPRODUCTICON" Value="OpenLP.ico" />
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch $(var.ProductName)" /> <Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch $(var.ProductName)" />
<Property Id="WixShellExecTarget" Value="[#file_e368869eb54b01e2288a3359b1cf51f8]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" /> <CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<UIRef Id="WixUI_Common" /> <UIRef Id="WixUI_Common" />
<UI Id="WixUI_OpenLP"> <UI Id="WixUI_OpenLP">
@ -63,31 +61,13 @@
<WixVariable Id="WixUIBannerBmp" Value="%(banner)s" /> <WixVariable Id="WixUIBannerBmp" Value="%(banner)s" />
<Directory Id="TARGETDIR" Name="SourceDir"> <Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="%(progfilefolder)s"> <Directory Id="%(progfilefolder)s">
<Directory Id="INSTALLDIR" Name="$(var.ProductName)"/> <Directory Id="INSTALLDIR" Name="$(var.ProductName)"/>
</Directory> </Directory>
<Directory Id="ProgramMenuFolder" Name="Programs"> <Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="$(var.ProductName)"> <Directory Id="ProgramMenuDir" Name="$(var.ProductName)">
<Component Id="ProgramMenuDir" Guid="{7AABE54C-5B03-4049-AA85-E18B787A19C7}"> <Component Id="ProgramMenuDir" Guid="{7AABE54C-5B03-4049-AA85-E18B787A19C7}">
<RemoveFolder Id="ProgramMenuDir" On="uninstall" /> <RemoveFolder Id="ProgramMenuDir" On="uninstall" />
<RegistryValue Root="HKCU" Key="Software\$(var.ProductName)\$(var.ProductName)" Type="string" Value="" KeyPath="yes" /> <RegistryValue Root="HKCU" Key="Software\$(var.ProductName)\$(var.ProductName)" Type="string" Value="" KeyPath="yes" />
<Shortcut Id="ApplicationStartMenuShortcut"
Name="$(var.ProductName)"
Description="$(var.Description)"
Target="[#file_e368869eb54b01e2288a3359b1cf51f8]"
Icon="OpenLP.ico"
WorkingDirectory="RootDirectory"/>
<Shortcut Id="DebugStartMenuShortcut"
Name="$(var.ProductName) (Debug)"
Description="Run OpenLP with debug logging enabled"
Target="[#file_e368869eb54b01e2288a3359b1cf51f8]"
Arguments="--log-level debug"
Icon="OpenLP.ico"
WorkingDirectory="RootDirectory"/>
<Shortcut Id="HelpStartMenuShortcut"
Name="$(var.ProductName) Help"
Description="Help file for $(var.ProductName)"
Target="[#file_436f15ee9b174c85745878fe09b6d47e]"
WorkingDirectory="RootDirectory"/>
<util:InternetShortcut Id="OpenLPWebSite" <util:InternetShortcut Id="OpenLPWebSite"
Name="$(var.ProductName) on the Web" Name="$(var.ProductName) on the Web"
Target="http://openlp.org/"/> Target="http://openlp.org/"/>
@ -96,7 +76,7 @@
Target="http://forums.openlp.org/"/> Target="http://forums.openlp.org/"/>
<Shortcut Id="UninstallProduct" <Shortcut Id="UninstallProduct"
Name="Uninstall $(var.ProductName)" Name="Uninstall $(var.ProductName)"
Target="[SystemFolder]msiexec.exe" Target="[%(systemfolder)s]msiexec.exe"
Arguments="/x [ProductCode]" Arguments="/x [ProductCode]"
Description="Removes $(var.ProductName) from your computer" /> Description="Removes $(var.ProductName) from your computer" />
</Component> </Component>
@ -104,12 +84,8 @@
</Directory> </Directory>
<Directory Id="DesktopFolder" Name="Desktop" /> <Directory Id="DesktopFolder" Name="Desktop" />
</Directory> </Directory>
<DirectoryRef Id="INSTALLDIR"> <Feature Id="Complete" Title="Complete" Description="The $(var.ProductName) program files" Level="1"
<Directory Id="RootDirectory" Name="$(var.ProductName)" />
</DirectoryRef>
<Feature Id="Complete" Title="Complete" Description="The $(var.ProductName) program files" Level="0"
ConfigurableDirectory="INSTALLDIR" AllowAdvertise="no" InstallDefault="local" Absent="disallow"> ConfigurableDirectory="INSTALLDIR" AllowAdvertise="no" InstallDefault="local" Absent="disallow">
<ComponentGroupRef Id="Files"/>
<ComponentRef Id="ProgramMenuDir"/> <ComponentRef Id="ProgramMenuDir"/>
</Feature> </Feature>
<Icon Id="OpenLP.ico" SourceFile="OpenLP.ico"/> <Icon Id="OpenLP.ico" SourceFile="OpenLP.ico"/>

View File

@ -1,10 +0,0 @@
<ProgId Id="OpenLP.Service" Description="OpenLP Service File" Icon="service_file.ico" Advertise="yes">
<Extension Id="osz">
<Verb Id="Open" Command="Open" Argument=" &quot;%1&quot;" />
<MIME Advertise="yes" ContentType="application/-x-openlp-service" Default="yes" />
</Extension>
<Extension Id="oszl">
<Verb Id="Open" Command="Open" Argument=" &quot;%1&quot;" />
<MIME Advertise="yes" ContentType="application/-x-openlp-service-lite" Default="yes" />
</Extension>
</ProgId>