Skip to content

build on develop branch #49

build on develop branch

build on develop branch #49

name: Build windows executable (.msi)
on:
push:
branches:
- main
pull_request:
branches: [ "main" ]
workflow_dispatch:
env:
PYTHON_VERSION: 3.10.0
# Define unique GUID for UpgradeCode
APP_UpgradeCode: "c1c7c11f-b063-4100-9854-af555d1b26d1"
# Define needed TOPP tools need in NuXLApp
TOPP_TOOLS: "OpenNuXL FileConverter PercolatorAdapter TextExporter FileInfo"
# App name
APP_NAME: OpenMS-NuXLApp
jobs:
build-executable:
runs-on: windows-2022
env:
PYTHON_VERSION: 3.10.0
APP_NAME: OpenMS-NuXLApp
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download OpenMS release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
gh release download openms-package_develop_26_03_2026 \
--repo Arslan-Siraj/nuxl_webapp_supporting_files \
--pattern "*.zip"
- name: Verify downloaded file
shell: bash
run: |
ls -lh
file *.zip
unzip -t *.zip
- name: Extract OpenMS package
shell: bash
run: |
unzip *.zip -d openms-package
ls -R openms-package
- name: Extract inner OpenMS package
shell: bash
run: |
unzip \
openms-package/openms-package/OpenMS/bld/openms-package.zip \
-d openms-inner
- name: Promote OpenMS bin and share to root
shell: bash
run: |
mkdir -p openms-bin openms-share
cp -r openms-inner/openms-package/bin/* openms-bin/
cp -r openms-inner/openms-package/share/* openms-share/
- name: Set up Python (regular distribution)
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }} # Use the same version as the embeddable version
- name: Setup python embeddable version
run: |
# Create a directory for the embeddable Python version
mkdir python-${{ env.PYTHON_VERSION }}
# Download and unzip the embeddable Python version
curl -O https://www.python.org/ftp/python/${{ env.PYTHON_VERSION }}/python-${{ env.PYTHON_VERSION }}-embed-amd64.zip
unzip python-${{ env.PYTHON_VERSION }}-embed-amd64.zip -d python-${{ env.PYTHON_VERSION }}
rm python-${{ env.PYTHON_VERSION }}-embed-amd64.zip
# Define paths for the regular Python distribution and the embeddable distribution
$PYTHON_DIR="${{ runner.tool_cache }}/Python/${{ env.PYTHON_VERSION }}/x64" # Path from actions/setup-python
$EMBED_DIR="python-${{ env.PYTHON_VERSION }}"
mkdir -p $EMBED_DIR/Lib/site-packages/tkinter
mkdir -p $EMBED_DIR/tcl
# Copy necessary Tkinter files from the regular Python distribution
cp -r $PYTHON_DIR/Lib/tkinter/* $EMBED_DIR/Lib/site-packages/tkinter/
cp -r $PYTHON_DIR/tcl/* $EMBED_DIR/tcl/
cp $PYTHON_DIR/DLLs/_tkinter.pyd $EMBED_DIR/
cp $PYTHON_DIR/DLLs/tcl86t.dll $EMBED_DIR/
cp $PYTHON_DIR/DLLs/tk86t.dll $EMBED_DIR/
- name: Bundle MSVC runtime DLLs
shell: powershell
run: |
$embed = "python-${{ env.PYTHON_VERSION }}"
$dlls = @(
"vcomp140.dll",
"vcruntime140.dll",
"vcruntime140_1.dll",
"msvcp140.dll"
)
foreach ($dll in $dlls) {
Copy-Item "C:\Windows\System32\$dll" "$embed\$dll" -Force
}
- name: Install pip
run: |
curl -O https://bootstrap.pypa.io/get-pip.py
./python-${{ env.PYTHON_VERSION }}/python get-pip.py --no-warn-script-location
rm get-pip.py
- name: Uncomment 'import site' in python310._pth file
run: |
sed -i 's/#import site/import site/' python-${{ env.PYTHON_VERSION }}/python310._pth
#- name: Install Required Packages
# run: .\python-${{ env.PYTHON_VERSION }}\python -m pip install --force-reinstall -r requirements_embd_py310_win.txt --no-warn-script-location
- name: Set to offline deployment
run: |
$content = Get-Content -Raw settings.json | ConvertFrom-Json
$content.online_deployment = $false
$content | ConvertTo-Json -Depth 100 | Set-Content settings.json
- name: Create launcher .bat file
shell: pwsh
run: |
$batContent = @"
@echo off
set PYTHON=.\python-3.10.0\python
set REQ=.\requirements_embd_py310_win.txt
set MARKER=.\python-3.10.0\.deps_installed
set FILE=.\python-3.10.0\Lib\site-packages\nuxl_rescore\run.py
REM If marker exists, skip installation
if exist "%MARKER%" goto RUN_APP
echo Preparing Python environment for launching App...
REM Ensure pip exists
"%PYTHON%" -m ensurepip >nul 2>&1
REM Attempt installation
"%PYTHON%" -m pip install -r "%REQ%" --no-warn-script-location
if errorlevel 1 (
echo Dependency installation failed or was interrupted.
exit /b 1
)
REM Copy NuXL share folder to pyopenms share
xcopy /E /I /Y ".\NuXL" ".\python-3.10.0\Lib\site-packages\pyopenms\share\OpenMS\NuXL"
REM Rename folder
ren "streamlit" ".streamlit"
REM Remove unwanted import line from run.py
echo Checking file...
if not exist "%FILE%" (
echo ERROR: File not found: %FILE%
pause
exit /b 1
)
echo Removing line...
powershell -NoProfile -ExecutionPolicy Bypass -Command "(Get-Content '%FILE%') | Where-Object { $_ -ne 'from pkg_resources import get_distribution' } | Set-Content '%FILE%'"
if errorlevel 1 (
echo ERROR: PowerShell command failed.
pause
exit /b 1
)
REM Create marker only after full success
echo OK>"%MARKER%"
:RUN_APP
start /min "" "%PYTHON%" -m streamlit run app.py
"@
$batContent | Set-Content -Encoding ASCII "${{ env.APP_NAME }}.bat"
- name: Verify .streamlit folder exists
shell: bash
run: |
echo "PWD:"
pwd
echo "Listing repo root:"
ls -la
echo "Listing .streamlit:"
ls -la .streamlit
- name: Create All-in-one executable folder
shell: bash
run: |
if [ -d "streamlit_exe" ]; then
rm -rf streamlit_exe
fi
mkdir -p streamlit_exe
mv python-${{ env.PYTHON_VERSION }} streamlit_exe
cp -r src streamlit_exe
cp -r content streamlit_exe
cp -r assets streamlit_exe
#cp -r example-data streamlit_exe
cp app.py streamlit_exe
cp settings.json streamlit_exe
cp ${{ env.APP_NAME }}.bat streamlit_exe
cp requirements_embd_py310_win.txt streamlit_exe
mkdir -p streamlit_exe streamlit_exe/share
# Copy all DLLs from openms-bin
cp -r openms-bin/*.dll streamlit_exe/
# Copy share folder
cp -r openms-share/* streamlit_exe/share/
cp -r openms-share/OpenMS/NuXL streamlit_exe/NuXL/
# copy chemistry outside
cp -r openms-share/OpenMS/CHEMISTRY streamlit_exe/
# Copy only selected .exe files from openms-bin
for tool in $TOPP_TOOLS; do
if [ -f "openms-bin/$tool.exe" ]; then
cp "openms-bin/$tool.exe" streamlit_exe/
else
echo "Warning: $tool.exe not found in openms-bin"
fi
done
# copy thirdparty folder
cp -r openms-package/openms-package/_thirdparty streamlit_exe/
- name: Create Streamlit config
shell: bash
run: |
mkdir -p streamlit_exe/streamlit
cat <<'EOF' > streamlit_exe/streamlit/config.toml
[global]
developmentMode = false
[server]
maxUploadSize = 50000
port = 8505
[theme]
primaryColor = "#29379b"
EOF
- name: Generate Readme.txt
shell: bash
run: |
cat <<EOF > streamlit_exe/Readme.txt
Welcome to ${{ env.APP_NAME }} app!
To launch the application:
1. Navigate to the installation directory.
2. Double-click on the file: ${{ env.APP_NAME }}.bat or ${{ env.APP_NAME }} shortcut.
Additional Information:
- If multiple Streamlit apps are running, you can change the port in the .streamlit/config.toml file.
Example:
[server]
port = 8505
Reach out to us:
- Join our Discord server for support and community discussions: https://discord.com/invite/4TAGhqJ7s5
- Contribute or stay updated with the latest OpenMS web app developments on GitHub: https://github.com/OpenMS/streamlit-template
- Checkout the ${{ env.APP_NAME }} on Github: https://github.com/Arslan-Siraj/nuxl-app
- Visit our website for more information: https://openms.de/
Thanks for using ${{ env.APP_NAME }}!
EOF
- name: Install WiX Toolset
run: |
curl -LO https://github.com/wixtoolset/wix3/releases/download/wix3111rtm/wix311-binaries.zip
unzip wix311-binaries.zip -d wix
rm wix311-binaries.zip
- name: Build .wxs for streamlit_exe folder
run: |
./wix/heat.exe dir streamlit_exe -gg -sfrag -sreg -srd -template component -cg StreamlitExeFiles -dr AppSubFolder -out streamlit_exe_files.wxs
- name: Generate VBScript file
shell: bash
run: |
cat <<EOF > ShowSuccessMessage.vbs
MsgBox "The ${{ env.APP_NAME }} application is successfully installed.", vbInformation, "Installation Complete"
EOF
- name: Prepare SourceDir
run: |
if (Test-Path -Path "SourceDir") {
Remove-Item -Recurse -Force "SourceDir"
}
mkdir SourceDir
mv streamlit_exe/* SourceDir
cp ShowSuccessMessage.vbs SourceDir
cp assets/openms_license.rtf SourceDir
# Logo of app : from https://www.xiconeditor.com/
cp assets/openNuXL.ico SourceDir
- name: Generate WiX XML file
shell: bash
run: |
cat <<EOF > streamlit_exe.wxs
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="${{ env.APP_NAME }}" Language="1033" Version="1.0.0.0" Codepage="1252" Manufacturer="OpenMS Developer Team" UpgradeCode="${{ env.APP_UpgradeCode }}">
<Package Id="*" InstallerVersion="300" Compressed="yes" InstallPrivileges="elevated" Platform="x64" />
<Media Id="1" Cabinet="streamlit.cab" EmbedCab="yes" />
<!-- Folder structure -->
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="${{ env.APP_NAME }}">
<Directory Id="AppSubFolder" Name="${{ env.APP_NAME }}" />
<Component Id="CreateAppFolder" Guid="95dbfa06-d36a-427f-995c-e87769ac2e59">
<CreateFolder>
<Permission User="Everyone" GenericAll="yes" />
</CreateFolder>
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" />
</Directory>
<!-- Add components -->
<Feature Id="MainFeature" Title="Main Application" Level="1">
<ComponentGroupRef Id="StreamlitExeFiles" />
<ComponentRef Id="CreateAppFolder" />
<ComponentRef Id="DesktopShortcutComponent" />
<ComponentRef Id="InstallDirShortcutComponent" />
</Feature>
<!-- Create shortcut for running app on desktop -->
<Component Id="DesktopShortcutComponent" Guid="3597b243-9180-4d0b-b105-30d8b0d1a334" Directory="DesktopFolder">
<Shortcut Id="DesktopShortcut" Name="${{ env.APP_NAME }}" Description="Launch ${{ env.APP_NAME }}" Target="[AppSubFolder]${{ env.APP_NAME }}.bat" WorkingDirectory="AppSubFolder" Icon="AppIcon" />
<RegistryValue Root="HKCU" Key="Software\\OpenMS\\${{ env.APP_NAME }}" Name="DesktopShortcut" Type="integer" Value="1" KeyPath="yes" />
</Component>
<!-- Create shortcut for running app in installer folder -->
<Component Id="InstallDirShortcutComponent" Guid="c2df9472-3b45-4558-a56d-6034cf7c8b72" Directory="AppSubFolder">
<Shortcut Id="InstallDirShortcut" Name="${{ env.APP_NAME }}" Description="Launch ${{ env.APP_NAME }}" Target="[AppSubFolder]${{ env.APP_NAME }}.bat" WorkingDirectory="AppSubFolder" Icon="AppIcon" />
<RegistryValue Root="HKCU" Key="Software\\OpenMS\\${{ env.APP_NAME }}" Name="InstallFolderShortcut" Type="integer" Value="1" KeyPath="yes" />
</Component>
<!-- Provide icon here; it should exist in the SourceDir folder -->
<Icon Id="AppIcon" SourceFile="SourceDir/openNuXL.ico" />
<!-- Run app directly after installation -->
<!-- <CustomAction Id="RunApp" Directory="AppSubFolder" Execute="deferred" Return="asyncNoWait" Impersonate="no"
ExeCommand="cmd.exe /c &quot;[AppSubFolder]${{ env.APP_NAME }}.bat&quot;" /> -->
<!-- Custom Action to Show Success Message -->
<Binary Id="ShowMessageScript" SourceFile="SourceDir/ShowSuccessMessage.vbs" />
<CustomAction Id="ShowSuccessMessage" BinaryKey="ShowMessageScript" VBScriptCall="" Execute="immediate" Return="check" />
<!-- Add all Custom Actions -->
<InstallExecuteSequence>
<!-- Custom action display success message -->
<Custom Action="ShowSuccessMessage" After="InstallFinalize">NOT Installed</Custom>
<!-- Run app directly after installation -->
<!-- <Custom Action="RunApp" Before="InstallFinalize">NOT REMOVE</Custom> -->
</InstallExecuteSequence>
<!-- Interface options -->
<UI>
<UIRef Id="WixUI_InstallDir" />
<UIRef Id="WixUI_ErrorProgressText" />
</UI>
<!-- Provide license; it should exist in the SourceDir folder -->
<WixVariable Id="WixUILicenseRtf" Value="SourceDir/openms_license.rtf" />
</Product>
</Wix>
EOF
- name: Build .wixobj file with candle.exe
run: |
./wix/candle.exe streamlit_exe.wxs streamlit_exe_files.wxs
- name: Link .wixobj file into .msi with light.exe
run: |
./wix/light.exe -ext WixUIExtension -sice:ICE60 -o ${{ env.APP_NAME }}.msi streamlit_exe_files.wixobj streamlit_exe.wixobj
#- name: Compress Installer
# run: |
# 7z a ${{ env.APP_NAME }}.zip
- name: Archive build artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.APP_NAME }}
path: |
${{ env.APP_NAME }}.msi