|
1 | | -name: Test streamlit executable for Windows with embeddable python |
2 | | -on: |
| 1 | +name: Build Streamlit Windows Installer (Multi-CAB, Embeddable Python) |
| 2 | + |
| 3 | +on: |
3 | 4 | push: |
4 | 5 | branches: [ "main" ] |
5 | 6 | workflow_dispatch: |
6 | 7 |
|
7 | 8 | jobs: |
8 | | - build-win-executable-with-embeddable-python: |
| 9 | + build-win-installer: |
9 | 10 | runs-on: windows-2022 |
10 | 11 |
|
11 | 12 | env: |
12 | 13 | PYTHON_VERSION: 3.10.0 |
13 | | - APP_UpgradeCode: 4abc2e23-3ba5-40e4-95c9-09e6cb8ecaeb |
14 | 14 | APP_NAME: OpenMS-NuXLApp-Test |
| 15 | + APP_UpgradeCode: 4abc2e23-3ba5-40e4-95c9-09e6cb8ecaeb |
15 | 16 |
|
16 | 17 | steps: |
17 | | - - name: Checkout code |
| 18 | + - name: Checkout repository |
18 | 19 | uses: actions/checkout@v4 |
19 | 20 |
|
20 | | - - name: Download python embeddable version |
| 21 | + # ---------------------------------------------------------------------- |
| 22 | + # Download embeddable Python |
| 23 | + # ---------------------------------------------------------------------- |
| 24 | + - name: Download Python embeddable |
| 25 | + shell: bash |
21 | 26 | run: | |
22 | | - mkdir python-${{ env.PYTHON_VERSION }} |
23 | | - curl -O https://www.python.org/ftp/python/${{ env.PYTHON_VERSION }}/python-${{ env.PYTHON_VERSION }}-embed-amd64.zip |
24 | | - unzip python-${{ env.PYTHON_VERSION }}-embed-amd64.zip -d python-${{ env.PYTHON_VERSION }} |
25 | | - rm python-${{ env.PYTHON_VERSION }}-embed-amd64.zip |
| 27 | + mkdir python-${PYTHON_VERSION} |
| 28 | + curl -LO https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-embed-amd64.zip |
| 29 | + unzip python-${PYTHON_VERSION}-embed-amd64.zip -d python-${PYTHON_VERSION} |
| 30 | + rm python-${PYTHON_VERSION}-embed-amd64.zip |
26 | 31 |
|
27 | | - - name: Install pip |
| 32 | + - name: Install pip into embeddable Python |
| 33 | + shell: bash |
28 | 34 | run: | |
29 | | - curl -O https://bootstrap.pypa.io/get-pip.py |
30 | | - ./python-${{ env.PYTHON_VERSION }}/python get-pip.py --no-warn-script-location |
| 35 | + curl -LO https://bootstrap.pypa.io/get-pip.py |
| 36 | + ./python-${PYTHON_VERSION}/python get-pip.py --no-warn-script-location |
31 | 37 | rm get-pip.py |
32 | | - |
33 | | - - name: Uncomment 'import site' in python310._pth file |
| 38 | +
|
| 39 | + - name: Enable site-packages (import site) |
| 40 | + shell: bash |
34 | 41 | run: | |
35 | | - sed -i 's/#import site/import site/' python-${{ env.PYTHON_VERSION }}/python310._pth |
36 | | - |
37 | | - - name: Print content of python310._pth file |
| 42 | + sed -i 's/#import site/import site/' python-${PYTHON_VERSION}/python310._pth |
| 43 | +
|
| 44 | + - name: Install Python requirements |
38 | 45 | run: | |
39 | | - cat python-${{ env.PYTHON_VERSION }}/python310._pth |
| 46 | + .\python-${{ env.PYTHON_VERSION }}\python -m pip install -r requirements.txt --no-warn-script-location |
40 | 47 |
|
41 | | - - name: Install Required Packages |
42 | | - run: .\python-${{ env.PYTHON_VERSION }}\python -m pip install -r requirements.txt --no-warn-script-location |
43 | | - |
44 | | - - name: Create .bat file |
| 48 | + # ---------------------------------------------------------------------- |
| 49 | + # Build portable application directory |
| 50 | + # ---------------------------------------------------------------------- |
| 51 | + - name: Create launcher batch file |
| 52 | + shell: bash |
45 | 53 | run: | |
46 | | - echo " start /min .\python-${{ env.PYTHON_VERSION }}\python -m streamlit run app.py local" > ${{ env.APP_NAME }}.bat |
47 | | - |
48 | | - - name: Create All-in-one executable folder |
| 54 | + echo "start /min python-${PYTHON_VERSION}\\python -m streamlit run app.py local" > ${APP_NAME}.bat |
| 55 | +
|
| 56 | + - name: Assemble portable app folder |
49 | 57 | run: | |
| 58 | + Remove-Item -Recurse -Force streamlit_exe -ErrorAction SilentlyContinue |
50 | 59 | mkdir streamlit_exe |
51 | 60 | mv python-${{ env.PYTHON_VERSION }} streamlit_exe |
52 | 61 | cp -r src streamlit_exe |
53 | 62 | cp -r content streamlit_exe |
54 | | - cp -r docs streamlit_exe |
55 | 63 | cp -r assets streamlit_exe |
56 | 64 | cp -r example-data streamlit_exe |
57 | 65 | cp -r .streamlit streamlit_exe |
58 | 66 | cp app.py streamlit_exe |
59 | 67 | cp settings.json streamlit_exe |
60 | | - cp default-parameters.json streamlit_exe |
61 | 68 | cp ${{ env.APP_NAME }}.bat streamlit_exe |
62 | | - |
63 | | - - name: Generate Readme.txt |
64 | | - shell: bash |
| 69 | +
|
| 70 | + # Optional but strongly recommended: reduce file count |
| 71 | + - name: Remove Python caches and tests |
65 | 72 | run: | |
66 | | - cat <<EOF > streamlit_exe/Readme.txt |
67 | | - Welcome to ${{ env.APP_NAME }} app! |
68 | | -
|
69 | | - To launch the application: |
70 | | - 1. Navigate to the installation directory. |
71 | | - 2. Double-click on the file: ${{ env.APP_NAME }}.bat or ${{ env.APP_NAME }} shortcut. |
72 | | -
|
73 | | - Additional Information: |
74 | | - - If multiple Streamlit apps are running, you can change the port in the .streamlit/config.toml file. |
75 | | - Example: |
76 | | - [server] |
77 | | - port = 8502 |
78 | | -
|
79 | | - Reach out to us: |
80 | | - - Join our Discord server for support and community discussions: https://discord.com/invite/4TAGhqJ7s5 |
81 | | - - Contribute or stay updated with the latest OpenMS web app developments on GitHub: https://github.com/OpenMS/streamlit-template |
82 | | - - Visit our website for more information: https://openms.de/ |
83 | | - |
84 | | - Thank you for using ${{ env.APP_NAME }}! |
85 | | - EOF |
86 | | - |
87 | | - - name: Install WiX Toolset |
| 73 | + Get-ChildItem streamlit_exe -Recurse -Directory -Filter "__pycache__" | Remove-Item -Recurse -Force |
| 74 | + Get-ChildItem streamlit_exe -Recurse -Directory -Match "test","tests" | Remove-Item -Recurse -Force |
| 75 | +
|
| 76 | + # ---------------------------------------------------------------------- |
| 77 | + # Install WiX Toolset 3.11 |
| 78 | + # ---------------------------------------------------------------------- |
| 79 | + - name: Install WiX |
| 80 | + shell: bash |
88 | 81 | run: | |
89 | 82 | curl -LO https://github.com/wixtoolset/wix3/releases/download/wix3111rtm/wix311-binaries.zip |
90 | 83 | unzip wix311-binaries.zip -d wix |
91 | 84 | rm wix311-binaries.zip |
92 | | - |
93 | | - - name: Build .wxs for streamlit_exe folder |
| 85 | +
|
| 86 | + # ---------------------------------------------------------------------- |
| 87 | + # Split harvesting (CRITICAL PART) |
| 88 | + # ---------------------------------------------------------------------- |
| 89 | + - name: Harvest application files (no Python) |
| 90 | + run: | |
| 91 | + ./wix/heat.exe dir streamlit_exe ` |
| 92 | + -gg -sfrag -sreg -srd ` |
| 93 | + -template component ` |
| 94 | + -cg AppFiles ` |
| 95 | + -dr AppSubFolder ` |
| 96 | + -x streamlit_exe/python-${{ env.PYTHON_VERSION }} ` |
| 97 | + -out app_files.wxs |
| 98 | +
|
| 99 | + - name: Harvest Python runtime (no site-packages) |
94 | 100 | run: | |
95 | | - ./wix/heat.exe dir streamlit_exe -gg -sfrag -sreg -srd -template component -cg StreamlitExeFiles -dr AppSubFolder -out streamlit_exe_files.wxs |
96 | | - |
97 | | - - name: Generate VBScript file |
| 101 | + ./wix/heat.exe dir streamlit_exe/python-${{ env.PYTHON_VERSION }} ` |
| 102 | + -gg -sfrag -sreg -srd ` |
| 103 | + -template component ` |
| 104 | + -cg PythonRuntime ` |
| 105 | + -dr AppSubFolder ` |
| 106 | + -x streamlit_exe/python-${{ env.PYTHON_VERSION }}/Lib/site-packages ` |
| 107 | + -out python_runtime.wxs |
| 108 | +
|
| 109 | + - name: Harvest Python site-packages |
| 110 | + run: | |
| 111 | + ./wix/heat.exe dir streamlit_exe/python-${{ env.PYTHON_VERSION }}/Lib/site-packages ` |
| 112 | + -gg -sfrag -sreg -srd ` |
| 113 | + -template component ` |
| 114 | + -cg PythonPackages ` |
| 115 | + -dr AppSubFolder ` |
| 116 | + -out python_packages.wxs |
| 117 | +
|
| 118 | + # ---------------------------------------------------------------------- |
| 119 | + # Assign DiskId to avoid CAB overflow |
| 120 | + # ---------------------------------------------------------------------- |
| 121 | + - name: Assign DiskId per harvest |
98 | 122 | shell: bash |
99 | 123 | run: | |
100 | | - cat <<EOF > ShowSuccessMessage.vbs |
101 | | - MsgBox " The ${{ env.APP_NAME }} application is successfully installed.", vbInformation, "Installation Complete" |
102 | | - EOF |
| 124 | + sed -i 's/<File /<File DiskId="1" /' app_files.wxs |
| 125 | + sed -i 's/<File /<File DiskId="2" /' python_runtime.wxs |
| 126 | + sed -i 's/<File /<File DiskId="3" /' python_packages.wxs |
103 | 127 |
|
| 128 | + # ---------------------------------------------------------------------- |
| 129 | + # Prepare SourceDir |
| 130 | + # ---------------------------------------------------------------------- |
104 | 131 | - name: Prepare SourceDir |
105 | 132 | run: | |
106 | 133 | mkdir SourceDir |
107 | 134 | mv streamlit_exe/* SourceDir |
108 | | - cp ShowSuccessMessage.vbs SourceDir |
109 | 135 | cp assets/openms_license.rtf SourceDir |
110 | | - # Logo of app |
111 | 136 | cp assets/openms.ico SourceDir |
112 | | - |
113 | | - - name: Generate WiX XML file |
| 137 | +
|
| 138 | + # ---------------------------------------------------------------------- |
| 139 | + # Main WiX product file |
| 140 | + # ---------------------------------------------------------------------- |
| 141 | + - name: Generate main WiX file |
114 | 142 | shell: bash |
115 | 143 | run: | |
116 | | - cat <<EOF > streamlit_exe.wxs |
| 144 | + cat <<EOF > installer.wxs |
117 | 145 | <?xml version="1.0"?> |
118 | 146 | <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> |
119 | | - <Product Id="*" Name="${{ env.APP_NAME }}" Language="1033" Version="1.0.0.0" Codepage="1252" Manufacturer="OpenMS Developer Team" UpgradeCode="${{ env.APP_UpgradeCode }}"> |
120 | | - <Package Id="*" InstallerVersion="300" Compressed="yes" InstallPrivileges="elevated" Platform="x64" /> |
121 | | - <Media Id="1" Cabinet="streamlit.cab" EmbedCab="yes" /> |
122 | | - |
123 | | - <!-- Folder structure --> |
124 | | - <Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" /> |
| 147 | + <Product Id="*" Name="${APP_NAME}" Language="1033" |
| 148 | + Version="1.0.0.0" |
| 149 | + Manufacturer="OpenMS Developer Team" |
| 150 | + UpgradeCode="${APP_UpgradeCode}"> |
| 151 | + <Package InstallerVersion="300" Compressed="yes" Platform="x64"/> |
| 152 | +
|
| 153 | + <Media Id="1" Cabinet="app.cab" EmbedCab="yes"/> |
| 154 | + <Media Id="2" Cabinet="python.cab" EmbedCab="yes"/> |
| 155 | + <Media Id="3" Cabinet="packages.cab" EmbedCab="yes"/> |
| 156 | +
|
125 | 157 | <Directory Id="TARGETDIR" Name="SourceDir"> |
126 | | - <Directory Id="ProgramFilesFolder"> |
127 | | - <Directory Id="INSTALLFOLDER" Name="${{ env.APP_NAME }}"> |
128 | | - <Directory Id="AppSubFolder" Name="${{ env.APP_NAME }}" /> |
129 | | - <Component Id="CreateAppFolder" Guid="95dbfa06-d36a-427f-995c-e87769ac2e59"> |
130 | | - <CreateFolder> |
131 | | - <Permission User="Everyone" GenericAll="yes" /> |
132 | | - </CreateFolder> |
133 | | - </Component> |
| 158 | + <Directory Id="ProgramFilesFolder"> |
| 159 | + <Directory Id="INSTALLFOLDER" Name="${APP_NAME}"> |
| 160 | + <Directory Id="AppSubFolder" Name="${APP_NAME}"/> |
134 | 161 | </Directory> |
135 | 162 | </Directory> |
136 | | - <Directory Id="DesktopFolder" /> |
| 163 | + <Directory Id="DesktopFolder"/> |
137 | 164 | </Directory> |
138 | | - |
139 | | - <!-- Add components --> |
140 | | - <Feature Id="MainFeature" Title="Main Application" Level="1"> |
141 | | - <ComponentGroupRef Id="StreamlitExeFiles" /> |
142 | | - <ComponentRef Id="CreateAppFolder" /> |
143 | | - <ComponentRef Id="DesktopShortcutComponent" /> |
144 | | - <ComponentRef Id="InstallDirShortcutComponent" /> |
| 165 | +
|
| 166 | + <Feature Id="MainFeature" Level="1"> |
| 167 | + <ComponentGroupRef Id="AppFiles"/> |
| 168 | + <ComponentGroupRef Id="PythonRuntime"/> |
| 169 | + <ComponentGroupRef Id="PythonPackages"/> |
145 | 170 | </Feature> |
146 | | - |
147 | | - <!-- Create shortcut for running app on desktop --> |
148 | | - <Component Id="DesktopShortcutComponent" Guid="3597b243-9180-4d0b-b105-30d8b0d1a334" Directory="DesktopFolder"> |
149 | | - <Shortcut Id="DesktopShortcut" Name="${{ env.APP_NAME }}" Description="Launch ${{ env.APP_NAME }}" Target="[AppSubFolder]${{ env.APP_NAME }}.bat" WorkingDirectory="AppSubFolder" Icon="AppIcon" /> |
150 | | - <RegistryValue Root="HKCU" Key="Software\\OpenMS\\${{ env.APP_NAME }}" Name="DesktopShortcut" Type="integer" Value="1" KeyPath="yes" /> |
151 | | - </Component> |
152 | | - |
153 | | - <!-- Create shortcut for running app in installer folder --> |
154 | | - <Component Id="InstallDirShortcutComponent" Guid="c2df9472-3b45-4558-a56d-6034cf7c8b72" Directory="AppSubFolder"> |
155 | | - <Shortcut Id="InstallDirShortcut" Name="${{ env.APP_NAME }}" Description="Launch ${{ env.APP_NAME }}" Target="[AppSubFolder]${{ env.APP_NAME }}.bat" WorkingDirectory="AppSubFolder" Icon="AppIcon" /> |
156 | | - <RegistryValue Root="HKCU" Key="Software\\OpenMS\\${{ env.APP_NAME }}" Name="InstallFolderShortcut" Type="integer" Value="1" KeyPath="yes" /> |
157 | | - </Component> |
158 | | - |
159 | | - <!-- Provide icon here; it should exist in the SourceDir folder --> |
160 | | - <Icon Id="AppIcon" SourceFile="SourceDir/openms.ico" /> |
161 | | - |
162 | | - <!-- Run app directly after installation --> |
163 | | - <!-- <CustomAction Id="RunApp" Directory="AppSubFolder" Execute="deferred" Return="asyncNoWait" Impersonate="no" |
164 | | - ExeCommand="cmd.exe /c "[AppSubFolder]${{ env.APP_NAME }}.bat"" /> --> |
165 | | - |
166 | | - <!-- Custom Action to Show Success Message --> |
167 | | - <Binary Id="ShowMessageScript" SourceFile="SourceDir/ShowSuccessMessage.vbs" /> |
168 | | - <CustomAction Id="ShowSuccessMessage" BinaryKey="ShowMessageScript" VBScriptCall="" Execute="immediate" Return="check" /> |
169 | | - |
170 | | - <!-- Add all Custom Actions --> |
171 | | - <InstallExecuteSequence> |
172 | | - <!-- Custom action display success message --> |
173 | | - <Custom Action="ShowSuccessMessage" After="InstallFinalize">NOT Installed</Custom> |
174 | | - <!-- Run app directly after installation --> |
175 | | - <!-- <Custom Action="RunApp" Before="InstallFinalize">NOT REMOVE</Custom> --> |
176 | | - </InstallExecuteSequence> |
177 | | - |
178 | | - <!-- Interface options --> |
| 171 | +
|
| 172 | + <Icon Id="AppIcon" SourceFile="SourceDir/openms.ico"/> |
| 173 | + <WixVariable Id="WixUILicenseRtf" Value="SourceDir/openms_license.rtf"/> |
| 174 | +
|
179 | 175 | <UI> |
180 | | - <UIRef Id="WixUI_InstallDir" /> |
181 | | - <UIRef Id="WixUI_ErrorProgressText" /> |
182 | | - </UI> |
183 | | - |
184 | | - <!-- Provide license; it should exist in the SourceDir folder --> |
185 | | - <WixVariable Id="WixUILicenseRtf" Value="SourceDir/openms_license.rtf" /> |
| 176 | + <UIRef Id="WixUI_InstallDir"/> |
| 177 | + <UIRef Id="WixUI_ErrorProgressText"/> |
| 178 | + </UI> |
186 | 179 | </Product> |
187 | 180 | </Wix> |
188 | 181 | EOF |
189 | 182 |
|
190 | | - - name: Build .wixobj file with candle.exe |
| 183 | + # ---------------------------------------------------------------------- |
| 184 | + # Build MSI |
| 185 | + # ---------------------------------------------------------------------- |
| 186 | + - name: Compile WiX sources |
191 | 187 | run: | |
192 | | - ./wix/candle.exe streamlit_exe.wxs streamlit_exe_files.wxs |
193 | | - |
194 | | - - name: Link .wixobj file into .msi with light.exe |
| 188 | + ./wix/candle.exe installer.wxs app_files.wxs python_runtime.wxs python_packages.wxs |
| 189 | +
|
| 190 | + - name: Link MSI |
195 | 191 | run: | |
196 | | - ./wix/light.exe -ext WixUIExtension -sice:ICE60 -o ${{ env.APP_NAME }}.msi streamlit_exe_files.wixobj streamlit_exe.wixobj |
| 192 | + ./wix/light.exe -ext WixUIExtension ` |
| 193 | + -o ${APP_NAME}.msi ` |
| 194 | + installer.wixobj app_files.wixobj python_runtime.wixobj python_packages.wixobj |
197 | 195 |
|
198 | | - - name: Archive build artifacts |
| 196 | + # ---------------------------------------------------------------------- |
| 197 | + # Upload artifact |
| 198 | + # ---------------------------------------------------------------------- |
| 199 | + - name: Upload MSI |
199 | 200 | uses: actions/upload-artifact@v4 |
200 | 201 | with: |
201 | | - name: OpenMS-App-Test |
202 | | - path: | |
203 | | - ${{ env.APP_NAME }}.msi |
| 202 | + name: OpenMS-Windows-MSI |
| 203 | + path: ${{ env.APP_NAME }}.msi |
0 commit comments