Browse Source

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 3 years ago
parent
commit
2a26e6c03d
  1. 5
      builders/builder.py
  2. 126
      builders/windows-builder.py
  3. 3
      pyinstaller-hooks/hook-openlp.py
  4. 36
      windows/OpenLP-base.wxs
  5. 10
      windows/file-associations.xml

5
builders/builder.py

@ -161,7 +161,7 @@ class Builder(object):
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('--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.args = parser.parse_args()
@ -218,7 +218,7 @@ class Builder(object):
else:
self.version = None
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.manual_path = os.path.join(self.documentation_path, 'manual')
self.manual_build_path = os.path.join(self.manual_path, 'build')
@ -507,6 +507,7 @@ class Builder(object):
self._print('')
self._print('WARNING: Documentation trunk not found')
self._print(' Help file will not be included in build')
self._print(' Manual path: %s', self.manual_path)
self._print('')
self.copy_extra_files()
if not self.args.skip_translations:

126
builders/windows-builder.py

@ -102,8 +102,9 @@ from distutils import dir_util
from hashlib import md5
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.objectify import fromstring
from builder import Builder
@ -128,63 +129,81 @@ class WindowsBuilder(Builder):
else:
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
"""
self._openlp_id = None
start_base, start_path = os.path.split(start_dir)
element = E.DirectoryRef(Id='INSTALLDIR')
element = install_dir
directories = {start_path: {'__dir__': element}}
components = []
component_ids = []
FxE = ElementMaker(namespace='http://schemas.microsoft.com/wix/FirewallExtension',
nsmap={'fw': 'http://schemas.microsoft.com/wix/FirewallExtension'})
for root, _, files in os.walk(start_dir):
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)
if root != start_dir:
dir_id = 'dir_{parent}_{base}'.format(parent=parent.replace(os.sep, '_'), base=base)
element = E.Directory(Id=dir_id, Name=base)
dir_id = 'd_{}'.format(md5(os.path.join(parent, base).encode('utf8')).hexdigest())
new_element = E.Directory(Id=dir_id, Name=base)
element.append(new_element)
element = new_element
new_dir = {'__dir__': element}
parent_dir = self._walk_dirs(directories, parent)
parent_dir[base] = new_dir
parent_dir['__dir__'].append(element)
for fname in files:
source = os.path.join(path, fname) if path else fname
source_id = md5(source.encode('utf8')).hexdigest()
file_id = 'file_{source_id}'.format(source_id=source_id)
component_id = 'cmp_{source_id}'.format(source_id=source_id)
source = os.path.join(root, fname)
source_id = 'f_{}'.format(md5(source.encode('utf8')).hexdigest())
component_ids.append(source_id)
if self.arch == 'x64':
file_ = E.File(Id=file_id, KeyPath='yes', Source=source, ProcessorArchitecture='x64')
component = E.Component(file_, Id=component_id, Guid='*', Win64='yes')
file_ = E.File(Id=source_id, Name=fname, Source=source, ProcessorArchitecture='x64')
component = E.Component(file_, Id=source_id, Guid='*', DiskId='1', Win64='yes')
else:
file_ = E.File(Id=file_id, KeyPath='yes', Source=source)
component = E.Component(file_, Id=component_id, Guid='*')
file_ = E.File(Id=source_id, Name=fname, Source=source)
component = E.Component(file_, Id=source_id, Guid='*', DiskId='1')
if source.endswith('OpenLP.exe'):
description = 'Firewall exception for OpenLP\'s remote interface (UDP)'
program = '[#file_e368869eb54b01e2288a3359b1cf51f8]'
component.append(FxE.FirewallException(Id='OpenLP_TCP', Name='OpenLP',
Description=description, IgnoreFailure='yes',
Program=program, Protocol='tcp', Scope='any'))
component.append(FxE.FirewallException(Id='OpenLP_UDP', Name='OpenLP',
Description=description, IgnoreFailure='yes',
Program=program, Protocol='udp', Scope='any'))
# Add the file association XML
config_dir = os.path.dirname(self.config_path)
with open(os.path.join(config_dir, 'file-associations.xml')) as assoc_file:
file_assoc = parse(assoc_file)
component.append(file_assoc.getroot())
self._openlp_id = source_id
file_.set('KeyPath', 'yes')
fw_program = '[#{}]'.format(source_id)
component.append(FxE.FirewallException(Id='OpenLP_TCP', Name='$(var.ProductName)',
IgnoreFailure='yes', Program=fw_program,
Protocol='tcp', Scope='any'))
component.append(FxE.FirewallException(Id='OpenLP_UDP', Name='$(var.ProductName)',
IgnoreFailure='yes', Program=fw_program,
Protocol='udp', Scope='any'))
component.append(E.Shortcut(Id='ApplicationStartMenuShortcut', Name='$(var.ProductName)',
Description='$(var.Description)', Directory='ProgramMenuDir',
Icon='OpenLP.ico', Advertise='yes', WorkingDirectory='INSTALLDIR'))
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)
components.append(component)
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
return component_ids
def _create_wix_file(self):
"""
@ -195,27 +214,40 @@ class WindowsBuilder(Builder):
self._print_verbose('Reading base WiX file')
with open(os.path.join(config_dir, 'OpenLP-base.wxs'), 'rt') as base_file:
xml = base_file.read()
progfilefolder = 'ProgramFiles64Folder' if self.arch == 'x64' else 'ProgramFilesFolder'
# convert the version string to format x.x.x if needed
if '.dev' in self.version:
windows_version = self.version.replace('.dev', '.')
windows_version = windows_version.rsplit('+', 1)[0]
else:
windows_version = self.version
xml = xml % dict(dialog=os.path.join(config_dir, 'WizardMain.bmp'),
banner=os.path.join(config_dir, 'WizardBanner.bmp'),
platform=self.arch,
progfilefolder=progfilefolder,
version=windows_version)
tree = fromstring(xml.encode('utf8'))
xml = xml % {
'dialog': os.path.join(config_dir, 'WizardMain.bmp'),
'banner': os.path.join(config_dir, 'WizardBanner.bmp'),
'license': os.path.join(config_dir, 'LICENSE.rtf'),
'platform': self.arch,
'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')
fragments = self._get_fragments_from_files(self.dist_path)
self._print_verbose('Inserting XML fragments into base WiX file')
for fragment in fragments:
tree.append(fragment)
component_ids = self._get_dirs_and_files(install_dir, self.dist_path)
# Write the property for the "Run OpenLP" checkbox
product = root.xpath('//wix:Product',
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')
tree = ElementTree(root)
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):
"""

3
pyinstaller-hooks/hook-openlp.py

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

36
windows/OpenLP-base.wxs

@ -10,16 +10,14 @@
<?define UpgradeCode="8C5881AC-8F1E-4937-BB99-B823FABF18F0"?>
<?define Platform="%(platform)s"?>
<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)"
Manufacturer="$(var.Manufacturer)" InstallerVersion="251" Languages="1033" Compressed="yes"
SummaryCodepage="1252" Platform="$(var.Platform)"/>
Manufacturer="$(var.Manufacturer)" InstallerVersion="400" Compressed="yes" Platform="$(var.Platform)"/>
<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="ARPPRODUCTICON" Value="OpenLP.ico" />
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch $(var.ProductName)" />
<Property Id="WixShellExecTarget" Value="[#file_e368869eb54b01e2288a3359b1cf51f8]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<UIRef Id="WixUI_Common" />
<UI Id="WixUI_OpenLP">
@ -63,31 +61,13 @@
<WixVariable Id="WixUIBannerBmp" Value="%(banner)s" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="%(progfilefolder)s">
<Directory Id="INSTALLDIR" Name="$(var.ProductName)"/>
<Directory Id="INSTALLDIR" Name="$(var.ProductName)"/>
</Directory>
<Directory Id="ProgramMenuFolder" Name="Programs">
<Directory Id="ProgramMenuDir" Name="$(var.ProductName)">
<Component Id="ProgramMenuDir" Guid="{7AABE54C-5B03-4049-AA85-E18B787A19C7}">
<RemoveFolder Id="ProgramMenuDir" On="uninstall" />
<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"
Name="$(var.ProductName) on the Web"
Target="http://openlp.org/"/>
@ -96,7 +76,7 @@
Target="http://forums.openlp.org/"/>
<Shortcut Id="UninstallProduct"
Name="Uninstall $(var.ProductName)"
Target="[SystemFolder]msiexec.exe"
Target="[%(systemfolder)s]msiexec.exe"
Arguments="/x [ProductCode]"
Description="Removes $(var.ProductName) from your computer" />
</Component>
@ -104,12 +84,8 @@
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
</Directory>
<DirectoryRef Id="INSTALLDIR">
<Directory Id="RootDirectory" Name="$(var.ProductName)" />
</DirectoryRef>
<Feature Id="Complete" Title="Complete" Description="The $(var.ProductName) program files" Level="0"
<Feature Id="Complete" Title="Complete" Description="The $(var.ProductName) program files" Level="1"
ConfigurableDirectory="INSTALLDIR" AllowAdvertise="no" InstallDefault="local" Absent="disallow">
<ComponentGroupRef Id="Files"/>
<ComponentRef Id="ProgramMenuDir"/>
</Feature>
<Icon Id="OpenLP.ico" SourceFile="OpenLP.ico"/>

10
windows/file-associations.xml

@ -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>
Loading…
Cancel
Save