170 lines
8.1 KiB
Markdown
170 lines
8.1 KiB
Markdown
# gbld — Simple Go Builder & Live-Reloader
|
|
|
|
`gbld` is a hot-reloader and build-automation utility for Go projects. It automatically tracks build numbers, formats source files using `goimports`, compiles the binary, manages the running process, and watches the project directory for changes to trigger automatic rebuilding and restarting.
|
|
|
|
---
|
|
|
|
## Key Features
|
|
|
|
- 🔄 **Hot Reloader**: Automatically watches for file changes (via `fsnotify`), recursively including subdirectories, and rebuilds/restarts your application instantly.
|
|
- 🔢 **Build Counter**: Increments a build number in `build.go` automatically with every compiled build.
|
|
- 🧹 **Auto-Import**: Runs `goimports` on save (optional via `-i`) to keep your imports clean — without touching the rest of your formatting.
|
|
- 🖥️ **Interactive Menu**: Uses a select menu (`gbld.menu.json`) if run without arguments, letting you define and run custom build tasks.
|
|
- 🚀 **Cross-Compilation**: Easily builds binaries for multiple target operating systems (macOS, Linux, Windows) and architectures (amd64, arm64) using a single command.
|
|
- ☁️ **Remote Uploads**: Integrated command to upload build artifacts to a deployment server (`gozilla`).
|
|
- 🔐 **Verified Self-Update**: Downloads updates over HTTPS and refuses to install anything that does not match its published SHA-256 checksum.
|
|
|
|
---
|
|
|
|
## Installation
|
|
|
|
### Prerequisites
|
|
Make sure you have [Go](https://go.dev/) installed and available in your system path. `goimports` is only required if you use the `-i` flag:
|
|
```bash
|
|
go install golang.org/x/tools/cmd/goimports@latest
|
|
```
|
|
|
|
### Building from Source
|
|
Clone the repository and compile `gbld`:
|
|
```bash
|
|
git clone https://git.fhi.mpg.de/mike/gbld.git
|
|
cd gbld
|
|
go build -o /usr/local/bin/gbld
|
|
```
|
|
|
|
---
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
gbld [flags] [target_name]
|
|
```
|
|
> [!NOTE]
|
|
> If `target_name` is omitted, the name of the current directory is used. The tool expects a main source file matching that name (e.g., `target_name.go`). The binary is always built from the package in the current directory, so the module path does not have to match the target name.
|
|
|
|
### CLI Flags
|
|
|
|
| Flag | Argument | Description |
|
|
| :--- | :--- | :--- |
|
|
| `-b` | None | **Build-only** mode (compiles the binary but does not run it). |
|
|
| `-1` | None | Run **once** (does not watch the directory for changes), see [Exit Codes](#exit-codes). |
|
|
| `-i` | None | Runs `goimports` to clean up imports before building. |
|
|
| `-x` | None | Exits after the first successful build and **leaves the started binary running**. |
|
|
| `-o` | `<args>` | Space-separated arguments to pass to the compiled binary on execution. |
|
|
| `-c` | `<command>` | Command to execute immediately after a successful build (before execution). |
|
|
| `-a` | None | Builds binaries for all supported platforms (Windows, macOS, Linux for AMD64/ARM64). |
|
|
| `-u` | None | Uploads built binaries via SSH/SCP to the `gozilla` server. |
|
|
| `-v` | None | Displays the current version of `gbld`. |
|
|
| `-h` | None | Displays help and usage information. |
|
|
|
|
### Environment
|
|
|
|
| Variable | Description |
|
|
| :--- | :--- |
|
|
| `GBLD_NO_UPDATE` | Set to any value to skip the update check at startup (useful offline or in CI). |
|
|
|
|
---
|
|
|
|
## Configuration (`gbld.menu.json`)
|
|
|
|
To make running common tasks easier, you can place a `gbld.menu.json` file in your project directory. If you run `gbld` without any flags, it will parse this file and present an interactive selection menu (entries are shown in alphabetical order):
|
|
|
|
```json
|
|
{
|
|
"Build and Run (hot reload)": ["-i"],
|
|
"Build Only": ["-b", "-i", "-1"],
|
|
"Show Help": ["-h"]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Under the Hood
|
|
|
|
### Build Increment
|
|
When compiling, `gbld` parses `build.go` to find a pattern matching `var build = "<number>"`. It increments this number by 1 and updates the file automatically, leaving the rest of the line (including trailing comments) untouched. This is useful for stamping build numbers/versions inside your binary. If there is no `build.go`, this step is silently skipped.
|
|
|
|
### Target Version
|
|
`-a` and `-u` name their artifacts after the first `var version = "x.y.z"` found in the `*.go` files of the project. Ordinary builds do not need this variable.
|
|
|
|
### Automatic Backups
|
|
Before `gbld` runs `goimports` on a file or modifies `build.go`, it creates a timestamped backup in a `./tmp/` directory inside the project workspace (the directory is created on demand):
|
|
```
|
|
./tmp/gbld.go.20260625145800
|
|
```
|
|
If a backup cannot be written, the file is **not** modified.
|
|
|
|
### File Watching
|
|
The project directory is watched recursively; directories created while `gbld` is running are picked up automatically. Hidden entries (`.git`, …) as well as `bin`, `tmp`, `vendor`, `node_modules` and `testdata` are skipped. Only writes and newly created `.go` files trigger a rebuild — a pure `touch` (mtime only) does not. Rebuilds are debounced by 100 ms and never run in parallel.
|
|
|
|
### Process Management
|
|
When hot-reloading, `gbld` handles process termination gracefully:
|
|
1. It sends an `os.Interrupt` (SIGINT) to the running binary.
|
|
2. It waits up to 1 second for the process to exit clean.
|
|
3. If it does not exit within the timeout, it terminates the process forcefully (`SIGKILL`).
|
|
|
|
`gbld` itself also traps SIGINT/SIGTERM and stops the started binary before exiting, so no orphaned processes are left behind — except with `-x`, where detaching is the point.
|
|
|
|
### Exit Codes
|
|
With `-1`, `gbld` is usable from scripts and CI:
|
|
|
|
| Situation | Exit code |
|
|
| :--- | :--- |
|
|
| Build failed | `1` |
|
|
| `-b -1`, build succeeded | `0` |
|
|
| `-1` without `-b` | exit code of the built program (gbld waits for it) |
|
|
|
|
---
|
|
|
|
## Cross-Compilation and Upload
|
|
|
|
```bash
|
|
gbld -a # build bin/<name>_<version>_<os>_<arch> for all 6 targets
|
|
gbld -u # upload them to gozilla
|
|
```
|
|
|
|
`-a` writes Windows artifacts with an `.exe` suffix and additionally produces:
|
|
|
|
- `bin/checksums.txt` — SHA-256 of every artifact, in the format used by `shasum -a 256 -c`
|
|
- `bin/version.txt` — the published version
|
|
|
|
If any target fails to build, `version.txt` is **not** written and `gbld` exits with `1`, so a half-published version can never be announced. `-u` refuses build names containing anything but `A-Za-z0-9._-` and uploads the artifacts together with `checksums.txt` and `version.txt`.
|
|
|
|
### Self-Update
|
|
On startup `gbld` fetches `version.txt` from the update server (3 s timeout — an unreachable server never blocks a build). If a newer version is published, it asks before downloading, then verifies the download against the SHA-256 from `checksums.txt` before replacing itself. **If no matching checksum is published, the update is refused.** Publish new versions with `gbld -a` followed by `gbld -u`.
|
|
|
|
---
|
|
|
|
## Colors
|
|
|
|
Output uses the [Catppuccin Mocha](https://terminalcolors.com/themes/catppuccin/mocha/) palette as 24-bit color:
|
|
|
|
| Helper | Palette | Hex |
|
|
| :--- | :--- | :--- |
|
|
| `Cr` / `Crb` | Red | `#f38ba8` |
|
|
| `Cg` / `Cgb` | Green | `#a6e3a1` |
|
|
| `Cy` / `Cyb` | Yellow | `#f9e2af` |
|
|
| `Cb` / `Cbb` | Blue | `#89b4fa` |
|
|
| `Cm` / `Cmb` | Pink | `#f5c2e7` |
|
|
| `Cc` / `Ccb` | Teal | `#94e2d5` |
|
|
| `Cw` | Subtext1 | `#bac2de` |
|
|
| `Cwb` | Text | `#cdd6f4` |
|
|
|
|
Mocha maps identical values to the normal and bright ANSI slots, so the bold helpers keep their hue and only add weight. The full palette is available as `CatMauve`, `CatPeach`, `CatLavender`, … in `tools.go`.
|
|
|
|
The interactive prompts (`survey`) are themed as well: their templates resolve colors through `{{color "green+hb"}}`-style names, and `tools.go` replaces that template function with one that maps those names onto the palette. This covers every prompt including its icons — question mark, select arrow, help and error markers — without copying any template.
|
|
|
|
Terminals that do not announce 24-bit color via `COLORTERM` fall back to the basic ANSI colors, so their own theme keeps deciding. `NO_COLOR` and non-TTY output disable colors entirely.
|
|
|
|
---
|
|
|
|
## Development
|
|
|
|
```bash
|
|
go test ./... # unit tests (build counter, version detection, update verification, toolbox)
|
|
go vet ./...
|
|
```
|
|
|
|
> [!NOTE]
|
|
> The sources are deliberately **not** `gofmt`-formatted (2-space indentation). The `-i` flag only replaces the `import (...)` block of a file and leaves the rest of the formatting alone — do not run `gofmt` over the tree.
|