Krolyxon
Commit 88f3865

Branches

Tags

Refs →

bench5188f3865

Merge pull request #3 from krolyxon/release

Releases, install scripts, and v0.2.0
Author
K
Date
2026-11-01 00:16 +0530
Committer
GitHub · 2026-11-01 00:16 +0530
Parents
83c841a 88ae7ba
Commit
88f3865c749763db190b20db66079c88945198f4

+594 −34

8 files changed

  1. M .github/workflows/ci.yml +25 −4
  2. A .github/workflows/release.yml +178 −0
  3. A CHANGELOG.md +44 −0
  4. M Cargo.lock +3 −3
  5. M Cargo.toml +1 −1
  6. M README.md +64 −26
  7. A install.ps1 +112 −0
  8. A install.sh +167 −0
M .github/workflows/ci.yml View
@@ -2,8 +2,14 @@ name: CI
22
33 on:
44 push:
5+ branches: [master]
56 pull_request:
67
8+# A newer push to the same branch or PR supersedes the running check.
9+concurrency:
10+ group: ci-${{ github.ref }}
11+ cancel-in-progress: true
12+
713 env:
814 CARGO_TERM_COLOR: always
915
@@ -16,7 +22,7 @@ jobs:
1622 os: [ubuntu-latest, windows-latest, macos-latest]
1723 runs-on: ${{ matrix.os }}
1824 steps:
19− - uses: actions/checkout@v4
25+ - uses: actions/checkout@v7
2026 - uses: dtolnay/rust-toolchain@stable
2127 with:
2228 components: clippy
@@ -26,6 +32,21 @@ jobs:
2632 sudo apt-get update
2733 sudo apt-get install -y libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libssl-dev
2834 - uses: Swatinem/rust-cache@v2
29− - run: cargo build --workspace --release
30− - run: cargo test --workspace
31− - run: cargo clippy --workspace --all-targets -- -D warnings
35+ - run: cargo build --workspace --release --locked
36+ - run: cargo test --workspace --locked
37+ - run: cargo clippy --workspace --all-targets --locked -- -D warnings
38+
39+ scripts:
40+ name: install scripts
41+ runs-on: ubuntu-latest
42+ steps:
43+ - uses: actions/checkout@v7
44+ - name: shellcheck install.sh
45+ run: shellcheck install.sh
46+ - name: PSScriptAnalyzer install.ps1
47+ shell: pwsh
48+ run: |
49+ # Write-Host is the right tool for an installer piped into iex.
50+ $issues = Invoke-ScriptAnalyzer -Path install.ps1 -Severity Warning,Error -ExcludeRule PSAvoidUsingWriteHost
51+ $issues | Format-Table -AutoSize
52+ if ($issues) { exit 1 }
A .github/workflows/release.yml View
@@ -0,0 +1,178 @@
1+name: Release
2+
3+# Pushing a tag vX.Y.Z (matching the version in Cargo.toml) builds bench51
4+# for every target, publishes a GitHub release with the archives, checksums
5+# and the CHANGELOG.md section as notes, then installs it with the one-line
6+# installers on each OS. Pull requests that touch the release machinery get
7+# a dry run: everything except publishing.
8+
9+on:
10+ push:
11+ tags: ['v*']
12+ pull_request:
13+ paths:
14+ - .github/workflows/release.yml
15+ - install.sh
16+ - install.ps1
17+ workflow_dispatch:
18+
19+permissions:
20+ contents: read
21+
22+env:
23+ CARGO_TERM_COLOR: always
24+
25+jobs:
26+ build:
27+ name: ${{ matrix.target }}
28+ strategy:
29+ fail-fast: false
30+ matrix:
31+ include:
32+ # 22.04 keeps the glibc requirement low for older distributions.
33+ - { target: x86_64-unknown-linux-gnu, os: ubuntu-22.04 }
34+ - { target: aarch64-unknown-linux-gnu, os: ubuntu-22.04-arm }
35+ - { target: x86_64-pc-windows-msvc, os: windows-latest }
36+ - { target: aarch64-apple-darwin, os: macos-latest }
37+ # Cross-compiled on Apple silicon, so it can't be run here.
38+ - { target: x86_64-apple-darwin, os: macos-latest, cross: true }
39+ runs-on: ${{ matrix.os }}
40+ steps:
41+ - uses: actions/checkout@v7
42+
43+ - name: Check the tag matches Cargo.toml
44+ if: startsWith(github.ref, 'refs/tags/v')
45+ shell: bash
46+ run: |
47+ version=$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -n 1)
48+ if [ "$GITHUB_REF_NAME" != "v$version" ]; then
49+ echo "::error::tag $GITHUB_REF_NAME does not match version $version in Cargo.toml"
50+ exit 1
51+ fi
52+
53+ - uses: dtolnay/rust-toolchain@stable
54+ with:
55+ targets: ${{ matrix.target }}
56+
57+ - name: Install Linux GUI dependencies
58+ if: runner.os == 'Linux'
59+ run: |
60+ sudo apt-get update
61+ sudo apt-get install -y libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libssl-dev
62+
63+ - uses: Swatinem/rust-cache@v2
64+ with:
65+ key: ${{ matrix.target }}
66+
67+ - name: Build
68+ run: cargo build --release --locked --target ${{ matrix.target }} -p bench51 -p bench51-gui
69+
70+ - name: Package
71+ shell: bash
72+ run: |
73+ name=bench51-${{ matrix.target }}
74+ ext=
75+ if [ "$RUNNER_OS" = Windows ]; then ext=.exe; fi
76+ mkdir -p "dist/$name"
77+ cp "target/${{ matrix.target }}/release/bench51$ext" "target/${{ matrix.target }}/release/bench51-gui$ext" "dist/$name/"
78+ cp README.md LICENSE CHANGELOG.md "dist/$name/"
79+ if [ "$RUNNER_OS" = Linux ]; then
80+ mkdir -p "dist/$name/share/applications" "dist/$name/share/icons/hicolor/scalable/apps"
81+ cp crates/bench51-gui/assets/bench51-gui.desktop "dist/$name/share/applications/"
82+ cp crates/bench51-gui/assets/bench51-gui.svg "dist/$name/share/icons/hicolor/scalable/apps/"
83+ fi
84+ cd dist
85+ if [ "$RUNNER_OS" = Windows ]; then
86+ 7z a -tzip "$name.zip" "$name" > /dev/null
87+ else
88+ tar -czf "$name.tar.gz" "$name"
89+ fi
90+ rm -rf "$name"
91+ ls -l
92+
93+ - name: Install the archive and run it
94+ if: runner.os != 'Windows' && !matrix.cross
95+ shell: bash
96+ run: |
97+ sh install.sh --archive "dist/bench51-${{ matrix.target }}.tar.gz" --dir "$RUNNER_TEMP/bin" --no-desktop
98+ "$RUNNER_TEMP/bin/bench51-gui" --version
99+ printf 'ORG 0\nloop: MOV A,#1\n SJMP loop\n END\n' > "$RUNNER_TEMP/t.asm"
100+ "$RUNNER_TEMP/bin/bench51" --assemble "$RUNNER_TEMP/t.asm"
101+ test -s "$RUNNER_TEMP/t.hex"
102+
103+ - name: Install the archive and run it
104+ if: runner.os == 'Windows'
105+ shell: pwsh
106+ run: |
107+ ./install.ps1 -Archive "dist/bench51-${{ matrix.target }}.zip" -InstallDir "$env:RUNNER_TEMP\bench51" -NoShortcut
108+ if ($LASTEXITCODE) { exit $LASTEXITCODE }
109+ # The GUI has no console; check its exit code instead of its output.
110+ $gui = Start-Process -FilePath "$env:RUNNER_TEMP\bench51\bench51-gui.exe" -ArgumentList '--version' -Wait -PassThru
111+ if ($gui.ExitCode -ne 0) { exit 1 }
112+
113+ - uses: actions/upload-artifact@v7
114+ with:
115+ name: bench51-${{ matrix.target }}
116+ path: dist/*
117+ if-no-files-found: error
118+
119+ publish:
120+ needs: build
121+ if: startsWith(github.ref, 'refs/tags/v')
122+ runs-on: ubuntu-latest
123+ permissions:
124+ contents: write
125+ steps:
126+ - uses: actions/checkout@v7
127+
128+ - uses: actions/download-artifact@v8
129+ with:
130+ path: dist
131+ merge-multiple: true
132+
133+ - name: Checksums
134+ run: |
135+ cd dist
136+ sha256sum -- * > SHA256SUMS
137+ cat SHA256SUMS
138+
139+ - name: Release notes from CHANGELOG.md
140+ run: |
141+ version=${GITHUB_REF_NAME#v}
142+ awk -v v="$version" '/^## \[/ { if (on) exit; on = index($0, "[" v "]") } on' CHANGELOG.md | tail -n +2 > notes.md
143+ if [ ! -s notes.md ]; then
144+ echo "::error::CHANGELOG.md has no section for $version"
145+ exit 1
146+ fi
147+ cat notes.md
148+
149+ - name: Publish
150+ env:
151+ GH_TOKEN: ${{ github.token }}
152+ run: gh release create "$GITHUB_REF_NAME" dist/* --verify-tag --title "bench51 $GITHUB_REF_NAME" --notes-file notes.md
153+
154+ # Installs the published release exactly as the README tells people to.
155+ verify:
156+ name: install on ${{ matrix.os }}
157+ needs: publish
158+ strategy:
159+ fail-fast: false
160+ matrix:
161+ os: [ubuntu-latest, macos-latest, windows-latest]
162+ runs-on: ${{ matrix.os }}
163+ steps:
164+ - name: One-line install
165+ if: runner.os != 'Windows'
166+ run: |
167+ curl -fsSL "https://raw.githubusercontent.com/$GITHUB_REPOSITORY/$GITHUB_REF_NAME/install.sh" | sh
168+ "$HOME/.local/bin/bench51" --version | grep -F "${GITHUB_REF_NAME#v}"
169+ "$HOME/.local/bin/bench51-gui" --version | grep -F "${GITHUB_REF_NAME#v}"
170+
171+ - name: One-line install
172+ if: runner.os == 'Windows'
173+ shell: pwsh
174+ run: |
175+ irm "https://raw.githubusercontent.com/$env:GITHUB_REPOSITORY/$env:GITHUB_REF_NAME/install.ps1" | iex
176+ $version = & "$env:LOCALAPPDATA\Programs\bench51\bench51.exe" --version
177+ if ($version -notmatch [regex]::Escape($env:GITHUB_REF_NAME.TrimStart('v'))) { exit 1 }
178+ if (-not (Test-Path "$([Environment]::GetFolderPath('Programs'))\bench51.lnk")) { exit 1 }
A CHANGELOG.md View
@@ -0,0 +1,44 @@
1+# Changelog
2+
3+All notable changes to bench51. The format follows
4+[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and versions follow
5+[Semantic Versioning](https://semver.org/).
6+
7+## [0.2.0] - 2026-11-01
8+
9+### Added
10+
11+- **bench51-gui**, a desktop IDE laid out like Keil µVision: menus, toolbar,
12+ Project window, editor with breakpoint and error gutter, Build Output, and
13+ in a debug session the Registers, Disassembly, Memory, Symbols, UART #1,
14+ Ports, Timers and Interrupts windows. Windows dock and tab anywhere; the
15+ edit and debug layouts are remembered separately.
16+- Monochrome, dot-matrix design in dark and light themes (follows the
17+ system by default), with Space Grotesk, Space Mono and Doto bundled.
18+- µVision's keys (F7, Ctrl-F5, F5, F10/F11, Ctrl-F10/F11, F9) with the
19+ TUI's as aliases; find (Ctrl-F); inline memory editing; clickable SFR
20+ bits and port pins; drag-and-drop to open files.
21+- Prebuilt releases for Linux (x86_64, aarch64), Windows (x86_64) and macOS
22+ (Apple silicon, Intel), with one-line installers: `install.sh` for Linux
23+ and macOS, `install.ps1` for Windows.
24+- CI on Linux, Windows and macOS.
25+
26+### Changed
27+
28+- The assembler, simulator and debugger session moved into a shared
29+ `bench51-core` crate used by both front ends. The terminal app behaves
30+ as before.
31+- Unsafe code is forbidden across the workspace.
32+
33+## [0.1.0] - 2026-10-23
34+
35+### Added
36+
37+- `bench51`, a terminal (TUI) 8051 IDE: editor, two-pass assembler for the
38+ full instruction set with Keil-style listing and Intel HEX output,
39+ simulator with timers, interrupts, UART and ports, and a debugger with
40+ breakpoints, stepping and memory poke.
41+- Headless assembly with `bench51 --assemble`.
42+- Opening Intel HEX files as disassembled, re-assemblable source.
43+
44+[0.2.0]: https://github.com/krolyxon/bench51/releases/tag/v0.2.0
M Cargo.lock View
@@ -485,7 +485,7 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
485485
486486 [[package]]
487487 name = "bench51"
488−version = "0.1.0"
488+version = "0.2.0"
489489 dependencies = [
490490 "bench51-core",
491491 "clap",
@@ -495,11 +495,11 @@ dependencies = [
495495
496496 [[package]]
497497 name = "bench51-core"
498−version = "0.1.0"
498+version = "0.2.0"
499499
500500 [[package]]
501501 name = "bench51-gui"
502−version = "0.1.0"
502+version = "0.2.0"
503503 dependencies = [
504504 "bench51-core",
505505 "clap",
M Cargo.toml View
@@ -2,7 +2,7 @@
22 members = ["crates/*"]
33
44 [workspace.package]
5−version = "0.1.0"
5+version = "0.2.0"
66 edition = "2024"
77
88 [workspace.lints.rust]
M README.md View
@@ -1,12 +1,13 @@
11 # bench51 — an 8051 assembler, simulator & debugger
22
33 [![CI](https://img.shields.io/github/actions/workflow/status/krolyxon/bench51/ci.yml?branch=master&style=flat-square&label=CI&labelColor=000000)](https://github.com/krolyxon/bench51/actions/workflows/ci.yml)
4−[![Version](https://img.shields.io/badge/dynamic/toml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fkrolyxon%2Fbench51%2Fmaster%2FCargo.toml&query=%24.workspace.package.version&label=version&style=flat-square&labelColor=000000&color=333333)](Cargo.toml)
4+[![Release](https://img.shields.io/github/v/release/krolyxon/bench51?style=flat-square&label=release&labelColor=000000&color=333333)](https://github.com/krolyxon/bench51/releases/latest)
5+[![Downloads](https://img.shields.io/github/downloads/krolyxon/bench51/total?style=flat-square&labelColor=000000&color=333333)](https://github.com/krolyxon/bench51/releases)
56 [![Top language](https://img.shields.io/github/languages/top/krolyxon/bench51?style=flat-square&logo=rust&logoColor=white&labelColor=000000&color=333333)](https://github.com/krolyxon/bench51)
67 [![Lines of code](https://img.shields.io/badge/lines%20of%20code-9.8k-333333?style=flat-square&labelColor=000000)](crates)
78 [![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-333333?style=flat-square&labelColor=000000)](Cargo.toml)
89 [![License](https://img.shields.io/github/license/krolyxon/bench51?style=flat-square&labelColor=000000&color=333333)](LICENSE)
9−[![Platforms](https://img.shields.io/badge/platform-Linux%20%7C%20Windows%20%7C%20macOS-333333?style=flat-square&labelColor=000000)](#usage)
10+[![Platforms](https://img.shields.io/badge/platform-Linux%20%7C%20Windows%20%7C%20macOS-333333?style=flat-square&labelColor=000000)](#install)
1011 [![Target](https://img.shields.io/badge/target-Intel%208051%20%28MCS--51%29-D71921?style=flat-square&labelColor=000000)](https://en.wikipedia.org/wiki/Intel_8051)
1112 [![egui](https://img.shields.io/badge/GUI-egui-333333?style=flat-square&labelColor=000000)](https://github.com/emilk/egui)
1213 [![ratatui](https://img.shields.io/badge/TUI-ratatui-333333?style=flat-square&labelColor=000000)](https://ratatui.rs)
@@ -88,32 +89,57 @@ Linux, in a window or right in the terminal.
8889 - **Dark and light themes** in a monochrome, dot-matrix design (Space
8990 Grotesk, Space Mono and Doto, bundled).
9091
91−## Usage
92+## Install
93+
94+Linux and macOS:
9295
9396 ```bash
94−cargo install --path crates/bench51-gui # installs `bench51-gui`
97+curl -fsSL https://raw.githubusercontent.com/krolyxon/bench51/master/install.sh | sh
98+```
99+
100+Windows (PowerShell):
95101
96−cargo run --release -p bench51-gui # welcome screen
97−cargo run --release -p bench51-gui -- examples/*.asm # open several files
98−cargo run --release -p bench51-gui -- firmware.hex # disassemble & debug a HEX file
99−cargo run --release -p bench51-gui -- --theme light
102+```powershell
103+irm https://raw.githubusercontent.com/krolyxon/bench51/master/install.ps1 | iex
100104 ```
101105
102−`--theme system|dark|light` overrides the theme chosen in View → Theme, and
103−`--clock <MHz>` the Xtal set in Project → Options for Target (default
104−11.0592), which is used for the elapsed-time display.
106+Both install `bench51-gui` and `bench51` from the
107+[latest release](https://github.com/krolyxon/bench51/releases/latest) and
108+verify the download against its SHA-256 checksum:
105109
106−On Linux it runs on Wayland and X11 and uses the XDG desktop portal for file
107−dialogs. To add it to your application launcher:
110+- **Linux and macOS:** the binaries go into `~/.local/bin`, and on Linux the
111+ app is added to your application menu. Options go after `sh -s --`:
112+ `--version v0.2.0` pins a release, `--dir /usr/local/bin` picks another
113+ directory, `--archive <file>` installs a downloaded archive offline
114+ (handy on lab PCs), and `--uninstall` removes it.
115+- **Windows:** it installs to `%LOCALAPPDATA%\Programs\bench51`, adds that to
116+ your PATH and adds a Start menu entry. `-Uninstall` removes it.
117+
118+Prebuilt binaries cover Linux (x86_64, aarch64), Windows (x86_64) and macOS
119+(Apple silicon, Intel). To build from source instead, with a Rust toolchain:
108120
109121 ```bash
110−install -Dm644 crates/bench51-gui/assets/bench51-gui.desktop ~/.local/share/applications/bench51-gui.desktop
111−install -Dm644 crates/bench51-gui/assets/bench51-gui.svg ~/.local/share/icons/hicolor/scalable/apps/bench51-gui.svg
122+cargo install --locked --git https://github.com/krolyxon/bench51 bench51-gui # the desktop app
123+cargo install --locked --git https://github.com/krolyxon/bench51 bench51 # the terminal app
112124 ```
113125
114−It also builds for Windows and macOS. On Debian or Ubuntu, first install the
115−packages egui needs: `libxcb-render0-dev libxcb-shape0-dev
116−libxcb-xfixes0-dev libxkbcommon-dev libssl-dev`.
126+## Usage
127+
128+```bash
129+bench51-gui # welcome screen
130+bench51-gui examples/*.asm # open several files
131+bench51-gui firmware.hex # disassemble & debug a HEX file
132+bench51-gui --theme light
133+```
134+
135+`--theme system|dark|light` overrides the theme chosen in View → Theme, and
136+`--clock <MHz>` the Xtal set in Project → Options for Target (default
137+11.0592), which is used for the elapsed-time display.
138+
139+On Linux it runs on Wayland and X11 and uses the XDG desktop portal for file
140+dialogs. Building it from source on Debian or Ubuntu needs the packages egui
141+links against: `libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
142+libxkbcommon-dev libssl-dev`.
117143
118144 ## Keys
119145
@@ -168,15 +194,13 @@ Makefiles.
168194 </table>
169195
170196 ```bash
171−cargo install --path . # installs the `bench51` binary
172−
173−cargo run --release -- examples/serial_hello.asm # open in the TUI
174−cargo run --release # start with a template
175−cargo run --release -- firmware.hex # disassemble & debug a HEX file
197+bench51 examples/serial_hello.asm # open in the TUI
198+bench51 # start with a template
199+bench51 firmware.hex # disassemble & debug a HEX file
176200
177201 # Headless assembly: writes prog.hex and prog.lst
178−cargo run --release -- --assemble prog.asm
179−cargo run --release -- --assemble prog.asm -o out.hex --lst out.lst
202+bench51 --assemble prog.asm
203+bench51 --assemble prog.asm -o out.hex --lst out.lst
180204 ```
181205
182206 `--clock <MHz>` sets the oscillator frequency used for the elapsed-time display
@@ -235,10 +259,24 @@ Letter shortcuts work too, for terminals that swallow function keys:
235259 ## Development
236260
237261 ```bash
238−cargo test --workspace # assembler, CPU, peripheral, session and example-program tests
262+cargo run --release -p bench51-gui # the desktop app
263+cargo run --release -p bench51 # the terminal app
264+cargo test --workspace # assembler, CPU, peripheral, session and example-program tests
239265 cargo clippy --workspace --all-targets
240266 ```
241267
268+Releasing: bump `version` in `Cargo.toml`, add a section to
269+[CHANGELOG.md](CHANGELOG.md), merge, then tag and push:
270+
271+```bash
272+git tag v0.3.0 && git push origin v0.3.0
273+```
274+
275+The release workflow checks that the tag matches `Cargo.toml` and builds
276+every target. It publishes the archives and `SHA256SUMS` with that
277+changelog section as the release notes, then installs the result with the
278+one-liners on Linux, macOS and Windows.
279+
242280 Code layout:
243281
244282 - `crates/bench51-gui/` is the `bench51-gui` desktop app (egui).
A install.ps1 View
@@ -0,0 +1,112 @@
1+# Installs bench51 (the bench51-gui desktop app and the bench51 terminal app)
2+# from the GitHub releases, on Windows.
3+#
4+# irm https://raw.githubusercontent.com/krolyxon/bench51/master/install.ps1 | iex
5+#
6+# With options:
7+#
8+# & ([scriptblock]::Create((irm https://raw.githubusercontent.com/krolyxon/bench51/master/install.ps1))) -Version v0.2.0
9+#
10+# Options: -Version <tag> (default latest), -InstallDir <path> (default
11+# %LOCALAPPDATA%\Programs\bench51), -Archive <bench51-<target>.zip>,
12+# -NoShortcut, -Uninstall. BENCH51_VERSION and BENCH51_INSTALL_DIR set the
13+# defaults for -Version and -InstallDir when piping into iex.
14+
15+param(
16+ [string]$Version = $(if ($env:BENCH51_VERSION) { $env:BENCH51_VERSION } else { 'latest' }),
17+ [string]$InstallDir = $(if ($env:BENCH51_INSTALL_DIR) { $env:BENCH51_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA 'Programs\bench51' }),
18+ [string]$Archive,
19+ [switch]$NoShortcut,
20+ [switch]$Uninstall
21+)
22+
23+$ErrorActionPreference = 'Stop'
24+# Invoke-WebRequest is much slower with the progress bar on.
25+$ProgressPreference = 'SilentlyContinue'
26+[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
27+
28+$Repo = 'krolyxon/bench51'
29+$Asset = 'bench51-x86_64-pc-windows-msvc.zip'
30+$Shortcut = Join-Path ([Environment]::GetFolderPath('Programs')) 'bench51.lnk'
31+
32+function Write-Step([string]$Message) {
33+ Write-Host "bench51: $Message"
34+}
35+
36+# Adds or removes $Dir in the user's PATH.
37+function Edit-UserPath([string]$Dir, [bool]$Add) {
38+ $current = [Environment]::GetEnvironmentVariable('Path', 'User')
39+ $parts = @(($current -split ';') | Where-Object { $_ -and ($_.TrimEnd('\') -ne $Dir.TrimEnd('\')) })
40+ if ($Add) {
41+ $parts += $Dir
42+ }
43+ [Environment]::SetEnvironmentVariable('Path', ($parts -join ';'), 'User')
44+}
45+
46+if ($Uninstall) {
47+ Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $InstallDir
48+ Remove-Item -Force -ErrorAction SilentlyContinue $Shortcut
49+ Edit-UserPath $InstallDir $false
50+ Write-Step "removed bench51 from $InstallDir"
51+ return
52+}
53+
54+$Temp = Join-Path ([IO.Path]::GetTempPath()) ("bench51-" + [guid]::NewGuid())
55+New-Item -ItemType Directory -Path $Temp | Out-Null
56+try {
57+ if (-not $Archive) {
58+ if ($Version -eq 'latest') {
59+ $Base = "https://github.com/$Repo/releases/latest/download"
60+ } else {
61+ if (-not $Version.StartsWith('v')) {
62+ $Version = "v$Version"
63+ }
64+ $Base = "https://github.com/$Repo/releases/download/$Version"
65+ }
66+ Write-Step "downloading $Asset ($Version)"
67+ $Archive = Join-Path $Temp $Asset
68+ $Sums = Join-Path $Temp 'SHA256SUMS'
69+ Invoke-WebRequest -UseBasicParsing -Uri "$Base/$Asset" -OutFile $Archive
70+ Invoke-WebRequest -UseBasicParsing -Uri "$Base/SHA256SUMS" -OutFile $Sums
71+ $line = Get-Content $Sums | Where-Object { $_ -match ('\s\*?' + [regex]::Escape($Asset) + '$') } | Select-Object -First 1
72+ if (-not $line) {
73+ throw "$Asset is not listed in SHA256SUMS"
74+ }
75+ $expected = ($line -split '\s+')[0].ToLowerInvariant()
76+ $actual = (Get-FileHash -Algorithm SHA256 -Path $Archive).Hash.ToLowerInvariant()
77+ if ($actual -ne $expected) {
78+ throw "checksum mismatch for $Asset"
79+ }
80+ }
81+ if (-not (Test-Path $Archive)) {
82+ throw "no such archive: $Archive"
83+ }
84+
85+ $Extracted = Join-Path $Temp 'x'
86+ Expand-Archive -Path $Archive -DestinationPath $Extracted -Force
87+ $gui = Get-ChildItem -Path $Extracted -Recurse -Filter 'bench51-gui.exe' | Select-Object -First 1
88+ if (-not $gui) {
89+ throw 'the archive has no bench51-gui.exe'
90+ }
91+
92+ New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
93+ Copy-Item -Path (Join-Path $gui.DirectoryName '*') -Destination $InstallDir -Recurse -Force
94+ Edit-UserPath $InstallDir $true
95+ $env:Path = "$env:Path;$InstallDir"
96+ Write-Step "installed bench51 and bench51-gui to $InstallDir"
97+
98+ if (-not $NoShortcut) {
99+ $shell = New-Object -ComObject WScript.Shell
100+ $link = $shell.CreateShortcut($Shortcut)
101+ $link.TargetPath = Join-Path $InstallDir 'bench51-gui.exe'
102+ $link.WorkingDirectory = $env:USERPROFILE
103+ $link.Description = 'Intel 8051 assembler, simulator and debugger'
104+ $link.Save()
105+ Write-Step 'added bench51 to the Start menu'
106+ }
107+
108+ & (Join-Path $InstallDir 'bench51.exe') --version
109+ Write-Step 'open a new terminal to use bench51 and bench51-gui from PATH'
110+} finally {
111+ Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $Temp
112+}
A install.sh View
@@ -0,0 +1,167 @@
1+#!/bin/sh
2+# Installs bench51 (the bench51-gui desktop app and the bench51 terminal app)
3+# from the GitHub releases, on Linux and macOS.
4+#
5+# curl -fsSL https://raw.githubusercontent.com/krolyxon/bench51/master/install.sh | sh
6+# curl -fsSL https://raw.githubusercontent.com/krolyxon/bench51/master/install.sh | sh -s -- --dir /usr/local/bin
7+#
8+# Run with --help for all options. On Windows, use install.ps1.
9+
10+set -eu
11+
12+REPO=krolyxon/bench51
13+VERSION=${BENCH51_VERSION:-latest}
14+DIR=${BENCH51_INSTALL_DIR:-$HOME/.local/bin}
15+ARCHIVE=
16+DESKTOP=1
17+UNINSTALL=0
18+
19+DATA=${XDG_DATA_HOME:-$HOME/.local/share}
20+APPS=$DATA/applications
21+ICONS=$DATA/icons/hicolor/scalable/apps
22+
23+usage() {
24+ cat <<EOF
25+Install bench51 from https://github.com/$REPO/releases
26+
27+Usage: install.sh [options]
28+
29+ --version <tag> release to install, e.g. v0.2.0 (default: latest)
30+ --dir <path> where to put the binaries (default: ~/.local/bin)
31+ --archive <file> install from a downloaded bench51-<target>.tar.gz
32+ --no-desktop on Linux, skip the application menu entry and icon
33+ --uninstall remove bench51 from --dir and the menu
34+ -h, --help show this help
35+
36+The environment variables BENCH51_VERSION and BENCH51_INSTALL_DIR set the
37+defaults for --version and --dir.
38+EOF
39+}
40+
41+say() { printf 'bench51: %s\n' "$*"; }
42+die() {
43+ printf 'bench51: error: %s\n' "$*" >&2
44+ exit 1
45+}
46+
47+while [ $# -gt 0 ]; do
48+ case $1 in
49+ --version) [ $# -ge 2 ] || die "--version needs a value"; VERSION=$2; shift 2 ;;
50+ --version=*) VERSION=${1#*=}; shift ;;
51+ --dir) [ $# -ge 2 ] || die "--dir needs a value"; DIR=$2; shift 2 ;;
52+ --dir=*) DIR=${1#*=}; shift ;;
53+ --archive) [ $# -ge 2 ] || die "--archive needs a value"; ARCHIVE=$2; shift 2 ;;
54+ --archive=*) ARCHIVE=${1#*=}; shift ;;
55+ --no-desktop) DESKTOP=0; shift ;;
56+ --uninstall) UNINSTALL=1; shift ;;
57+ -h | --help) usage; exit 0 ;;
58+ *) die "unknown option: $1 (see --help)" ;;
59+ esac
60+done
61+
62+refresh_menu() {
63+ if command -v update-desktop-database >/dev/null 2>&1; then
64+ update-desktop-database -q "$APPS" 2>/dev/null || true
65+ fi
66+}
67+
68+if [ "$UNINSTALL" = 1 ]; then
69+ rm -f "$DIR/bench51" "$DIR/bench51-gui" "$APPS/bench51-gui.desktop" "$ICONS/bench51-gui.svg"
70+ refresh_menu
71+ say "removed bench51 from $DIR"
72+ exit 0
73+fi
74+
75+# ---- Which build fits this machine ----
76+
77+os=$(uname -s)
78+arch=$(uname -m)
79+case $os in
80+Linux) os=unknown-linux-gnu ;;
81+Darwin) os=apple-darwin ;;
82+*) die "no prebuilt binaries for $os; on Windows use install.ps1" ;;
83+esac
84+case $arch in
85+x86_64 | amd64) arch=x86_64 ;;
86+aarch64 | arm64) arch=aarch64 ;;
87+*) die "no prebuilt binaries for $arch; build from source with: cargo install --git https://github.com/$REPO bench51-gui" ;;
88+esac
89+TARGET=$arch-$os
90+NAME=bench51-$TARGET.tar.gz
91+
92+download() {
93+ if command -v curl >/dev/null 2>&1; then
94+ curl --proto '=https' --tlsv1.2 -fsSL -o "$2" "$1"
95+ elif command -v wget >/dev/null 2>&1; then
96+ wget -q --https-only -O "$2" "$1"
97+ else
98+ die "neither curl nor wget is installed"
99+ fi
100+}
101+
102+sha256() {
103+ if command -v sha256sum >/dev/null 2>&1; then
104+ sha256sum "$1" | cut -d ' ' -f 1
105+ elif command -v shasum >/dev/null 2>&1; then
106+ shasum -a 256 "$1" | cut -d ' ' -f 1
107+ else
108+ die "neither sha256sum nor shasum is installed to verify the download"
109+ fi
110+}
111+
112+TMP=$(mktemp -d 2>/dev/null || mktemp -d -t bench51)
113+trap 'rm -rf "$TMP"' EXIT
114+trap 'exit 130' INT TERM
115+
116+# ---- Download and verify ----
117+
118+if [ -z "$ARCHIVE" ]; then
119+ if [ "$VERSION" = latest ]; then
120+ BASE=https://github.com/$REPO/releases/latest/download
121+ else
122+ case $VERSION in v*) ;; *) VERSION=v$VERSION ;; esac
123+ BASE=https://github.com/$REPO/releases/download/$VERSION
124+ fi
125+ say "downloading $NAME ($VERSION)"
126+ download "$BASE/$NAME" "$TMP/$NAME" || die "could not download $BASE/$NAME"
127+ download "$BASE/SHA256SUMS" "$TMP/SHA256SUMS" || die "could not download the checksums"
128+ expected=$(grep " [* ]*$NAME\$" "$TMP/SHA256SUMS" | cut -d ' ' -f 1)
129+ [ -n "$expected" ] || die "$NAME is not listed in SHA256SUMS"
130+ [ "$(sha256 "$TMP/$NAME")" = "$expected" ] || die "checksum mismatch for $NAME"
131+ ARCHIVE=$TMP/$NAME
132+fi
133+[ -f "$ARCHIVE" ] || die "no such archive: $ARCHIVE"
134+
135+mkdir "$TMP/x"
136+tar -xzf "$ARCHIVE" -C "$TMP/x"
137+SRC=$(find "$TMP/x" -type f -name bench51-gui | head -n 1)
138+[ -n "$SRC" ] || die "the archive has no bench51-gui"
139+SRC=$(dirname "$SRC")
140+[ -f "$SRC/bench51" ] || die "the archive has no bench51"
141+
142+# ---- Install ----
143+
144+mkdir -p "$DIR"
145+for bin in bench51 bench51-gui; do
146+ cp "$SRC/$bin" "$DIR/$bin.tmp"
147+ chmod 755 "$DIR/$bin.tmp"
148+ mv -f "$DIR/$bin.tmp" "$DIR/$bin"
149+done
150+say "installed bench51 and bench51-gui to $DIR"
151+
152+if [ "$DESKTOP" = 1 ] && [ "$(uname -s)" = Linux ] && [ -f "$SRC/share/applications/bench51-gui.desktop" ]; then
153+ mkdir -p "$APPS" "$ICONS"
154+ # Launchers don't always see ~/.local/bin on PATH: point at the binary.
155+ exec_path=$(printf '%s' "$DIR/bench51-gui" | sed 's/[\\&|]/\\&/g')
156+ sed "s|^Exec=bench51-gui|Exec=\"$exec_path\"|" \
157+ "$SRC/share/applications/bench51-gui.desktop" >"$APPS/bench51-gui.desktop"
158+ cp "$SRC/share/icons/hicolor/scalable/apps/bench51-gui.svg" "$ICONS/bench51-gui.svg"
159+ refresh_menu
160+ say "added bench51 to the application menu"
161+fi
162+
163+"$DIR/bench51" --version
164+case ":$PATH:" in
165+*":$DIR:"*) say "run bench51-gui for the desktop app, or bench51 in a terminal" ;;
166+*) say "$DIR is not on your PATH; add it, e.g. in ~/.profile: export PATH=\"$DIR:\$PATH\"" ;;
167+esac