Skip to content

Commit 21e5de1

Browse files
authored
feat(build) modify build.py to produce installers (#858)
* modify build.py to produce installers * download_and_install_inno_setup * black/flake8 * remove zipping in build
1 parent e5a2c15 commit 21e5de1

File tree

2 files changed

+99
-12
lines changed

2 files changed

+99
-12
lines changed

.github/workflows/release-and-publish.yml

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,11 @@ jobs:
4747
- name: Build executables
4848
run: |
4949
poetry run python -m openadapt.build
50-
cd dist
51-
zip -r ../OpenAdapt.app.zip OpenAdapt.app
52-
cd ..
5350
- name: Upload executables
5451
uses: actions/upload-artifact@v4
5552
with:
56-
name: OpenAdapt.app
57-
path: OpenAdapt.app.zip
53+
name: OpenAdapt.dmg
54+
path: OpenAdapt.dmg
5855

5956
build-windows-executables:
6057
name: Build Windows app
@@ -86,14 +83,11 @@ jobs:
8683
- name: Build executables
8784
run: |
8885
poetry run python -m openadapt.build
89-
cd dist
90-
7z a -tzip ../OpenAdapt.zip OpenAdapt
91-
cd ..
9286
- name: Upload executables
9387
uses: actions/upload-artifact@v4
9488
with:
95-
name: OpenAdapt
96-
path: OpenAdapt.zip
89+
name: OpenAdapt_Installer
90+
path: OpenAdapt_Installer
9791

9892
test_on_macos:
9993
name: Test on macOS

openadapt/build.py

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import shutil
1212
import subprocess
1313
import sys
14+
import tempfile
15+
import time
16+
import urllib.request
1417

1518
import gradio_client
1619
import nicegui
@@ -28,8 +31,8 @@
2831
import screen_recorder_sdk
2932

3033

31-
def main() -> None:
32-
"""Entry point."""
34+
def build_pyinstaller() -> None:
35+
"""Build the application using PyInstaller."""
3336
additional_packages_to_install = [
3437
nicegui,
3538
oa_pynput,
@@ -182,5 +185,95 @@ def main() -> None:
182185
)
183186

184187

188+
def create_macos_dmg() -> None:
189+
"""Create a DMG installer for macOS."""
190+
ROOT_DIR = Path(__file__).parent.parent
191+
subprocess.run(
192+
[
193+
"hdiutil",
194+
"create",
195+
"-volname",
196+
"OpenAdapt",
197+
"-srcfolder",
198+
ROOT_DIR / "dist" / "OpenAdapt.app",
199+
"-ov",
200+
"-format",
201+
"UDZO",
202+
ROOT_DIR / "dist" / "OpenAdapt.dmg",
203+
]
204+
)
205+
206+
207+
def download_and_extract_inno_setup() -> tuple[str, str]:
208+
"""Download and extract Inno Setup."""
209+
inno_setup_url = "https://files.jrsoftware.org/is/6/innosetup-6.2.2.exe"
210+
temp_dir = tempfile.mkdtemp()
211+
temp_file = Path(temp_dir) / "innosetup.exe"
212+
print("Downloading Inno Setup...")
213+
urllib.request.urlretrieve(inno_setup_url, temp_file)
214+
215+
print("Extracting Inno Setup...")
216+
subprocess.run(
217+
[str(temp_file), "/VERYSILENT", "/CURRENTUSER", f"/DIR={temp_dir}\\InnoSetup"],
218+
check=True,
219+
)
220+
221+
inno_setup_compiler = Path(temp_dir) / "InnoSetup" / "ISCC.exe"
222+
if not inno_setup_compiler.exists():
223+
raise FileNotFoundError("Failed to extract Inno Setup compiler (ISCC.exe)")
224+
225+
return inno_setup_compiler, temp_dir
226+
227+
228+
def create_windows_installer() -> None:
229+
"""Create an EXE installer for Windows using Inno Setup."""
230+
ROOT_DIR = Path(__file__).parent.parent
231+
DIST_DIR = ROOT_DIR / "dist" / "OpenAdapt"
232+
233+
INNO_SETUP_SCRIPT = f"""
234+
[Setup]
235+
AppName=OpenAdapt
236+
AppVersion=1.0
237+
DefaultDirName={{userappdata}}\\OpenAdapt
238+
DefaultGroupName=OpenAdapt
239+
OutputBaseFilename=OpenAdapt_Installer
240+
Compression=lzma
241+
SolidCompression=yes
242+
PrivilegesRequired=lowest
243+
OutputDir={ROOT_DIR / "dist"}
244+
245+
[Files]
246+
Source: "{DIST_DIR}\\*"; DestDir: "{{app}}";
247+
Flags: ignoreversion recursesubdirs createallsubdirs
248+
249+
[Icons]
250+
Name: "{{group}}\\OpenAdapt"; Filename: "{{app}}\\OpenAdapt.exe"
251+
Name: "{{group}}\\{{cm:UninstallProgram,OpenAdapt}}"; Filename: "{{uninstallexe}}"
252+
"""
253+
INNO_SETUP_PATH = ROOT_DIR / "build_scripts" / "OpenAdapt.iss"
254+
INNO_SETUP_PATH.write_text(INNO_SETUP_SCRIPT)
255+
256+
inno_setup_compiler, temp_dir = download_and_extract_inno_setup()
257+
try:
258+
subprocess.run([str(inno_setup_compiler), str(INNO_SETUP_PATH)], check=True)
259+
finally:
260+
# Wait a moment before cleaning up
261+
time.sleep(2)
262+
try:
263+
shutil.rmtree(temp_dir)
264+
except PermissionError:
265+
print(f"Warning: Unable to remove temporary directory: {temp_dir}")
266+
print("You may need to manually delete this directory later.")
267+
268+
269+
def main() -> None:
270+
"""Entry point."""
271+
build_pyinstaller()
272+
if sys.platform == "darwin":
273+
create_macos_dmg()
274+
elif sys.platform == "win32":
275+
create_windows_installer()
276+
277+
185278
if __name__ == "__main__":
186279
main()

0 commit comments

Comments
 (0)