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
126 changes: 123 additions & 3 deletions .github/workflows/release-desktop-apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ on:
# Allow manual triggering of the workflow for testing (artifacts will be uploaded to the workflow run, not a release))
workflow_dispatch:

permissions:
contents: write

jobs:
build-and-upload:
runs-on: ubuntu-latest
permissions:
contents: write

strategy:
fail-fast: false
Expand Down Expand Up @@ -84,3 +83,124 @@ jobs:
DotNet6502-Avalonia-${{ matrix.runtime }}.zip
DotNet6502-SadConsole-${{ matrix.runtime }}.zip
checksums-${{ matrix.runtime }}.sha256

update-package-managers:
if: github.event_name == 'release'
needs: build-and-upload
runs-on: ubuntu-latest
steps:
- name: Extract version from tag
id: version
run: |
TAG="${{ github.event.release.tag_name }}"
VERSION="${TAG#v}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"

- name: Download checksum files from release
env:
GH_TOKEN: ${{ github.token }}
run: |
for runtime in osx-arm64 linux-x64 linux-arm64 win-x64 win-arm64; do
gh release download "${{ github.event.release.tag_name }}" \
--repo ${{ github.repository }} \
--pattern "checksums-${runtime}.sha256"
done

- name: Extract SHA256 hashes
id: hashes
run: |
extract_hash() {
grep "DotNet6502-Avalonia-${1}.zip" "checksums-${1}.sha256" | awk '{print $1}'
}
echo "osx_arm64=$(extract_hash osx-arm64)" >> "$GITHUB_OUTPUT"
echo "linux_x64=$(extract_hash linux-x64)" >> "$GITHUB_OUTPUT"
echo "linux_arm64=$(extract_hash linux-arm64)" >> "$GITHUB_OUTPUT"
echo "win_x64=$(extract_hash win-x64)" >> "$GITHUB_OUTPUT"
echo "win_arm64=$(extract_hash win-arm64)" >> "$GITHUB_OUTPUT"

- name: Update Homebrew tap
env:
GH_TOKEN: ${{ secrets.PACKAGE_MANAGER_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
OSX_ARM64_HASH: ${{ steps.hashes.outputs.osx_arm64 }}
LINUX_X64_HASH: ${{ steps.hashes.outputs.linux_x64 }}
LINUX_ARM64_HASH: ${{ steps.hashes.outputs.linux_arm64 }}
run: |
git clone "https://x-access-token:${GH_TOKEN}@github.com/highbyte/homebrew-dotnet-6502.git"
cd homebrew-dotnet-6502

# Update Cask (macOS)
sed -i "s/version \".*\"/version \"${VERSION}\"/" Casks/dotnet-6502.rb
sed -i "s/sha256 \".*\"/sha256 \"${OSX_ARM64_HASH}\"/" Casks/dotnet-6502.rb

# Update Formula (Linux) - use Python for multi-hash replacement
python3 <<'PYEOF'
import re, os

version = os.environ["VERSION"]
linux_x64_hash = os.environ["LINUX_X64_HASH"]
linux_arm64_hash = os.environ["LINUX_ARM64_HASH"]

with open("Formula/dotnet-6502.rb", "r") as f:
content = f.read()

content = re.sub(r'version ".*?"', f'version "{version}"', content)

# Replace hashes in order: first occurrence is x64, second is arm64
hashes = [linux_x64_hash, linux_arm64_hash]
idx = [0]
def replace_hash(m):
if idx[0] < len(hashes):
h = hashes[idx[0]]
idx[0] += 1
return f'sha256 "{h}"'
return m.group(0)
content = re.sub(r'sha256 ".*?"', replace_hash, content)

with open("Formula/dotnet-6502.rb", "w") as f:
f.write(content)
PYEOF

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -A
git diff --cached --quiet || { git commit -m "Update to ${VERSION}" && git push; }

- name: Update Scoop bucket
env:
GH_TOKEN: ${{ secrets.PACKAGE_MANAGER_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
TAG: ${{ steps.version.outputs.tag }}
WIN_X64_HASH: ${{ steps.hashes.outputs.win_x64 }}
WIN_ARM64_HASH: ${{ steps.hashes.outputs.win_arm64 }}
run: |
git clone "https://x-access-token:${GH_TOKEN}@github.com/highbyte/scoop-dotnet-6502.git"
cd scoop-dotnet-6502

python3 <<'PYEOF'
import json, os

version = os.environ["VERSION"]
tag = os.environ["TAG"]
win_x64_hash = os.environ["WIN_X64_HASH"]
win_arm64_hash = os.environ["WIN_ARM64_HASH"]

with open("bucket/dotnet-6502.json", "r") as f:
manifest = json.load(f)

manifest["version"] = version
manifest["architecture"]["64bit"]["url"] = f"https://github.com/highbyte/dotnet-6502/releases/download/{tag}/DotNet6502-Avalonia-win-x64.zip"
manifest["architecture"]["64bit"]["hash"] = win_x64_hash
manifest["architecture"]["arm64"]["url"] = f"https://github.com/highbyte/dotnet-6502/releases/download/{tag}/DotNet6502-Avalonia-win-arm64.zip"
manifest["architecture"]["arm64"]["hash"] = win_arm64_hash

with open("bucket/dotnet-6502.json", "w") as f:
json.dump(manifest, f, indent=4)
f.write("\n")
PYEOF

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -A
git diff --cached --quiet || { git commit -m "Update to ${VERSION}" && git push; }
114 changes: 95 additions & 19 deletions doc/DESKTOP_APPS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,82 @@ The emulator has front-ends written with different technologies, and have somewh
| **SadConsole** | Cross-platform desktop console-style app using SadConsole library. See details [here](APPS_SADCONSOLE.md). |
| **SilkNetNative** | Cross-platform desktop app using Silk.NET + SkiaSharp + shaders for rendering. See details [here](APPS_SILKNET_NATIVE.md). |

## Download
## Install via Package Manager

The **Avalonia** desktop app can be installed via package managers for a simpler experience.

**Prerequisites:** Install [Homebrew](https://brew.sh/) (macOS/Linux) or [Scoop](https://scoop.sh/) (Windows) if you don't have them already.

### macOS (Homebrew)

```bash
brew tap highbyte/dotnet-6502
brew install --cask dotnet-6502
```

### Linux (Homebrew)

```bash
brew tap highbyte/dotnet-6502
brew install --formula dotnet-6502
```

### Windows (Scoop)

```powershell
scoop bucket add dotnet-6502 https://github.com/highbyte/scoop-dotnet-6502
scoop install dotnet-6502
```

### Launching

After installing via a package manager, run the emulator from a terminal:

```sh
dotnet-6502
```

On macOS, the app is also installed to `/Applications` and can be launched from Launchpad, Spotlight, or Finder like any other Mac app.

On Windows (Scoop), a Start Menu shortcut **DotNet6502 Emulator** is also created.

### Updating

```bash
# macOS
brew update && brew upgrade --cask dotnet-6502

# Linux
brew update && brew upgrade --formula dotnet-6502
```

```powershell
# Windows
scoop update
scoop update dotnet-6502
```

### Uninstalling

```bash
# macOS
brew uninstall --cask dotnet-6502
brew untap highbyte/dotnet-6502

# Linux
brew uninstall --formula dotnet-6502
brew untap highbyte/dotnet-6502
```

```powershell
# Windows
scoop uninstall dotnet-6502
scoop bucket rm dotnet-6502
```

---

## Install via manual download

Download the latest release for your platform from the [Releases](https://github.com/highbyte/dotnet-6502/releases) page under Assets.

Expand All @@ -24,22 +99,14 @@ Download the latest release for your platform from the [Releases](https://github
| Linux ARM64 | `DotNet6502-*-linux-arm64.zip` |
| macOS ARM64 (Apple Silicon) | `DotNet6502-*-osx-arm64.zip` |

---
### Prerequisites, compatibility, and troubleshooting
[Avalonia desktop app](APPS_AVALONIA_TROUBLESHOOT.md)
### Launching the Application

[Silk.NET desktop app](APPS_SILKNET_NATIVE_TROUBLESHOOT.md)

[SadConsole desktop app](APPS_SADCONSOLE_TROUBLESHOOT.md)

## Launching the Application

### Windows
#### Windows

1. Extract the `.zip` file to a folder
2. Double-click the `.exe` file to run

#### SmartScreen Warning
##### SmartScreen Warning

Since the application is not code-signed, Windows SmartScreen may show a warning:

Expand All @@ -53,7 +120,7 @@ This warning only appears the first time you run the application.

---

### Linux
#### Linux

1. Extract the `.zip` file:
```sh
Expand All @@ -70,7 +137,7 @@ No security warnings are typically shown on Linux.

---

### macOS
#### macOS

> **Note:** The macOS build is not notarized with Apple. It must be run from Terminal.

Expand All @@ -91,32 +158,41 @@ No security warnings are typically shown on Linux.
./Highbyte.DotNet6502.App.Avalonia.Desktop
```

#### Why can't I double-click to run?
##### Why can't I double-click to run?

macOS Gatekeeper blocks unsigned/non-notarized applications from running via Finder. Running from Terminal with the `xattr -cr .` command removes the quarantine flag and allows execution.

---

## Verifying Download Integrity (Optional)
### Verifying Download Integrity (Optional)

Each release includes SHA256 checksum files (`checksums-*.sha256`) to verify your download hasn't been corrupted or tampered with.

### Windows (PowerShell)
#### Windows (PowerShell)

```powershell
(Get-FileHash -Algorithm SHA256 DotNet6502-Avalonia-win-x64.zip).Hash.ToLower()
```

### Linux
#### Linux

```sh
sha256sum DotNet6502-Avalonia-linux-x64.zip
```

### macOS
#### macOS

```sh
shasum -a 256 DotNet6502-Avalonia-osx-arm64.zip
```

Compare the output with the corresponding entry in the `checksums-*.sha256` file.

---

## Prerequisites, compatibility, and troubleshooting
[Avalonia desktop app](APPS_AVALONIA_TROUBLESHOOT.md)

[Silk.NET desktop app](APPS_SILKNET_NATIVE_TROUBLESHOOT.md)

[SadConsole desktop app](APPS_SADCONSOLE_TROUBLESHOOT.md)
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>..\Highbyte.DotNet6502.App.Avalonia.Core\Assets\favicon.ico</ApplicationIcon>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>DotNet6502</string>
<key>CFBundleDisplayName</key>
<string>DotNet6502 Emulator</string>
<key>CFBundleIdentifier</key>
<string>com.highbyte.dotnet6502</string>
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleExecutable</key>
<string>Highbyte.DotNet6502.App.Avalonia.Desktop</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>LSMinimumSystemVersion</key>
<string>12.0</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,9 @@ public static int Main(string[] args)
// Get config file
// ----------
WriteBootstrapLog($"Creating configuration object.");
var appDir = AppContext.BaseDirectory;
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.SetBasePath(appDir)
.AddJsonFile("appsettings.json")
.AddJsonFile("appsettings.Development.json", optional: true);

Expand Down
Loading
Loading