Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
49 changes: 35 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,51 +17,72 @@ on:
permissions:
contents: read

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

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 20
container: sacredbanana/amiga-compiler:m68k-amigaos

steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6

- name: Resolve release metadata
shell: sh
run: |
version="$(make -s print-version)"
date="$(make -s print-date)"
if [ "${{ github.ref_type }}" = "tag" ]; then
tag_version="${{ github.ref_name }}"
tag_version="${tag_version#v}"
if [ "$tag_version" != "$version" ]; then
echo "Tag version $tag_version does not match version.mk ($version)" >&2
exit 1
fi
fi
echo "VERSION=$version" >> "$GITHUB_ENV"
echo "DATE=$date" >> "$GITHUB_ENV"

- name: Build tools
run: make all
run: make VERSION="$VERSION" DATE="$DATE" all

- name: Run tests
run: make test
run: make VERSION="$VERSION" DATE="$DATE" test

- name: Package tools
run: |
if [ "${{ github.ref_type }}" = "tag" ]; then
VERSION="${{ github.ref_name }}"
else
VERSION="latest"
fi
make package PACKAGE="Host-Tools-${VERSION}.lha"
run: make VERSION="$VERSION" DATE="$DATE" package

- name: Generate checksum
run: sha256sum "Host-Tools-${VERSION}.lha" > "Host-Tools-${VERSION}.lha.sha256"

- name: Upload Artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: host-tools-package
path: "*.lha"
path: |
*.lha
*.lha.sha256

release:
needs: build
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write

steps:
- name: Download Artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: host-tools-package

- name: Create Release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: gh release create ${{ github.ref_name }} *.lha --title "Host-Tools ${{ github.ref_name }}" --generate-notes
run: gh release create ${{ github.ref_name }} *.lha *.lha.sha256 --title "Host-Tools ${{ github.ref_name }}" --generate-notes
46 changes: 46 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!--
SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas
SPDX-License-Identifier: GPL-3.0-or-later
-->

# Changelog

Notable user-visible changes are recorded here. This project follows semantic
versioning for release tags.

## [2.6] - Unreleased

### Added

- Publish a SHA-256 checksum beside each release archive.
- Validate every packaged command, the AmigaGuide, and `mhiuae.library` against
the release version and date before creating an archive.
- Support native tests on both x86-64 and ARM64 hosts in the AmigaOS 3 Docker
image.

### Changed

- Preserve trailing line breaks when pasting from POSIX host clipboards.
- Make `host-download` replacements transactional and limit downloads to HTTP,
HTTPS, FTP, and FTPS, including curl redirects.
- Store the POSIX `host-env` file atomically with owner-only permissions and
reject multiline values.
- Allow Ctrl-C cancellation and bound idle waits in status-aware host commands.

### Fixed

- Keep the `host-shell` login wrapper within the HostShell command trap limit.
- Signal MHI buffer completion only after Amiberry has consumed a buffer.
- Close `utility.library` when UAESND AHI driver initialization fails.
- Prevent the package-layout test directory from leaking into the recursive MHI
build.
- Propagate release metadata into binaries instead of applying the tag only to
the archive filename.

## [2.5] - 2026-06-14

- Added `host-env` and the UAE MHI MP3 decoder library.
- Added UAESND recording support and driver refinements.

[2.6]: https://github.com/BlitterStudio/host-tools/compare/v2.5...HEAD
[2.5]: https://github.com/BlitterStudio/host-tools/releases/tag/v2.5
43 changes: 29 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

TOOLS = host-run host-multiview host-shell host-path host-reveal host-notify host-edit host-clip host-info host-download host-env
TEST_BINS = tests/test_host_common.out tests/test_host_command_builders.out tests/test_host_edit_command.out tests/test_host_download_command.out tests/test_host_terminal_filter.out
TEST_SCRIPTS = tests/test_package_layout.sh tests/test_ahi_driver_source.sh
TESTS = $(TEST_BINS) $(TEST_SCRIPTS)
TEST_SCRIPTS = tests/test_package_layout.sh tests/test_ahi_driver_source.sh tests/test_runtime_source.sh
include version.mk
COMMON_HEADERS = src/host_common.h src/host_path.h src/host_capture.h src/host_base64.h src/host_clip_command.h src/host_download_command.h src/host_edit_command.h src/host_env_command.h src/host_info_command.h src/host_notify_command.h src/host_powershell.h src/host_reveal_command.h src/host_shell_command.h src/uae_pragmas.h
PACKAGE = Host-Tools-$(VERSION).lha
PACKAGE_ROOT = Host-Tools
Expand Down Expand Up @@ -44,28 +44,40 @@ README_ICON = package/icons/readme.info
GUIDE_ICON = package/icons/guide.info

.SUFFIXES:
.PHONY: all test debug package package-dir ahi ahi-v2 mhi clean
.PHONY: all test test-unit test-package debug package package-dir verify-package print-version print-date ahi ahi-v2 mhi clean

all: $(TOOLS) $(AHI_FILES) $(AHI_V2_FILES) $(MHI_FILES)
test: $(TESTS)
@for test in $(TESTS); do \
case "$$test" in \
*.sh) sh "$$test" ;; \
*) ./$$test ;; \
esac || exit $$?; \

test: test-unit test-package

test-unit: $(TEST_BINS)
@for test in $(TEST_BINS); do \
./$$test || exit $$?; \
done

test-package: $(TEST_SCRIPTS)
@for test in $(TEST_SCRIPTS); do \
VERSION="$(VERSION)" DATE="$(DATE)" sh "$$test" || exit $$?; \
done

VERSION = 2.4
DATE = 2026-06-10
print-version:
@printf '%s\n' '$(VERSION)'

print-date:
@printf '%s\n' '$(DATE)'

ifeq ($(origin CC),default)
CC = m68k-amigaos-gcc
endif
INCLUDES = -Isrc
CFLAGS = -mcpu=68020 -noixemul -Os -fomit-frame-pointer -std=c99 -Wall -Wextra -Wstrict-prototypes
VERFLAGS = -DVERSION_STR="\"$(VERSION)\"" -DDATE_STR="\"$(DATE)\""
HOST_CC ?= $(shell command -v x86_64-linux-gnu-gcc 2>/dev/null || command -v cc 2>/dev/null || printf cc)
HOST_NATIVE_FLAGS = $(if $(findstring x86_64-linux-gnu-gcc,$(notdir $(HOST_CC))),-B/usr/bin/x86_64-linux-gnu- -fuse-ld=bfd,)
HOST_ARCH = $(shell uname -m)
HOST_GNU_ARCH = $(if $(filter arm64,$(HOST_ARCH)),aarch64,$(HOST_ARCH))
HOST_CC ?= $(shell command -v $(HOST_GNU_ARCH)-linux-gnu-gcc 2>/dev/null || command -v cc 2>/dev/null || printf cc)
HOST_CC_NAME = $(notdir $(HOST_CC))
HOST_GNU_PREFIX = $(patsubst %-gcc,%,$(HOST_CC_NAME))
HOST_NATIVE_FLAGS = $(if $(findstring -linux-gnu-gcc,$(HOST_CC_NAME)),-B/usr/bin/$(HOST_GNU_PREFIX)- -fuse-ld=bfd,)
HOST_CFLAGS = -std=c99 -Wall -Wextra -Wstrict-prototypes -Isrc

host-run: src/host-run.c $(COMMON_HEADERS)
Expand Down Expand Up @@ -162,7 +174,10 @@ package-dir: all package/Install $(HELP_GUIDE) $(DRAWER_ICON) $(HELP_ICON) $(INS
cp $(MHI_LIBRARY) $(PACKAGE_STAGE)/Libs/MHI/mhiuae.library; \
fi

package: package-dir
verify-package: package-dir
PACKAGE_READY=1 PACKAGE_DIR="$(PACKAGE_DIR)" VERSION="$(VERSION)" DATE="$(DATE)" sh tests/test_package_layout.sh

package: verify-package
rm -f $(PACKAGE)
cd $(PACKAGE_DIR) && lha a $(CURDIR)/$(PACKAGE) $(PACKAGE_ROOT) $(PACKAGE_ROOT).info

Expand Down
34 changes: 25 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ host-edit <path> [path2 ...]

### 8. host-clip
**Use the host clipboard.**
`host-clip` copies text to the host clipboard or prints the current host clipboard contents. Without text arguments, `host-clip copy` reads standard input verbatim, so multi-line text and command output can be piped or redirected to the host clipboard. Text is converted between the Amiga's ISO-8859-1 character set and the host's encoding: through `iconv` on Linux and macOS, and inherently through PowerShell's Unicode pipeline on Windows.
`host-clip` copies text to the host clipboard or prints the current host clipboard contents. Without text arguments, `host-clip copy` reads standard input verbatim, so multi-line text and command output can be piped or redirected to the host clipboard. Paste also preserves trailing line breaks. Text is converted between the Amiga's ISO-8859-1 character set and the host's encoding: through `iconv` on Linux and macOS, and inherently through PowerShell's Unicode pipeline on Windows.

**Usage:**
```shell
Expand All @@ -105,9 +105,9 @@ host-info

### 10. host-download
**Download files through the host.**
`host-download` fetches a URL with the host's `curl` (or `wget`) and saves it to any Amiga path — `RAM:`, hardfiles, and directory mounts all work, because the file is written by the tool through AmigaDOS. The host handles HTTPS/TLS, giving classic AmigaOS access to modern servers.
`host-download` fetches an HTTP, HTTPS, FTP, or FTPS URL with the host's `curl` (or `wget`) and saves it to any Amiga path — `RAM:`, hardfiles, and directory mounts all work, because the file is written by the tool through AmigaDOS. The host handles HTTPS/TLS, giving classic AmigaOS access to modern servers.
- **Live Progress**: With a current Amiberry, the file streams to the Amiga as it downloads, with a percentage display when the server reports a size.
- **Safe**: Failed or aborted downloads (Ctrl-C) never leave a partial file behind, and an existing destination is only overwritten with `FORCE`.
- **Transactional**: Data is written to a temporary file beside the destination. Failed, stalled, or aborted downloads (Ctrl-C) never leave a partial result, and `FORCE` preserves the previous file until the replacement is complete.
- **Flexible Destination**: With no destination the file is saved in the current directory under its URL name; a directory destination keeps the URL name.

**Usage:**
Expand All @@ -119,6 +119,7 @@ host-download <URL> [<destination>] [FORCE]
**Get and set host user environment variables.**
`host-env` reads, writes, removes, and lists environment variables on the host. On Windows it updates the user's persistent environment. On Linux and macOS it writes persistent values to `$HOME/.host-tools-env`; source that file from your host shell startup files if you want future host login shells to import those values automatically.
- **Persistent**: Changes are intended for future host processes.
- **Private by Default**: On Linux and macOS, the managed file is written atomically with mode `0600`. Values must fit on one line.
- **Scoped Safely**: Existing host shells, desktop apps, and Amiberry's parent process cannot have their live environment changed by a child process.

**Usage:**
Expand All @@ -135,10 +136,18 @@ host-env list

- **Amiberry v6.0+** (or a version with updated `uaelib` support).
- "Native Code" execution must be enabled in Amiberry settings.
- All tools work on **Linux and macOS hosts**. On **Windows hosts**, `host-path`, `host-download`, `host-clip`, `host-reveal`, `host-info`, and `host-env` are supported with a current Amiberry (PowerShell and Explorer handle the Windows side; `curl.exe` ships with Windows 10 and later). The remaining tools (`host-run`, `host-multiview`, `host-shell`, `host-edit`, `host-notify`) currently require a Linux or macOS host, since their host commands run through the POSIX shell.
- For status-aware tools (`host-reveal`, `host-notify`, `host-clip`, and `host-info`), a newer Amiberry build with the `HostShell_Status` trap reports host command failures immediately. Older builds still work, but use timeout-based completion detection.
- All tools work on **Linux and macOS hosts**. Current Windows support is summarized below.

| Tool | Linux | macOS | Windows |
| --- | :---: | :---: | :---: |
| `host-run`, `host-multiview`, `host-shell`, `host-edit`, `host-notify` | Yes | Yes | — |
| `host-path`, `host-reveal`, `host-clip`, `host-info`, `host-download`, `host-env` | Yes | Yes | Yes |

Windows integrations require a current Amiberry. PowerShell and Explorer handle desktop operations, and `curl.exe` ships with Windows 10 and later.

- For status-aware tools (`host-reveal`, `host-notify`, `host-clip`, `host-info`, and `host-env`), a newer Amiberry build with the `HostShell_Status` trap reports host command failures immediately. Press Ctrl-C to cancel a stuck host command. An idle command times out after approximately 30 seconds on status-aware builds or 5 seconds on older builds.
- Linux desktop integration uses `xdg-utils` (`xdg-open`, `xdg-mime`) and GTK's `gtk-launch` when available. Notifications use `notify-send`; clipboard support uses `wl-clipboard`, `xclip`, or `xsel`; file selection in `host-reveal` uses `gdbus` when present. Character set conversion uses `iconv` when present.
- `host-download` uses the host's `curl` or `wget` (`curl.exe` on Windows). Live streaming progress requires an Amiberry build with pipe-based HostShell sessions; on older Linux and macOS builds the tool falls back to a two-phase transfer that downloads on the host first.
- `host-download` uses the host's `curl` or `wget` (`curl.exe` on Windows) and accepts HTTP, HTTPS, FTP, and FTPS URLs. Live streaming progress requires an Amiberry build with pipe-based HostShell sessions; on older Linux and macOS builds the tool falls back to a two-phase transfer that downloads on the host first.

## Exit Codes

Expand Down Expand Up @@ -203,20 +212,27 @@ To build locally with the same Docker image used by CI:
docker run --rm -v "$PWD":/work -w /work sacredbanana/amiga-compiler:m68k-amigaos make all
```

To run the host-side command-builder tests:
To run only the native command-builder tests:
```shell
make test
make test-unit
```

To run the complete test suite, including a fresh cross-build and package verification, use the CI image:
```shell
docker run --rm -v "$PWD":/work -w /work sacredbanana/amiga-compiler:m68k-amigaos make clean test
```

To build a release archive:
```shell
make package
```

The package target creates `Host-Tools-<version>.lha`, containing a structured `Host-Tools` drawer with the Installer script, command tools, README, AmigaGuide documentation, the UAE and UAESND AHI driver files, and the UAE MHI MP3 decoder library.
The package target creates and verifies `Host-Tools-<version>.lha`, containing a structured `Host-Tools` drawer with the Installer script, command tools, README, AmigaGuide documentation, the UAE and UAESND AHI driver files, and the UAE MHI MP3 decoder library.

Native package builds also require `lha`. The Docker build image contains this tool.

Release metadata is defined once in [`version.mk`](version.mk). See [`docs/RELEASING.md`](docs/RELEASING.md) for the release checklist and [`CHANGELOG.md`](CHANGELOG.md) for user-visible changes.

To build with debug output enabled:
```shell
make debug
Expand Down
43 changes: 43 additions & 0 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!--
SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas
SPDX-License-Identifier: GPL-3.0-or-later
-->

# Releasing Host-Tools

Release metadata lives in `version.mk`. The tag must be `v` followed by that
exact version; CI rejects a mismatch before building.

## Checklist

1. Update `VERSION` and `DATE` in `version.mk`.
2. Update the `$VER` line in `package/Help/Host-Tools.guide`.
3. Move the pending changelog entry from `Unreleased` to the release date.
4. Run the complete release build from a clean tree:

```shell
docker run --rm -v "$PWD":/work -w /work \
sacredbanana/amiga-compiler:m68k-amigaos make clean test package
```

5. Confirm that `git status --short` contains only intentional source changes.
`make package` already verifies the package layout and all release version
strings before writing the archive.
6. Review the archive and checksum locally if desired:

```shell
lha l "Host-Tools-$(make -s print-version).lha"
shasum -a 256 "Host-Tools-$(make -s print-version).lha"
```

7. Merge the release pull request, then create and push the matching annotated
tag:

```shell
version="$(make -s print-version)"
git tag -a "v$version" -m "Host-Tools v$version"
git push origin "v$version"
```

The tag workflow rebuilds and verifies the package, publishes the `.lha` and
`.lha.sha256` artifacts, and creates the GitHub release with generated notes.
3 changes: 1 addition & 2 deletions drivers/ahi/Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas
# SPDX-License-Identifier: GPL-3.0-or-later

VERSION ?= 2.4
DATE ?= 2026-06-10
include ../../version.mk

VASMM68K_FALLBACK := $(shell command -v vasmm68k_mot 2>/dev/null || { test -x /opt/m68k-amigaos/bin/vasmm68k_mot && printf /opt/m68k-amigaos/bin/vasmm68k_mot; } || printf vasmm68k_mot)
ifeq ($(origin VASMM68K),undefined)
Expand Down
11 changes: 9 additions & 2 deletions drivers/ahi/src/v2/uaesnd.audio.asm
Original file line number Diff line number Diff line change
Expand Up @@ -1710,7 +1710,7 @@ initRoutine:
moveq #0,d0
call OpenLibrary
tst.l d0
beq.s .end
beq.s .init_failed
move.l d0,a6
sub.l a0,a0
move.w #6502,d0
Expand All @@ -1722,11 +1722,18 @@ initRoutine:
call CloseLibrary

move.l ub_ConfigDev(a5),d0
beq.s .end
beq.s .init_failed
move.l d0,a0
move.l cd_BoardAddr(a0),ub_Base(a5)

move.l a5,a4
bra.s .end
.init_failed
move.l ub_UtilBase(a5),a1
beq.s .end
move.l ub_SysLib(a5),a6
call CloseLibrary
clr.l ub_UtilBase(a5)
.end
move.l a4,d0
movem.l (sp)+,d1/a0/a1/a4/a5/a6
Expand Down
Loading