diff --git a/.gitignore b/.gitignore index 4febd3b..d0b0bbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /bin/ /dist/ +/haul.app/ diff --git a/Makefile b/Makefile index 41c6a96..867b288 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,12 @@ LDFLAGS := -s -w # prefer that toolchain and fall back to whatever `go` is in PATH elsewhere. GO ?= $(shell test -x $(HOME)/.local/go/bin/go && echo $(HOME)/.local/go/bin/go || echo go) -.PHONY: build install test vet check run run-xvfb dist clean +# The packaging tool lives outside the Fyne library repo since v2.5. Pinned and +# run through `go run` so no separate install step is needed; override with +# FYNE=/path/to/fyne if you'd rather use an installed copy. +FYNE ?= $(GO) run fyne.io/tools/cmd/fyne@v1.7.2 + +.PHONY: build install test vet check run run-xvfb dist package-darwin clean build: ## Build a native binary into ./bin/haul $(GO) build -trimpath -ldflags "$(LDFLAGS)" -o bin/haul ./cmd/haul @@ -60,5 +65,20 @@ dist: ## Build the release binary for this host into ./dist $(GO) build -trimpath -ldflags "$(LDFLAGS)" -o dist/haul-linux-amd64 ./cmd/haul @echo "built dist/haul-linux-amd64 (see the Makefile for cross-compiling)" +# Finder hands a bare Unix executable to Terminal.app, so double-clicking the +# raw binary opens a terminal window alongside the GUI. Nothing in the code can +# stop that — the fix is to ship a .app bundle instead, which Finder launches +# directly. `fyne package` writes the Info.plist (CFBundlePackageType APPL and +# friends) and converts cmd/haul/Icon.png into Contents/Resources/icon.icns; the +# rest of the metadata comes from cmd/haul/FyneApp.toml. +# +# Run this ON a Mac: it compiles the binary with the host cgo toolchain, and it +# builds for the host architecture, so an Intel Mac gives an amd64 bundle and +# Apple silicon an arm64 one. The .app is unsigned, so first launch needs +# right-click -> Open (or `xattr -dr com.apple.quarantine haul.app`). +package-darwin: ## Package haul.app for macOS (run this on a Mac) + $(FYNE) package --target darwin --src ./cmd/haul --release + @echo "built ./haul.app — drag it into /Applications" + clean: ## Remove build artifacts - rm -rf bin dist + rm -rf bin dist haul.app diff --git a/README.md b/README.md index 783dda7..f5f9bc2 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,51 @@ Unlike Linux, Windows needs no graphics development *packages* to build: OpenGL ships with the operating system. Getting a usable OpenGL at **run** time is a separate matter — see below. +### Packaging on macOS + +`make build` produces a plain Unix executable, and that is all you need if you +launch haul from a shell. **Double-click it in Finder, though, and macOS opens a +Terminal window alongside the app.** That is not a bug in haul and no build flag +fixes it — it is what Finder does with any bare executable: having no better +idea what a Mach-O file is, it hands it to Terminal.app to run, and the terminal +stays on screen for as long as the process does. macOS has no equivalent of +Windows' `-H=windowsgui`. + +The fix is to ship an application *bundle* — a `haul.app` directory carrying an +`Info.plist` — which Finder launches directly, with a Dock icon and no terminal: + +```sh +make package-darwin # -> ./haul.app +``` + +Then drag `haul.app` into `/Applications`. Run it on a Mac: it compiles with the +host cgo toolchain, and it builds for the host architecture, so an Intel Mac +gives you an `amd64` bundle and Apple silicon an `arm64` one. + +Under the hood that target runs [`fyne +package`](https://docs.fyne.io/started/packaging), which reads its metadata from +`cmd/haul/FyneApp.toml`, converts `cmd/haul/Icon.png` into the bundle's +`.icns` icon, and writes the `Info.plist`. Without `make`: + +```sh +go run fyne.io/tools/cmd/fyne@v1.7.2 package --target darwin --src ./cmd/haul --release +``` + +Note that `fyne package` **rewrites `cmd/haul/FyneApp.toml` in place**, bumping +`Build` on every run and dropping any comments you add to it. That is by design; +commit the bump or discard it as you prefer. + +The bundle is unsigned, so Gatekeeper blocks the first launch on any Mac that +did not build it. Right-click the app and choose **Open** (once — after that it +starts normally), or clear the quarantine flag: + +```sh +xattr -dr com.apple.quarantine /Applications/haul.app +``` + +Signing and notarising properly needs a paid Apple Developer ID, after which +`fyne release --target darwin --certificate ` handles it. + ### Running over Remote Desktop (or in a VM) A build that compiles perfectly will still fail to start in an RDP session with: @@ -269,7 +314,8 @@ Software rendering is slower than a GPU, but haul draws two tables and some text | `make run` | Build, then run (needs a `DISPLAY`) | | `make run-xvfb` | Build, then run against a virtual X display | | `make dist` | Release binary into `./dist` | -| `make clean` | Remove `bin/` and `dist/` | +| `make package-darwin` | macOS `.app` bundle into `./haul.app` (run on a Mac) | +| `make clean` | Remove `bin/`, `dist/` and `haul.app/` | The Makefile picks up a Go toolchain at `~/.local/go/bin/go` if one is there, falling back to whatever `go` is on `PATH` — so it works on machines where Go @@ -297,7 +343,9 @@ toolchain: | `windows/amd64` | `gcc-mingw-w64` | | `darwin/*` | a Mac, or [osxcross](https://github.com/tpoechtrager/osxcross) | -For that reason `make dist` builds only the native binary. The practical route +For that reason `make dist` builds only the native binary — and on macOS the +binary alone is not the artefact you want to hand out, see [Packaging on +macOS](#packaging-on-macos). The practical route to the others is [`fyne-cross`](https://github.com/fyne-io/fyne-cross), which does each build inside a Docker image carrying the right toolchain: diff --git a/cmd/haul/FyneApp.toml b/cmd/haul/FyneApp.toml new file mode 100644 index 0000000..850767d --- /dev/null +++ b/cmd/haul/FyneApp.toml @@ -0,0 +1,14 @@ +Website = "https://gitea.apointless.space/bsncubed/haul" + +[Details] +Icon = "Icon.png" +Name = "haul" +ID = "space.apointless.haul" +Version = "0.1.0" +Build = 1 + +[LinuxAndBSD] +GenericName = "SFTP Client" +Categories = ["Network", "FileTransfer", "Utility"] +Comment = "Two-pane SFTP file browser over SSH" +Keywords = ["sftp", "ssh", "scp", "file transfer"] diff --git a/cmd/haul/Icon.png b/cmd/haul/Icon.png new file mode 100644 index 0000000..f401d81 Binary files /dev/null and b/cmd/haul/Icon.png differ