Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
cd04957
First draft of installer creation workflow
damskii9992 Oct 15, 2025
9b92593
Trigger the workflow once.
damskii9992 Oct 15, 2025
2cd45ca
Add flag to uv call to install on system env
damskii9992 Oct 15, 2025
00d6991
Set working directory to imaging-app when running pyinstaller
damskii9992 Oct 15, 2025
903233b
Update the EasyApp branch dependency
damskii9992 Oct 16, 2025
3a7e606
Add linux libraries
damskii9992 Oct 16, 2025
c76792c
Try different linux libs
damskii9992 Oct 16, 2025
3fe3be3
Downgrade pyinstaller on MacOS
damskii9992 Oct 16, 2025
c79753c
Wrong syntax for uv pip
damskii9992 Oct 16, 2025
b21cd98
Add QtInstaller folders
damskii9992 Oct 16, 2025
beee197
Add qt installer to build workflow
damskii9992 Oct 17, 2025
1bf93c6
Qt dependencies pulled in by Qt installer step, fixed wrong path.
damskii9992 Oct 17, 2025
fe4f2ea
Test paths on GH runners
damskii9992 Oct 17, 2025
aefab15
Use Qt Tools env var rather than Qt bin env var
damskii9992 Oct 17, 2025
5da48bc
Check paths (again)
damskii9992 Oct 17, 2025
aad2c38
Specify Qt installer version
damskii9992 Oct 17, 2025
ffebd2d
Qt Installer framework is only version 4.7 with aqtinstall
damskii9992 Oct 17, 2025
b537d70
Ammen windows paths
damskii9992 Oct 17, 2025
2d2174d
Try codesigning on Windows
damskii9992 Oct 20, 2025
08aba77
Could not find file, try again
damskii9992 Oct 20, 2025
eb579be
Try MacOS fix
damskii9992 Oct 20, 2025
36da354
Fix icon env variable
damskii9992 Oct 20, 2025
290f958
Upload app not terminal executable
damskii9992 Oct 21, 2025
f1d97f4
wrong name for macOS
damskii9992 Oct 21, 2025
03b06eb
Fix copilot misshap
damskii9992 Oct 21, 2025
45bb856
Full Build
damskii9992 Oct 21, 2025
68c8bbe
Fix icon path on windows
damskii9992 Oct 21, 2025
c6938c6
Remove the automatic run when pushing to non-master branch
damskii9992 Oct 21, 2025
6a1c920
Minor changes to installer.
damskii9992 Oct 21, 2025
8b8159c
Update icons
damskii9992 Oct 21, 2025
b401219
Increase resolution of icons
damskii9992 Oct 21, 2025
51bdcec
Trigger new build with updated icons.
Oct 22, 2025
e80f757
Remove trigger on push to non-master branch
Oct 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions .github/workflows/Create_installer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
name: Build installer

on:
workflow_dispatch:
push:
branches:
- 'master'

jobs:
build_pyinstaller:
runs-on: ${{ matrix.os }}
strategy:
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable.
fail-fast: false

# Build on the following 4 configurations:
# 1. <Windows, Release, 2022 MSVC compiler toolchain>
# 2. <Ubuntu latest, i.e. version 22.04, Release, GCC 11 compiler toolchain>
# 3. <MacOS 12 with x86-64 arch, Release, Clang 14 compiler toolchain>
# 4. <MacOS 14 with arm64 arch, Release, Clang 15 compiler toolchain
# To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the list.
matrix:
os: [windows-2022, ubuntu-22.04, macos-14, macos-15-intel]

steps:
- name: Checkout EasyImaginApp
uses: actions/checkout@v5
with:
path: imaging-app

- name: Checkout EasyApp
uses: actions/checkout@v5
with:
repository: EasyScience/EasyApp
ref: 'Fix_wrong_application_types'
path: EasyApp

- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: '3.12'

- name: Install uv
run: |
python -m pip install --upgrade pip
pip install uv

- name: Install dependencies
shell: bash
run: uv pip install -r imaging-app/pyproject.toml --extra ci --system

- name: Install Qt Installer Framework
uses: jurplel/install-qt-action@v4
with:
version: '6.9.3'
dir: '${{GITHUB.WORKSPACE}}'
install-deps: 'true'
tools: 'tools_ifw'
no-qt-binaries: 'true'

- name: Set icon environment variable
shell: bash
run: |
if [ "${{ runner.os }}" == "Windows" ]; then
echo "ICON_PATH=EasyImagingApp/Gui/Resources/Logos/App.ico" >> $GITHUB_ENV
else
echo "ICON_PATH=EasyImagingApp/Gui/Resources/Logos/App.icns" >> $GITHUB_ENV
fi

- name: Build with pyinstaller
working-directory: imaging-app
shell: bash
run: |
pyinstaller EasyImagingApp/main.py --onedir --windowed --name EasyImaging --icon ${{ env.ICON_PATH }} \
--clean --noconfirm \
--add-data=EasyImagingApp:. --collect-submodules PySide6 --collect-all scitiff --collect-all easyscience --collect-all EasyApp

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
path: imaging-app/dist/EasyImaging
name: EasyImaging-${{ matrix.os }}

- name: Prepare creation of installer
working-directory: imaging-app/Installer
shell: bash
run: |
if [ "${{ runner.os}}" == "macOS" ]; then
cp -r ../dist/EasyImaging.app packages/core/data/
else
cp -r ../dist/EasyImaging/* packages/core/data/
fi

- name: Create installers (Windows)
if: runner.os == 'Windows'
working-directory: imaging-app\Installer
run: |
${{env.IQTA_TOOLS}}\QtInstallerFramework\4.7\bin\binarycreator.exe -c config\config.xml -p packages ${{runner.os}}-${{runner.arch}}_EasyImaging_Installer.exe

- name: Create installers (Linux & MacOS)
if: runner.os != 'Windows'
working-directory: imaging-app/Installer
run: |
${{env.IQTA_TOOLS}}/QtInstallerFramework/4.7/bin/binarycreator -c config/config.xml -p packages ${{runner.os}}-${{runner.arch}}_EasyImaging_Installer

- name: Install DigiCert Client tools from Github Custom Actions marketplace
if: runner.os == 'windows'
uses: digicert/ssm-code-signing@v1.1.0

- name: Set up P12 certificate
if: runner.os == 'windows'
shell: bash
run: echo "${{ secrets.WINDOWS_CERT_DATA }}" | base64 --decode > /d/Certificate_pkcs12.p12

- name: Set keylocker variables
if: runner.os == 'windows'
shell: bash
run: |
echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
echo "SM_HOST=${{ secrets.KEYLOCKER_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.KEYLOCKER_API_KEY }}" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.WINDOWS_CERT_PASSWORD }}" >> "$GITHUB_ENV"

- name: Sign the binary using keypair alias
if: runner.os == 'windows'
shell: cmd
run: smctl sign --keypair-alias key_911959544 --input imaging-app\Installer\${{runner.os}}-${{runner.arch}}_EasyImaging_Installer.exe

- name: Upload installers
uses: actions/upload-artifact@master
with:
name: EasyImaging-installer-${{runner.os}}-${{runner.arch}}
path: imaging-app/Installer/*EasyImaging_Installer*
Binary file modified EasyImagingApp/Gui/Resources/Logos/App.icns
Binary file not shown.
Binary file modified EasyImagingApp/Gui/Resources/Logos/App.ico
Binary file not shown.
Binary file modified EasyImagingApp/Gui/Resources/Logos/App.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 1 addition & 27 deletions EasyImagingApp/Gui/Resources/Logos/App.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions EasyImagingApp/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine, qmlRegisterSingletonType
from PySide6.QtCore import qInstallMessageHandler
from PySide6.QtGui import QIcon

# It is usually assumed that the EasyApp package is already installed in the desired python environment.
# If this is not the case, and if the example is run from the EasyApp repository, one need to add the path to the
Expand Down Expand Up @@ -37,6 +38,7 @@

app = QApplication(sys.argv)
console.debug(f'Qt Application created {app}')
app.setWindowIcon(QIcon(str(CURRENT_DIR / 'Gui' / 'Resources' / 'Logos' / 'App.svg')))

engine = QQmlApplicationEngine()
console.debug(f'QML application engine created {engine}')
Expand Down
14 changes: 14 additions & 0 deletions Installer/config/config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<Installer>
<Name>EasyImaging</Name>
<Version>0.0.1</Version>
<Title>EasyImaging Installer</Title>
<Publisher>ESS DMSC</Publisher>
<InstallerWindowIcon>../../EasyImagingApp/Gui/Resources/Logos/App.png</InstallerWindowIcon>
<InstallerApplicationIcon>../../EasyImagingApp/Gui/Resources/Logos/App</InstallerApplicationIcon>
<StartMenuDir>EasyImaging</StartMenuDir>
<TargetDir>@ApplicationsDirUser@/EasyImaging</TargetDir>
<WizardStyle>Modern</WizardStyle>
<ControlScript>controllerscript.js</ControlScript>
<MaintenanceToolName>EasyImaging Maintenance Tool</MaintenanceToolName>
</Installer>
16 changes: 16 additions & 0 deletions Installer/config/controllerscript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// This is the script which handles the parts of the installer not related to any of the packages.


function Controller()
{
if (systemInfo.productType === "windows") {
installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false);
}

}

Controller.prototype.IntroductionPageCallback = function()
{
gui.clickButton(buttons.NextButton);
}

2 changes: 2 additions & 0 deletions Installer/packages/core/data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
29 changes: 29 additions & 0 deletions Installer/packages/core/meta/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2024, EasyImaging contributors (https://github.com/easyscience/imaging-app).
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 changes: 28 additions & 0 deletions Installer/packages/core/meta/customintroductionpage.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Page</class>
<widget class="QWidget" name="CustomIntroductionPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Welcome</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="m_pageLabel">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
127 changes: 127 additions & 0 deletions Installer/packages/core/meta/installscript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the FOO module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

var Dir = new function () {
this.toNativeSparator = function (path) {
if (systemInfo.kernelType === "winnt")
return path.replace(/\//g, '\\');
return path;
}
};

function Component() {
// constructor
if (installer.isInstaller()) {
component.loaded.connect(this, Component.prototype.loaded);
}
}

Component.prototype.loaded = function () {
if (installer.addWizardPage(component, "CustomIntroductionPage", QInstaller.TargetDirectory)) {
var page = gui.pageByObjectName("DynamicCustomIntroductionPage");
if (page != null) {
page.entered.connect(Component.prototype.dynamicCustromIntroductionPageEntered);
}
}
console.log("component loaded");
if (systemInfo.kernelType === "winnt") {
console.log("System is windows")
if (installer.addWizardPage(component, "ShortcutWidget", QInstaller.StartMenuSelection)) {
var widget = gui.pageWidgetByObjectName("DynamicShortcutWidget");
if (widget != null) {
widget.createDesktopShortcut.checked = true;
widget.createStartMenuShortcut.checked = true;

widget.windowTitle = "Create shortcuts";
}
}
} else if (systemInfo.kernelType == "linux") {
console.log("System is linux");
if (installer.addWizardPage(component, "SymlinkWidget", QInstaller.StartMenuSelection)) {
var widget = gui.pageWidgetByObjectName("DynamicSymlinkWidget");
if (widget != null) {
widget.createDesktopShortcut.checked = true;
widget.createUserLink.checked = true;
widget.createSystemLink.checked = false;

widget.windowTitle = "Create shortcuts";
}
}
}
}

Component.prototype.dynamicCustromIntroductionPageEntered = function ()
{
var pageWidget = gui.pageWidgetByObjectName("DynamicCustomIntroductionPage");
if (pageWidget != null) {
pageWidget.m_pageLabel.text = "Welcome to the EasyImaging setup.";
installer.setDefaultPageVisible(QInstaller.Introduction, false);
}
}

Component.prototype.createOperations = function()
{
try {
// call the base create operations function
component.createOperations();
} catch (e) {
console.log(e);
}

if (systemInfo.kernelType === "winnt") {
var shortcutpage = component.userInterface("ShortcutWidget");
if (shortcutpage && shortcutpage.createDesktopShortcut.checked) {
component.addElevatedOperation("CreateShortcut", "@TargetDir@/EasyImaging.exe", "@DesktopDir@/EasyImaging.lnk");
}
if (shortcutpage && shortcutpage.createStartMenuShortcut.checked) {
component.addElevatedOperation("CreateShortcut", "@TargetDir@/EasyImaging.exe", "@UserStartMenuProgramsPath@/@StartMenuDir@/EasyImaging.lnk",
"workingDirectory=@TargetDir@");
}
} else if (systemInfo.kernelType === "linux") {
var shortcutpage = component.userInterface("SymlinkWidget");
if (shortcutpage && shortcutpage.createDesktopShortcut.checked) {
component.addOperation("CreateDesktopEntry", "@HomeDir@/.local/share/applications/EasyImaging.desktop",
"Type=Application\n"+
"Name=EasyImaging\n"+
"Comment=Neutron imaging Bragg-edge analysis software\n"+
"Exec=@TargetDir@/EasyImaging\n"+
"Icon=@TargetDir@/_internal/Gui/Resources/Logos/App.svg\n"+
"Categories=Science"
);

}
if (shortcutpage && shortcutpage.createUserLink.checked) {
console.log("Creating Symlinks in @HomeDir@/.local/bin");
component.addOperation("CreateLink", "@HomeDir@/.local/bin/easyimaging", "@TargetDir@/EasyImaging");
}
if (shortcutpage && shortcutpage.createSystemLink.checked) {
console.log("Creating Symlinks in @RootDir@usr/local/bin");
component.addElevatedOperation("CreateLink", "@RootDir@usr/local/bin/easyimaging", "@TargetDir@/EasyImaging");
}
}
}
19 changes: 19 additions & 0 deletions Installer/packages/core/meta/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<Package>
<DisplayName>EasyImaging core components</DisplayName>
<Name>core</Name>
<Description>The core components critical to running EasyImaging</Description>
<Version>0.0.1</Version>
<ReleaseDate>2025-10-16</ReleaseDate>
<Licenses>
<License name="BSD 3-Clause License" file="LICENSE" />
</Licenses>
<Default>false</Default>
<ForcedInstallation>true</ForcedInstallation>
<Script>installscript.js</Script>
<UserInterfaces>
<UserInterface>customintroductionpage.ui</UserInterface>
<UserInterface>shortcutwidget.ui</UserInterface>
<UserInterface>symlinkwidget.ui</UserInterface>
</UserInterfaces>
</Package>
Loading