← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~raoul-snyman/openlp/wix-packaging into lp:openlp/packaging

 

Raoul Snyman has proposed merging lp:~raoul-snyman/openlp/wix-packaging into lp:openlp/packaging.

Commit message:
Mostly a proof of concept. I'd like to see if I can get this set up in AppVeyor sometime.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~raoul-snyman/openlp/wix-packaging/+merge/365717
-- 
Your team OpenLP Core is requested to review the proposed merge of lp:~raoul-snyman/openlp/wix-packaging into lp:openlp/packaging.
=== modified file 'builders/builder.py'
--- builders/builder.py	2019-02-18 20:10:59 +0000
+++ builders/builder.py	2019-04-09 06:17:13 +0000
@@ -1,5 +1,5 @@
 # -*- 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                                      #
@@ -276,8 +276,11 @@
         """
         self._print('Running PyInstaller...')
         os.chdir(self.work_path)
-        cmd = [self.python,
-               self.pyinstaller_exe,
+        if self.pyinstaller_exe.endswith('.py'):
+            cmd = [self.python, self.pyinstaller_exe]
+        else:
+            cmd = [self.pyinstaller_exe]
+        cmd.extend([
                '--clean',
                '--noconfirm',
                '--windowed',
@@ -287,7 +290,8 @@
                '-i', self.icon_path,
                '-n', 'OpenLP',
                *self.get_extra_parameters(),  # Adds any extra parameters we wish to use
-               self.openlp_script]
+               self.openlp_script
+        ])
         if self.args.verbose:
             cmd.append('--log-level=DEBUG')
         else:

=== modified file 'builders/windows-builder.py'
--- builders/windows-builder.py	2019-03-13 21:00:05 +0000
+++ builders/windows-builder.py	2019-04-09 06:17:13 +0000
@@ -114,8 +114,15 @@
 from distutils import dir_util
 from shutil import copy, move, rmtree
 
+from lxml.etree import fromstring, tostring
+from lxml.builder import E
+
 from builder import Builder
 
+BLACKLIST = [
+    'pptviewlib.dll.intermediate.manifest'
+]
+
 
 class WindowsBuilder(Builder):
     """
@@ -123,29 +130,95 @@
     to build a Windows installer.
     """
 
-    def _create_innosetup_file(self):
-        """
-        Create an InnoSetup file pointing to the branch being built.
-        """
-        self._print('Creating Inno Setup file...')
-        config_dir = os.path.dirname(self.config_path)
-        with open(os.path.join(config_dir, 'OpenLP.iss.default'), 'r') as input_file, \
-                open(os.path.join(config_dir, 'OpenLP.iss'), 'w') as output_file:
-            content = input_file.read()
-            content = content.replace('%(branch)s', self.branch_path)
-            content = content.replace('%(display_version)s', self.version.replace('-bzr', '.'))
-            content = content.replace('%(arch)s', self.arch)
-            output_file.write(content)
-
-    def _run_innosetup(self):
-        """
-        Run InnoSetup to create an installer.
-        """
-        self._print('Running Inno Setup...')
-        config_dir = os.path.dirname(self.config_path)
-        os.chdir(config_dir)
-        self._run_command([self.innosetup_exe, os.path.join(config_dir, 'OpenLP.iss'), '/q'],
-                          'Error running InnoSetup')
+    def _walk_dirs(self, dir_dict, path):
+        """
+        Walk a dictionary according to path
+        """
+        parts = path.split(os.sep)
+        search_key = parts.pop(0)
+        if search_key in dir_dict.keys():
+            if not parts:
+                return dir_dict[search_key]
+            else:
+                return walk_dirs(dir_dict[search_key], os.sep.join(parts))
+        else:
+            return None
+
+    def _get_fragments_from_files(self, start_dir):
+        """
+        Walk down a directory recursively and build up the XML for WiX
+        """
+        start_base, start_path = os.path.split(start_dir)
+        element = E.DirectoryRef(Id='INSTALLDIR')
+        directories = {start_path: {'__dir__': element}}
+        components = []
+
+        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)
+                new_dir = {'__dir__': element}
+                parent_dir = walk_dirs(directories, parent)
+                parent_dir[base] = new_dir
+                parent_dir['__dir__'].append(element)
+            for fname in files:
+                if fname in BLACKLIST:
+                    continue
+                source = os.path.join(path, fname) if path else fname
+                file_id = 'file_{source}'.format(source=source.replace('-', '_').replace(os.sep, '_'))
+                file_ = E.File(Id=file_id, KeyPath="yes", Source=source)
+                component = E.Component(file_, Id='cmp_' + fixed_id, Guid='*')
+                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
+
+    def _create_wix_file(self):
+        """
+        Create a WiX project file
+        """
+        self._print('Creating WiX file...')
+        config_dir = os.path.dirname(self.config_path)
+        self._print_verbose('Reading base WiX file')
+        with open(os.path.join(config_dir, 'OpenLP-base.wxs'), 'rb') as base_file:
+            xml = base_file.read()
+        xml = xml.format(dialog=os.path.join(config_dir, 'WizardMain.bmp'),
+                         banner=os.path.join(config_dir, 'WizardBanner.bmp'))
+        tree = fromstring(xml)
+        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')
+        wix = base_tree.getroot()
+        for fragment in fragments:
+            wix.append(fragment)
+        self._print_verbose('Writing new WiX file')
+        with open(os.path.join(self.config_path, 'OpenLP.wxs'), 'wb') as f:
+            f.write(tostring(tree, encoding='utf-8', xml_declaration=True, pretty_print=True))
+
+    def _run_wix_tools(self):
+        """
+        Run the WiX toolset to create an installer
+        """
+        self._print('Running WiX tools...')
+        msi_file = os.path.join(self.dist_path, 'OpenLP-{}.msi'.format(self.version))
+        if msi_file:
+            self._print_verbose('Removing old MSI file')
+            os.unlink(msi_file)
+        config_dir = os.path.dirname(self.config_path)
+        os.chdir(self.dist_path)
+        self._run_command([self.candle_exe, '-ext', 'WiXUtilExtension', os.path.join(config_dir, 'OpenLP.wxs')],
+                          'Error running WiX tool: candle')
+        self._run_command([self.light_exe, '-ext', 'WiXUtilExtension', '-ext', 'WixUIExtension', 'OpenLP.wixobj',
+                           '-o', msi_file],
+                          'Error running WiX tool: light')
 
     def _create_portableapp_structure(self):
         """
@@ -333,8 +406,8 @@
         """
         Build the installer
         """
-        self._create_innosetup_file()
-        self._run_innosetup()
+        self._create_wix_file()
+        self._run_wix_tools()
         if self.args.portable:
             self._run_portableapp_builder()
 

=== added file 'windows/OpenLP-base.wxs'
--- windows/OpenLP-base.wxs	1970-01-01 00:00:00 +0000
+++ windows/OpenLP-base.wxs	2019-04-09 06:17:13 +0000
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi";
+     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension";>
+  <Product Name="OpenLP" Manufacturer="OpenLP" Id="{98092172-3875-47d3-8DBE-3EB0D5A57CE7}"
+    UpgradeCode="{8C5881AC-8F1E-4937-BB99-B823FABF18F0}" Language="1033" Codepage="1252" Version="2.5.0">
+    <Package Id="*" Keywords="Installer" Description="Free open source church worship presentation software"
+      Comments="OpenLP is open source under the GNU General Public License" Manufacturer="OpenLP Developers"
+      InstallerVersion="251" Languages="1033" Compressed="yes" SummaryCodepage="1252"/>
+    <Condition Message="You need to be an administrator to install this product.">Privileged</Condition>
+    <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 OpenLP" />
+    <Property Id="WixShellExecTarget" Value="[#file_OpenLP.exe]" />
+    <CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
+    <UI>
+      <UIRef Id="WixUI_InstallDir" />
+      <Publish Dialog="ExitDialog"
+        Control="Finish" 
+        Event="DoAction" 
+        Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
+    </UI>
+    <WixVariable Id="WixUILicenseRtf" Value="gpl-2.0.rtf" />
+    <WixVariable Id="WixUIDialogBmp" Value="{dialog}" />
+    <WixVariable Id="WixUIBannerBmp" Value="{banner}" />
+    <Directory Id="TARGETDIR" Name="SourceDir">
+      <Directory Id="ProgramFilesFolder">
+        <Directory Id="INSTALLDIR" Name="OpenLP"/>
+      </Directory>
+      <Directory Id="ProgramMenuFolder" Name="Programs">
+        <Directory Id="ProgramMenuDir" Name="OpenLP">
+          <Component Id="ProgramMenuDir" Guid="{7AABE54C-5B03-4049-AA85-E18B787A19C7}">
+            <RemoveFolder Id="ProgramMenuDir" On="uninstall" />
+            <RegistryValue Root="HKCU" Key="Software\OpenLP\OpenLP" Type="string" Value="" KeyPath="yes" />
+            <Shortcut Id="ApplicationStartMenuShortcut"
+              Name="OpenLP" 
+              Description="Open Source Worship Presentation Software"
+              Target="[#file_OpenLP.exe]"
+              Icon="OpenLP.ico"
+              WorkingDirectory="RootDirectory"/>
+            <Shortcut Id="DebugStartMenuShortcut"
+              Name="OpenLP (Debug)" 
+              Description="Run OpenLP with debug logging enabled"
+              Target="[#file_OpenLP.exe]"
+              Arguments="--log-level debug"
+              Icon="OpenLP.ico"
+              WorkingDirectory="RootDirectory"/>
+            <Shortcut Id="HelpStartMenuShortcut"
+              Name="OpenLP Help" 
+              Description="Help file for OpenLP"
+              Target="[#file_OpenLP.chm]"
+              WorkingDirectory="RootDirectory"/>
+            <util:InternetShortcut Id="OpenLPWebSite"
+              Name="OpenLP on the Web"
+              Target="http://openlp.org/"/>
+            <util:InternetShortcut Id="OpenLPForums"
+              Name="Get support for OpenLP"
+              Target="http://forums.openlp.org/"/>
+            <Shortcut Id="UninstallProduct"             
+              Name="Uninstall OpenLP"
+              Target="[SystemFolder]msiexec.exe"
+              Arguments="/x [ProductCode]"
+              Description="Removes OpenLP from your computer" />
+          </Component>
+        </Directory>
+      </Directory>
+      <Directory Id="DesktopFolder" Name="Desktop" />
+    </Directory>
+    <DirectoryRef Id="INSTALLDIR">
+      <Directory Id="RootDirectory" Name="OpenLP" />
+    </DirectoryRef>
+    <Feature Id="Complete" Title="Complete" Description="The OpenLP 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"/>
+  </Product>
+</Wix>

=== added file 'windows/WizardBanner.bmp'
Binary files windows/WizardBanner.bmp	1970-01-01 00:00:00 +0000 and windows/WizardBanner.bmp	2019-04-09 06:17:13 +0000 differ
=== added file 'windows/WizardMain.bmp'
Binary files windows/WizardMain.bmp	1970-01-01 00:00:00 +0000 and windows/WizardMain.bmp	2019-04-09 06:17:13 +0000 differ

Follow ups