Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
cb0b453
Add built executable
sumana-2705 Jun 28, 2025
53f8797
Remove built executable from repo and add PyInstaller .spec file
sumana-2705 Jul 3, 2025
f4d1806
Update spec file.
JoeZiminski Jul 4, 2025
2d9b080
Packaging with terminal working on Windows.
JoeZiminski Jul 22, 2025
c89d85b
Remove spec from gitignore.
JoeZiminski Jul 22, 2025
7f11a0d
Add macos packaging.
JoeZiminski Jul 24, 2025
ff5aea3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 24, 2025
cae29f2
Tidying up on windows.
JoeZiminski Jul 25, 2025
9d30ecc
Working on windows.
JoeZiminski Jul 25, 2025
3d6fdaa
Working on macos but no installer yet.
JoeZiminski Jul 25, 2025
7c39de4
Start playing around with Linux.
JoeZiminski Sep 2, 2025
a29bafa
Start playing around with Linux 2.
JoeZiminski Sep 2, 2025
b711ce2
Start playing around with Linux 3.
JoeZiminski Sep 2, 2025
47a494d
Start playing around with Linux 4.
JoeZiminski Sep 2, 2025
4f13e61
Start playing around with Linux 5.
JoeZiminski Sep 2, 2025
c47c044
Start playing around with Linux 6.
JoeZiminski Sep 2, 2025
0720f87
Start playing around with Linux 7.
JoeZiminski Sep 2, 2025
5f3eb53
Start playing around with Linux 8.
JoeZiminski Sep 2, 2025
8498cba
Working on linux2
JoeZiminski Sep 2, 2025
5515ed1
Working on linux.
JoeZiminski Sep 2, 2025
f72c412
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 2, 2025
ecc0e08
More windows.
JoeZiminski Feb 24, 2026
a51ced3
Windows package 2.
JoeZiminski Feb 24, 2026
a0ee451
update ci.
JoeZiminski Feb 24, 2026
515cdee
Remove emojis.
JoeZiminski Feb 24, 2026
ccb92eb
Remove emojis 2.
JoeZiminski Feb 24, 2026
96f7cb9
Make rclone search more general.
JoeZiminski Feb 24, 2026
6e0f7ef
Fixes for ci.
JoeZiminski Feb 24, 2026
8929de4
Fix installer link.
JoeZiminski Feb 24, 2026
4fda408
Small tidy up.
JoeZiminski Feb 24, 2026
9cb8329
Remove linux.
JoeZiminski Feb 24, 2026
5d3951f
Tidying up and finalising on Windows.
JoeZiminski Feb 25, 2026
2b4b29f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 25, 2026
34f3883
opus 4.7 tidy ups and fix version.
JoeZiminski May 24, 2026
7e28327
Opus 4.7 backward compatable macOS build.
JoeZiminski May 24, 2026
aff756f
Remove 0.0.0 fallback.
JoeZiminski May 25, 2026
9342ff3
Fix zip extesnion for macos and requests install.
JoeZiminski May 25, 2026
f079b5d
Fix linting.
JoeZiminski May 25, 2026
77b26d9
Install pip on workflows.
JoeZiminski May 25, 2026
a8fcb5b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 25, 2026
61857d4
Fix macOS build.
JoeZiminski May 25, 2026
6f51c40
Merge branch 'cross-platform-packaging' of github.com:neuroinformatic…
JoeZiminski May 25, 2026
e9de5c1
Fix license, ssh tests and windows release bug.
JoeZiminski May 25, 2026
1f28329
Fix MEIPASS path.
JoeZiminski May 25, 2026
e0ad46e
Fix CSS resolve for frozen macOS.
JoeZiminski May 25, 2026
d2511eb
Ensure tcss are bundled.
JoeZiminski May 25, 2026
44eea3c
Fix CI by using SPECFILE far.
JoeZiminski May 25, 2026
b0ba1cb
Start updating docs with links, add some notes.
JoeZiminski May 25, 2026
1d03ea1
add notarisation, some notes and refactor.
JoeZiminski May 30, 2026
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
153 changes: 153 additions & 0 deletions .github/workflows/package_macos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
name: macos-build

on:
push:
branches: [ main ]
tags: [ "v*" ]
pull_request:
# Manual trigger so you can exercise the build (and optionally the
# release-upload step) from the Actions tab without cutting a tag.
workflow_dispatch:
inputs:
test_release_upload:
description: "Also push the .dmg(s) to a throwaway draft Release for end-to-end testing."
type: boolean
default: false

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-macos:
name: ${{ matrix.target_arch }} (${{ matrix.os }})
runs-on: ${{ matrix.os }}

# `contents: write` is required for softprops/action-gh-release to
# create / update the GitHub Release. The release step itself is
# gated to tag pushes only, so PRs and main-branch pushes don't get
# write access.
permissions:
contents: write

strategy:
fail-fast: false
matrix:
include:
# macos-13 was deprecated by GitHub in Feb 2026. We now build on
# newer images and use MACOSX_DEPLOYMENT_TARGET to pin the
# backward-compatibility floor (the deployment target, not the
# build host, is what determines the minimum macOS the binary
# will run on).
- os: macos-15-intel
target_arch: x86_64
macos_min_version: "10.13.0"
macosx_deployment_target: "10.13"
- os: macos-14
target_arch: arm64
macos_min_version: "11.0.0"
macosx_deployment_target: "11.0"

defaults:
run:
shell: bash -l {0}

env:
TARGET_ARCH: ${{ matrix.target_arch }}
MACOS_MIN_VERSION: ${{ matrix.macos_min_version }}
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}

steps:
- uses: actions/checkout@v6
with:
# Need full history for setuptools_scm to derive the version.
fetch-depth: 0

- name: Set up Conda
uses: conda-incubator/setup-miniconda@v4
with:
python-version: "3.12"
auto-update-conda: true
channels: conda-forge
activate-environment: "datashuttle-package"

- name: Install pip
run: conda install pip

- name: Install rclone
run: conda install -c conda-forge rclone

- name: Install create-dmg
run: brew install create-dmg

# Import the Developer ID Application certificate into a temporary
# keychain. The keychain is torn down automatically at job end so
# the cert never persists on the runner. Only runs on tag pushes and
# opt-in manual dispatches — PRs and main-branch pushes don't get
# access to the secrets.
- name: Import code-signing certificate
if: >-
startsWith(github.ref, 'refs/tags/v') ||
(github.event_name == 'workflow_dispatch' &&
inputs.test_release_upload)
uses: apple-actions/import-codesign-certs@v3
with:
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }}
p12-password: ${{ secrets.MACOS_CERTIFICATE_PWD }}

- name: Install datashuttle and packaging deps
run: |
python -m pip install --upgrade pip
python -m pip install .[dev]
python -m pip install pyinstaller requests

- name: Run macOS packaging script
env:
# The signing / notarisation env vars are read by
# package/macos/sign_macos.py. They are only present on tag pushes and
# opt-in manual dispatches; on PRs they are empty strings and
# sign_macos becomes a no-op.
MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
run: python package/macos/package_macos.py

- name: Verify .app bundle is valid for this arch
run: |
BIN="package/macos/dist/Datashuttle.app/Contents/Resources/datashuttle"
test -x "$BIN"
file "$BIN"
# Ensure the architecture matches what we asked PyInstaller to build.
lipo -archs "$BIN" | grep -q "${TARGET_ARCH}"
# Print the Info.plist min OS version so it's visible in the log.
/usr/libexec/PlistBuddy -c "Print :LSMinimumSystemVersion" \
package/macos/dist/Datashuttle.app/Contents/Info.plist

- name: Upload installer artifact
uses: actions/upload-artifact@v4
with:
name: macos-installer-${{ matrix.target_arch }}
path: package/macos/Output/datashuttle-*-${{ matrix.target_arch }}.dmg

# Attach the .dmg to a GitHub Release in two cases:
# * Real tag push (v*) -> draft release named after the tag.
# * Manual run with `test_release_upload=true` -> draft release
# named `test-build-<run_id>`, safe to delete afterwards.
# `softprops/action-gh-release` creates the release as a draft if
# it doesn't already exist, and appends assets if it does — so the
# arm64 and x86_64 matrix jobs both attach to the same release.
- name: Attach .dmg to GitHub Release
if: >-
startsWith(github.ref, 'refs/tags/v') ||
(github.event_name == 'workflow_dispatch' &&
inputs.test_release_upload)
uses: softprops/action-gh-release@v2
with:
draft: true
prerelease: ${{ github.event_name == 'workflow_dispatch' }}
tag_name: ${{ github.event_name == 'workflow_dispatch' && format('test-build-{0}', github.run_id) || github.ref_name }}
name: ${{ github.event_name == 'workflow_dispatch' && format('Test build {0}', github.run_id) || github.ref_name }}
target_commitish: ${{ github.sha }}
files: package/macos/Output/datashuttle-*-${{ matrix.target_arch }}.dmg
fail_on_unmatched_files: true
93 changes: 93 additions & 0 deletions .github/workflows/package_windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: windows-build

on:
push:
branches: [ main ]
tags: [ "v*" ]
pull_request:
# Manual trigger so you can exercise the build (and optionally the
# release-upload step) from the Actions tab without cutting a tag.
workflow_dispatch:
inputs:
test_release_upload:
description: "Also push the .exe to a throwaway draft Release for end-to-end testing."
type: boolean
default: false

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-windows:
runs-on: windows-latest

# `contents: write` is required for softprops/action-gh-release to
# create / update the GitHub Release. The release step itself is
# gated to tag pushes only.
permissions:
contents: write

defaults:
run:
shell: powershell

steps:
- uses: actions/checkout@v6
- name: Set up Conda
uses: conda-incubator/setup-miniconda@v4
with:
python-version: "3.12"
auto-update-conda: true
channels: conda-forge
activate-environment: "datashuttle-test"

- name: Install pip
run: conda install pip

- name: Install rclone
run: conda install -c conda-forge rclone

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install .[dev]
python -m pip install pyinstaller requests

# Install Inno Setup silently
- name: Install Inno Setup
run: |
choco install innosetup --yes

- name: Verify Inno Setup installation
run: |
Get-Command "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"

- name: Run Windows packaging script
run: |
python package/windows/package_windows.py

- name: Upload installer artifact
uses: actions/upload-artifact@v4
with:
name: windows-installer
path: package\windows\Output\datashuttle_*.exe

# Attach the .exe to a GitHub Release in two cases:
# * Real tag push (v*) -> draft release named after the tag.
# * Manual run with `test_release_upload=true` -> draft release
# named `test-build-<run_id>`, safe to delete afterwards.
- name: Attach .exe to GitHub Release
if: >-
startsWith(github.ref, 'refs/tags/v') ||
(github.event_name == 'workflow_dispatch' &&
inputs.test_release_upload)
uses: softprops/action-gh-release@v2
with:
draft: true
prerelease: ${{ github.event_name == 'workflow_dispatch' }}
tag_name: ${{ github.event_name == 'workflow_dispatch' && format('test-build-{0}', github.run_id) || github.ref_name }}
name: ${{ github.event_name == 'workflow_dispatch' && format('Test build {0}', github.run_id) || github.ref_name }}
target_commitish: ${{ github.sha }}
files: package/windows/Output/datashuttle_*.exe
fail_on_unmatched_files: true
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# python-dotenv environment file for test account credentials.
.env

# Packaging
package/_vendored
package/windows/build
package/windows/dist
package/windows/Output
package/windows/inno_compile_script.iss
package/macos/build
package/macos/dist
package/macos/Output

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down Expand Up @@ -35,7 +44,6 @@ MANIFEST
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
Expand Down
21 changes: 20 additions & 1 deletion datashuttle/tui/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import os
import sys
from typing import TYPE_CHECKING, Dict

if TYPE_CHECKING:
Expand Down Expand Up @@ -29,6 +30,24 @@
from datashuttle.tui.tooltips import get_tooltip


def _resolve_css_path() -> list[Path]:
"""Resolve the directory containing the TUI ``.tcss`` files.

When running from source, the stylesheets live next to this module.
When running as a PyInstaller-frozen executable, the ``.tcss`` files
are bundled under ``_MEIPASS/datashuttle/tui/css/`` via the spec's
``datas`` entry; the synthetic ``__file__`` for this module cannot
be relied on for that lookup (especially on macOS), so prefer
``sys._MEIPASS`` when frozen.
"""
if getattr(sys, "frozen", False):
base = Path(getattr(sys, "_MEIPASS", Path(sys.executable).parent))
css_dir = base / "datashuttle" / "tui" / "css"
else:
css_dir = Path(__file__).parent / "css"
return sorted(css_dir.glob("*.tcss"))


class TuiApp(App, inherit_bindings=False): # type: ignore
"""The main app page for the DataShuttle TUI.

Expand All @@ -38,7 +57,7 @@ class TuiApp(App, inherit_bindings=False): # type: ignore
"""

tui_path = Path(__file__).parent
CSS_PATH = list(Path(tui_path / "css").glob("*.tcss"))
CSS_PATH = _resolve_css_path()
ENABLE_COMMAND_PALETTE = False

BINDINGS = [
Expand Down
1 change: 1 addition & 0 deletions datashuttle/tui/css/tui_menu.tcss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#mainwindow_contents_container {
align: center top;
padding: 1 0 0 0;
overflow: hidden auto;
}
#mainwindow_contents_container > Button {
width: 50%;
Expand Down
5 changes: 4 additions & 1 deletion datashuttle/tui_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,7 @@


if __name__ == "__main__":
main()
try:
main()
except:

Check failure on line 47 in datashuttle/tui_launcher.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Specify an exception class to catch or reraise the exception

See more on https://sonarcloud.io/project/issues?id=neuroinformatics-unit_datashuttle&issues=AZ5evguZqJQ-O8gWOKVu&open=AZ5evguZqJQ-O8gWOKVu&pullRequest=587
input("hello")
Loading
Loading