First upload

This commit is contained in:
SuperKali
2025-12-12 07:47:07 +01:00
commit cde3011f64
148 changed files with 20580 additions and 0 deletions

201
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,201 @@
name: Build and Release
on:
push:
branches: [main, master]
tags:
- 'v*'
pull_request:
branches: [main, master]
workflow_dispatch:
# Cancel previous runs on the same branch
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
# Minimum Node.js version (matches package.json engines)
NODE_VERSION: '20'
jobs:
build-linux:
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
arch: amd64
os: ubuntu-22.04
- target: aarch64-unknown-linux-gnu
arch: arm64
os: ubuntu-22.04-arm
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
patchelf \
libssl-dev \
libgtk-3-dev \
squashfs-tools
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
- name: Install npm dependencies
run: npm ci
- name: Build frontend
run: npm run build
- name: Install Tauri CLI
run: cargo install tauri-cli --version "^2" --locked
- name: Build Tauri app
run: cargo tauri build --bundles deb
- name: Upload Linux artifacts
uses: actions/upload-artifact@v4
with:
name: linux-${{ matrix.arch }}
path: |
src-tauri/target/release/bundle/deb/*.deb
if-no-files-found: error
build-macos:
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-apple-darwin
arch: x64
os: macos-13
- target: aarch64-apple-darwin
arch: arm64
os: macos-14
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
- name: Install npm dependencies
run: npm ci
- name: Build frontend
run: npm run build
- name: Install Tauri CLI
run: cargo install tauri-cli --version "^2" --locked
- name: Build Tauri app
run: cargo tauri build --bundles dmg,app
- name: Upload macOS artifacts
uses: actions/upload-artifact@v4
with:
name: macos-${{ matrix.arch }}
path: |
src-tauri/target/release/bundle/dmg/*.dmg
src-tauri/target/release/bundle/macos/*.app
if-no-files-found: error
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri
- name: Install npm dependencies
run: npm ci
- name: Build frontend
run: npm run build
- name: Install Tauri CLI
run: cargo install tauri-cli --version "^2" --locked
- name: Build Tauri app
run: cargo tauri build --bundles msi,nsis
- name: Upload Windows artifacts
uses: actions/upload-artifact@v4
with:
name: windows-x64
path: |
src-tauri/target/release/bundle/msi/*.msi
src-tauri/target/release/bundle/nsis/*.exe
if-no-files-found: error
release:
needs: [build-linux, build-macos, build-windows]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Display structure of downloaded files
run: ls -la artifacts/**/*
- name: Create Release
uses: softprops/action-gh-release@v2
with:
draft: true
generate_release_notes: true
files: |
artifacts/**/*.deb
artifacts/**/*.dmg
artifacts/**/*.msi
artifacts/**/*.exe

49
.gitignore vendored Normal file
View File

@@ -0,0 +1,49 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Dependencies
node_modules
# Build outputs
dist
dist-ssr
/releases/
/dist-releases/
# Local env files
*.local
.env
.env.*
# Editor directories and files
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# OS files
.DS_Store
Thumbs.db
# Tauri
src-tauri/target/
src-tauri/Cargo.lock
# Test coverage
coverage/
# Temporary files
*.tmp
*.temp
.cache

257
README.md Normal file
View File

@@ -0,0 +1,257 @@
<p align="center">
<a href="https://www.armbian.com">
<img src="https://raw.githubusercontent.com/armbian/.github/master/profile/logosmall.png" alt="Armbian logo" width="144">
</a>
</p>
<h1 align="center">Armbian Imager</h1>
<p align="center">
<strong>The official tool for flashing Armbian OS to your single-board computer</strong>
</p>
<p align="center">
<a href="https://github.com/armbian/armbian-imager/releases"><img src="https://img.shields.io/github/v/release/armbian/armbian-imager?style=flat-square" alt="Release"></a>
<a href="https://github.com/armbian/armbian-imager/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-GPLv2-blue?style=flat-square" alt="License"></a>
<a href="https://www.armbian.com"><img src="https://img.shields.io/badge/armbian-supported-orange?style=flat-square" alt="Armbian"></a>
</p>
<p align="center">
<a href="#why-armbian-imager">Why?</a> •
<a href="#features">Features</a> •
<a href="#download">Download</a> •
<a href="#how-it-works">How it works</a> •
<a href="#development">Development</a>
</p>
---
## Why Armbian Imager?
Getting started with single-board computers shouldn't be complicated. Yet, for years, the process of flashing an OS image involved:
- **Hunting for the right image** across multiple download pages
- **Manually verifying checksums** to ensure file integrity
- **Using generic tools** that don't understand SBC specifics
- **Risk of bricking your main drive** with poorly designed software
**Armbian Imager changes everything.**
We built this tool because the Armbian community deserves a first-class experience. With 185+ supported boards from 70+ manufacturers, finding and flashing the right image should be effortless—and now it is.
### The Vision
Inspired by the simplicity of [Raspberry Pi Imager](https://github.com/raspberrypi/rpi-imager), we wanted to bring that same polished experience to the broader SBC ecosystem. But we didn't just copy—we innovated:
- **Native performance** with Rust and Tauri (not Electron's 200MB+ overhead)
- **Touch ID support** on macOS for seamless authentication
- **Real board photos** scraped directly from armbian.com
- **Smart filtering** by kernel type, desktop environment, and release channel
## Features
| Feature | Description |
|---------|-------------|
| **185+ Boards** | Browse every Armbian-supported SBC, organized by manufacturer |
| **Smart Filtering** | Filter by stable/nightly, desktop/server, kernel variant |
| **Safe by Design** | System disks are automatically excluded—no accidents |
| **Verified Writes** | Read-back verification ensures your flash is perfect |
| **Custom Images** | Use your own `.img` or `.img.xz` files |
| **Touch ID** | Authenticate with biometrics on macOS |
| **Light/Dark Mode** | Follows your system preference |
| **Tiny Footprint** | ~15MB app size vs 200MB+ for Electron alternatives |
## Download
<table>
<tr>
<td align="center"><img src="https://cdn.jsdelivr.net/npm/simple-icons@v11/icons/apple.svg" width="48"><br><b>macOS</b></td>
<td align="center"><img src="https://cdn.jsdelivr.net/npm/simple-icons@v11/icons/windows.svg" width="48"><br><b>Windows</b></td>
<td align="center"><img src="https://cdn.jsdelivr.net/npm/simple-icons@v11/icons/linux.svg" width="48"><br><b>Linux</b></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/armbian/armbian-imager/releases">Intel & Apple Silicon<br><code>.dmg</code></a></td>
<td align="center"><a href="https://github.com/armbian/armbian-imager/releases">x64<br><code>.msi</code> / <code>.exe</code></a></td>
<td align="center"><a href="https://github.com/armbian/armbian-imager/releases">x64 & ARM64<br><code>.deb</code></a></td>
</tr>
</table>
## How It Works
```
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 1. SELECT 2. SELECT 3. SELECT 4. FLASH │
│ MANUFACTURER BOARD IMAGE & VERIFY │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌───────┐ │
│ │ Orange │ → │ Pi 5 │ → │ Bookworm│ → │ ██ │ │
│ │ Pi │ │ │ │ Desktop │ │ ████ │ │
│ │ Khadas │ │ Pi 4 │ │ Minimal │ │ ████ │ │
│ │ Radxa │ │ Zero 3 │ │ Nightly │ │ 100% │ │
│ └─────────┘ └─────────┘ └─────────┘ └───────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
1. **Select Manufacturer** — Choose from 70+ SBC manufacturers or load a custom image
2. **Select Board** — Pick your board with real photos from armbian.com
3. **Select Image** — Choose desktop/server, kernel variant, stable/nightly
4. **Flash** — Download, decompress, write, and verify automatically
## Tech Stack
Built with modern technologies for optimal performance:
| Layer | Technology | Why |
|-------|------------|-----|
| **UI** | React 19 + TypeScript | Type-safe, component-based UI |
| **Bundler** | Vite 7 | Lightning-fast HMR and builds |
| **Framework** | Tauri 2 | Native performance, tiny bundle |
| **Backend** | Rust | Memory-safe, blazing fast I/O |
| **Async** | Tokio | Efficient concurrent downloads |
### Why Tauri over Electron?
| Metric | Armbian Imager (Tauri) | Typical Electron App |
|--------|------------------------|---------------------|
| App Size | ~15 MB | 150-200 MB |
| RAM Usage | ~50 MB | 200-400 MB |
| Startup | < 1 second | 2-5 seconds |
| Native Feel | ✅ Uses system webview | ❌ Bundles Chromium |
## Platform Support
| Platform | Architecture | Status | Notes |
|----------|-------------|--------|-------|
| macOS | Intel x64 | ✅ | Full support |
| macOS | Apple Silicon | ✅ | Native ARM64 + Touch ID |
| Windows | x64 | ✅ | Admin elevation via UAC |
| Linux | x64 | ✅ | pkexec for privileges |
| Linux | ARM64 | ✅ | Native ARM64 build |
## Development
### Prerequisites
- **Node.js 20+** (LTS recommended)
- **Rust 1.77+** (install via [rustup](https://rustup.rs))
- **Platform tools**: Xcode (macOS), Visual Studio Build Tools (Windows), or build-essential (Linux)
### Quick Start
```bash
# Clone
git clone https://github.com/armbian/armbian-imager.git
cd armbian-imager
# Install dependencies
npm install
# Run in development mode
npm run tauri:dev
# Build for production
npm run tauri:build
```
### Available Scripts
```bash
# Development
npm run dev # Frontend only (Vite)
npm run tauri:dev # Full app with hot reload
# Production
npm run build # Build frontend
npm run tauri:build # Build distributable
# Utilities
npm run lint # ESLint
npm run clean # Clean all build artifacts
```
### Build Scripts
```bash
# Platform-specific builds (output in releases/)
./scripts/build-macos.sh [--clean] [--dev] # macOS ARM64 + x64
./scripts/build-linux.sh [--clean] [--dev] # Linux x64 + ARM64
./scripts/build-all.sh [--clean] [--dev] # All platforms
```
<details>
<summary><b>Project Structure</b></summary>
```
armbian-imager/
├── src/ # React Frontend
│ ├── components/ # UI Components
│ │ ├── Header.tsx # Progress steps header
│ │ ├── HomePage.tsx # Main wizard interface
│ │ ├── ManufacturerModal.tsx # Manufacturer selection
│ │ ├── BoardModal.tsx # Board selection
│ │ ├── ImageModal.tsx # Image selection
│ │ ├── DeviceModal.tsx # Device selection
│ │ └── FlashProgress/ # Flash operation UI
│ ├── hooks/ # React Hooks
│ ├── config/ # Configuration
│ ├── styles/ # Modular CSS
│ └── assets/ # Images and logos
├── src-tauri/ # Rust Backend
│ ├── src/
│ │ ├── commands/ # Tauri IPC handlers
│ │ ├── devices/ # Platform device detection
│ │ ├── flash/ # Platform flash implementation
│ │ ├── images/ # Image management
│ │ └── utils/ # Utilities
│ ├── icons/ # App icons
│ └── tauri.conf.json # Tauri configuration
├── scripts/ # Build scripts
└── .github/workflows/ # CI/CD
```
</details>
## Data Sources
| Data | Source |
|------|--------|
| Board List | [github.armbian.com/all-images.json](https://github.armbian.com/all-images.json) |
| Board Photos | Scraped from [armbian.com](https://www.armbian.com) board pages |
| Checksums | Embedded in image metadata |
## Contributing
We welcome contributions! Whether it's:
- 🐛 **Bug reports** — Found an issue? [Open a ticket](https://github.com/armbian/armbian-imager/issues)
- 💡 **Feature requests** — Have an idea? Let's discuss it
- 🔧 **Pull requests** — Code improvements are always welcome
- 📖 **Documentation** — Help others get started
### Development Workflow
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## License
This project is part of the [Armbian](https://www.armbian.com) ecosystem and is licensed under the GPLv2.
## Acknowledgments
- **[Raspberry Pi Imager](https://github.com/raspberrypi/rpi-imager)** — The inspiration for this project
- **[Tauri](https://tauri.app/)** — The framework that makes native apps accessible
- **[Armbian Community](https://forum.armbian.com)** — For years of amazing work on SBC support
---
<p align="center">
<sub>Made with ❤️ by the Armbian community</sub>
</p>

View File

@@ -0,0 +1,21 @@
FROM --platform=linux/arm64 rust:1.87-slim-bookworm
# Install build dependencies
RUN apt-get update && apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf build-essential curl wget file libssl-dev libgtk-3-dev squashfs-tools pkg-config nodejs npm && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy project
COPY . .
# Install npm dependencies
RUN npm install
# Build frontend
RUN npm run build
# Build Tauri app for deb
RUN cargo install tauri-cli --version "^2"
RUN cargo tauri build --bundles deb
CMD ["ls", "-la", "src-tauri/target/release/bundle/deb/"]

23
eslint.config.js Normal file
View File

@@ -0,0 +1,23 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
},
])

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/armbian-icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Armbian Imager</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

3466
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

54
package.json Normal file
View File

@@ -0,0 +1,54 @@
{
"name": "armbian-imager",
"private": true,
"version": "1.0.0",
"description": "Flash Armbian OS images to SD cards and USB drives",
"author": "Armbian",
"maintainers": [
"SuperKali <hello@superkali.me>"
],
"type": "module",
"engines": {
"node": ">=20.19.0"
},
"scripts": {
"--dev": "Development commands",
"dev": "vite",
"build:dev": "tsc -b && vite build --mode development",
"tauri:dev": "tauri dev",
"tauri:build:dev": "tauri build --debug",
"--prod": "Production commands",
"build": "tsc -b && vite build",
"build:prod": "tsc -b && vite build --mode production",
"tauri:build": "tauri build",
"tauri:build:prod": "tauri build",
"--other": "Other commands",
"lint": "eslint .",
"preview": "vite preview",
"clean": "rm -rf node_modules dist src-tauri/target",
"tauri": "tauri"
},
"dependencies": {
"@tauri-apps/api": "^2.9.1",
"lucide-react": "^0.560.0",
"react": "^19.2.2",
"react-dom": "^19.2.2"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@tauri-apps/cli": "^2.9.6",
"@types/node": "^24.10.3",
"@types/react": "^19.2.5",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"typescript": "~5.9.3",
"typescript-eslint": "^8.49.0",
"vite": "^7.2.4"
}
}

BIN
public/armbian-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

289
scripts/build-all.sh Executable file
View File

@@ -0,0 +1,289 @@
#!/bin/bash
set -e
# Build script for Armbian Imager - all platforms
# Run from project root: ./scripts/build-all.sh
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
OUTPUT_DIR="$PROJECT_DIR/releases"
cd "$PROJECT_DIR"
# Create output directory (don't clean - allow incremental builds)
mkdir -p "$OUTPUT_DIR"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} Armbian Imager - Multi-Platform Build ${NC}"
echo -e "${BLUE}========================================${NC}"
# Check prerequisites
echo -e "\n${YELLOW}Checking prerequisites...${NC}"
if ! command -v cargo &> /dev/null; then
echo -e "${RED}Error: Rust/Cargo not found. Install from https://rustup.rs${NC}"
exit 1
fi
if ! command -v npm &> /dev/null; then
echo -e "${RED}Error: npm not found. Install Node.js first.${NC}"
exit 1
fi
# Install tauri-cli if needed
if ! cargo tauri --version &> /dev/null 2>&1; then
echo -e "${YELLOW}Installing tauri-cli...${NC}"
cargo install tauri-cli --version "^2"
fi
# Build frontend first
echo -e "\n${YELLOW}Building frontend (mode: $VITE_MODE)...${NC}"
npm ci
npm run build -- --mode "$VITE_MODE"
# ============================================
# macOS Builds (Native)
# ============================================
build_macos() {
echo -e "\n${GREEN}========================================${NC}"
echo -e "${GREEN} Building for macOS${NC}"
echo -e "${GREEN}========================================${NC}"
# Disable GUI interactions for hdiutil/DMG creation
export CI=true
export NONINTERACTIVE=1
# Determine current architecture
CURRENT_ARCH=$(uname -m)
if [ "$CURRENT_ARCH" = "arm64" ]; then
NATIVE_TARGET="aarch64-apple-darwin"
NATIVE_NAME="arm64"
OTHER_TARGET="x86_64-apple-darwin"
OTHER_NAME="x64"
else
NATIVE_TARGET="x86_64-apple-darwin"
NATIVE_NAME="x64"
OTHER_TARGET="aarch64-apple-darwin"
OTHER_NAME="arm64"
fi
# Build native architecture
echo -e "\n${YELLOW}Building macOS $NATIVE_NAME (native)...${NC}"
cargo tauri build $TAURI_BUILD_FLAGS --bundles dmg 2>&1 | tee /tmp/tauri-build.log
# Copy and rename native DMG immediately
echo -e "\n${YELLOW}Copying $NATIVE_NAME artifacts to releases...${NC}"
for f in src-tauri/target/release/bundle/dmg/*.dmg; do
if [ -f "$f" ]; then
BASENAME=$(basename "$f" .dmg)
cp -v "$f" "$OUTPUT_DIR/${BASENAME}_macos_${NATIVE_NAME}.dmg"
fi
done
# Build other architecture
echo -e "\n${YELLOW}Building macOS $OTHER_NAME (cross-compile)...${NC}"
rustup target add "$OTHER_TARGET" 2>/dev/null || true
cargo tauri build $TAURI_BUILD_FLAGS --target "$OTHER_TARGET" --bundles dmg 2>&1 | tee /tmp/tauri-build.log
# Copy and rename cross-compiled DMG immediately
echo -e "\n${YELLOW}Copying $OTHER_NAME artifacts to releases...${NC}"
for f in src-tauri/target/"$OTHER_TARGET"/release/bundle/dmg/*.dmg; do
if [ -f "$f" ]; then
BASENAME=$(basename "$f" .dmg)
cp -v "$f" "$OUTPUT_DIR/${BASENAME}_macos_${OTHER_NAME}.dmg"
fi
done
echo -e "${GREEN}macOS builds complete!${NC}"
echo -e "${GREEN}Files in: $OUTPUT_DIR${NC}"
ls -la "$OUTPUT_DIR"/*.dmg 2>/dev/null || true
}
# ============================================
# Linux Builds (via Docker)
# ============================================
build_linux() {
echo -e "\n${GREEN}========================================${NC}"
echo -e "${GREEN} Building for Linux (via Docker)${NC}"
echo -e "${GREEN}========================================${NC}"
if ! command -v docker &> /dev/null; then
echo -e "${RED}Docker not found, skipping Linux builds${NC}"
return
fi
# Linux x86_64
echo -e "\n${YELLOW}Building Linux x86_64...${NC}"
docker run --rm -v "$PROJECT_DIR":/app -w /app \
--platform linux/amd64 \
debian:bookworm-slim \
bash -c '
apt-get update && apt-get install -y \
curl build-essential \
libwebkit2gtk-4.1-dev libayatana-appindicator3-dev \
librsvg2-dev patchelf libssl-dev libgtk-3-dev \
squashfs-tools pkg-config nodejs npm && \
curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
. "$HOME/.cargo/env" && \
npm ci && npm run build && \
cargo install tauri-cli --version "^2" --locked && \
cargo tauri build --bundles deb || true
'
# Copy x64 artifacts
for f in src-tauri/target/release/bundle/deb/*.deb; do
if [ -f "$f" ]; then
BASENAME=$(basename "$f" .deb)
cp -v "$f" "$OUTPUT_DIR/${BASENAME}_linux_x64.deb"
fi
done
for f in src-tauri/target/release/bundle/appimage/*.AppImage; do
if [ -f "$f" ]; then
BASENAME=$(basename "$f" .AppImage)
cp -v "$f" "$OUTPUT_DIR/${BASENAME}_linux_x64.AppImage"
fi
done
# Clean target for arm64 build
rm -rf src-tauri/target/release/bundle
# Linux ARM64
echo -e "\n${YELLOW}Building Linux ARM64 (this will be slow via emulation)...${NC}"
docker run --rm -v "$PROJECT_DIR":/app -w /app \
--platform linux/arm64 \
debian:bookworm-slim \
bash -c '
apt-get update && apt-get install -y \
curl build-essential \
libwebkit2gtk-4.1-dev libayatana-appindicator3-dev \
librsvg2-dev patchelf libssl-dev libgtk-3-dev \
squashfs-tools pkg-config nodejs npm && \
curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
. "$HOME/.cargo/env" && \
npm ci && npm run build && \
cargo install tauri-cli --version "^2" --locked && \
cargo tauri build --bundles deb || true
'
# Copy ARM64 artifacts
for f in src-tauri/target/release/bundle/deb/*.deb; do
if [ -f "$f" ]; then
BASENAME=$(basename "$f" .deb)
cp -v "$f" "$OUTPUT_DIR/${BASENAME}_linux_arm64.deb"
fi
done
echo -e "${GREEN}Linux builds complete!${NC}"
}
# ============================================
# Windows Build - Not supported locally
# ============================================
build_windows() {
echo -e "\n${YELLOW}========================================${NC}"
echo -e "${YELLOW} Windows Build${NC}"
echo -e "${YELLOW}========================================${NC}"
echo -e ""
echo -e "${RED}Windows builds are not supported locally from macOS/Linux.${NC}"
echo -e ""
echo -e "Tauri requires native Windows tools (WebView2, MSVC) that cannot"
echo -e "be cross-compiled. Use one of these options instead:"
echo -e ""
echo -e " ${GREEN}1. GitHub Actions (recommended)${NC}"
echo -e " Push a tag like 'v0.1.0' to trigger automatic builds"
echo -e " See: .github/workflows/build.yml"
echo -e ""
echo -e " ${GREEN}2. Build on Windows directly${NC}"
echo -e " Run on a Windows machine or VM:"
echo -e " cargo tauri build --bundles msi,nsis"
echo -e ""
}
# ============================================
# Main
# ============================================
# Parse arguments
BUILD_MACOS=false
BUILD_LINUX=false
BUILD_WINDOWS=false
BUILD_ALL=false
DO_CLEAN=false
BUILD_MODE="production" # Default to production
if [ $# -eq 0 ]; then
BUILD_ALL=true
fi
while [[ $# -gt 0 ]]; do
case $1 in
--macos) BUILD_MACOS=true; shift ;;
--linux) BUILD_LINUX=true; shift ;;
--windows) BUILD_WINDOWS=true; shift ;;
--all) BUILD_ALL=true; shift ;;
--clean) DO_CLEAN=true; shift ;;
--dev) BUILD_MODE="development"; shift ;;
--prod) BUILD_MODE="production"; shift ;;
*)
echo "Usage: $0 [--macos] [--linux] [--windows] [--all] [--clean] [--dev] [--prod]"
echo ""
echo " Platforms:"
echo " --macos Build for macOS (x64 and ARM64)"
echo " --linux Build for Linux (x64 and ARM64, requires Docker)"
echo " --windows Build for Windows (x64, requires Docker)"
echo " --all Build all platforms (default if no args)"
echo ""
echo " Build mode:"
echo " --dev Development build (debug, context menu enabled)"
echo " --prod Production build (optimized, context menu disabled) [default]"
echo ""
echo " Other:"
echo " --clean Clean build artifacts before building"
exit 1
;;
esac
done
# Set build flags based on mode
if [ "$BUILD_MODE" = "development" ]; then
echo -e "${YELLOW}Building in DEVELOPMENT mode${NC}"
TAURI_BUILD_FLAGS="--debug"
VITE_MODE="development"
else
echo -e "${GREEN}Building in PRODUCTION mode${NC}"
TAURI_BUILD_FLAGS=""
VITE_MODE="production"
fi
# Clean if requested
if $DO_CLEAN; then
echo -e "${YELLOW}Cleaning build artifacts...${NC}"
rm -rf "$OUTPUT_DIR"
rm -rf "$PROJECT_DIR/src-tauri/target"
rm -rf "$PROJECT_DIR/dist"
fi
if $BUILD_ALL; then
BUILD_MACOS=true
BUILD_LINUX=true
BUILD_WINDOWS=true
fi
# Run builds
$BUILD_MACOS && build_macos
$BUILD_LINUX && build_linux
$BUILD_WINDOWS && build_windows
# Summary
echo -e "\n${BLUE}========================================${NC}"
echo -e "${BLUE} Build Complete!${NC}"
echo -e "${BLUE}========================================${NC}"
echo -e "\nArtifacts in: ${GREEN}$OUTPUT_DIR${NC}\n"
ls -la "$OUTPUT_DIR"

165
scripts/build-linux.sh Executable file
View File

@@ -0,0 +1,165 @@
#!/bin/bash
set -e
# Quick Linux build script - builds via Docker
cd "$(dirname "$0")/.."
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Parse arguments
BUILD_MODE="production"
BUILD_ARCH="all" # all, x64, arm64
CLEAN_BUILD=false
while [[ $# -gt 0 ]]; do
case $1 in
--dev) BUILD_MODE="development"; shift ;;
--prod) BUILD_MODE="production"; shift ;;
--x64) BUILD_ARCH="x64"; shift ;;
--arm64) BUILD_ARCH="arm64"; shift ;;
--clean) CLEAN_BUILD=true; shift ;;
*)
echo "Usage: $0 [--dev] [--prod] [--x64] [--arm64] [--clean]"
echo ""
echo " Build mode:"
echo " --dev Development build (debug symbols, context menu enabled)"
echo " --prod Production build (optimized) [default]"
echo ""
echo " Architecture:"
echo " --x64 Build only x86_64"
echo " --arm64 Build only ARM64"
echo " (default: build both)"
echo ""
echo " Options:"
echo " --clean Clean build artifacts before building"
exit 1
;;
esac
done
# Clean if requested
if [ "$CLEAN_BUILD" = true ]; then
echo -e "${YELLOW}Cleaning build artifacts...${NC}"
rm -rf src-tauri/target
rm -rf dist
rm -rf releases
fi
# Check Docker
if ! command -v docker &> /dev/null; then
echo -e "${RED}Error: Docker not found. Install Docker first.${NC}"
exit 1
fi
# Set build flags
if [ "$BUILD_MODE" = "development" ]; then
echo -e "${YELLOW}Building in DEVELOPMENT mode${NC}"
TAURI_FLAGS="--debug"
VITE_MODE="development"
else
echo -e "${GREEN}Building in PRODUCTION mode${NC}"
TAURI_FLAGS=""
VITE_MODE="production"
fi
# Output directory
OUTPUT_DIR="./releases"
mkdir -p "$OUTPUT_DIR"
# Build x64
build_x64() {
echo -e "\n${GREEN}========================================${NC}"
echo -e "${GREEN} Building Linux x86_64${NC}"
echo -e "${GREEN}========================================${NC}"
docker run --rm -v "$(pwd)":/app -w /app \
--platform linux/amd64 \
rust:bookworm \
bash -c "
apt-get update && apt-get install -y \
libwebkit2gtk-4.1-dev libayatana-appindicator3-dev \
librsvg2-dev patchelf libssl-dev libgtk-3-dev \
squashfs-tools pkg-config nodejs npm && \
npm ci && \
npm run build -- --mode $VITE_MODE && \
cargo install tauri-cli --version '^2' --locked && \
cargo tauri build $TAURI_FLAGS --bundles deb || true
"
# Copy artifacts
for f in src-tauri/target/release/bundle/deb/*.deb; do
if [ -f "$f" ]; then
BASENAME=$(basename "$f" .deb)
cp -v "$f" "$OUTPUT_DIR/${BASENAME}_linux_x64.deb"
fi
done
for f in src-tauri/target/release/bundle/appimage/*.AppImage; do
if [ -f "$f" ]; then
BASENAME=$(basename "$f" .AppImage)
cp -v "$f" "$OUTPUT_DIR/${BASENAME}_linux_x64.AppImage"
fi
done
echo -e "${GREEN}Linux x64 build complete!${NC}"
}
# Build ARM64
build_arm64() {
echo -e "\n${GREEN}========================================${NC}"
echo -e "${GREEN} Building Linux ARM64${NC}"
echo -e "${GREEN}========================================${NC}"
docker run --rm -v "$(pwd)":/app -w /app \
--platform linux/arm64 \
rust:bookworm \
bash -c "
apt-get update && apt-get install -y \
libwebkit2gtk-4.1-dev libayatana-appindicator3-dev \
librsvg2-dev patchelf libssl-dev libgtk-3-dev \
squashfs-tools pkg-config nodejs npm && \
npm ci && \
npm run build -- --mode $VITE_MODE && \
cargo install tauri-cli --version '^2' --locked && \
cargo tauri build $TAURI_FLAGS --bundles deb || true
"
# Copy artifacts
for f in src-tauri/target/release/bundle/deb/*.deb; do
if [ -f "$f" ]; then
BASENAME=$(basename "$f" .deb)
cp -v "$f" "$OUTPUT_DIR/${BASENAME}_linux_arm64.deb"
fi
done
for f in src-tauri/target/release/bundle/appimage/*.AppImage; do
if [ -f "$f" ]; then
BASENAME=$(basename "$f" .AppImage)
cp -v "$f" "$OUTPUT_DIR/${BASENAME}_linux_arm64.AppImage"
fi
done
echo -e "${GREEN}Linux ARM64 build complete!${NC}"
}
# Run builds based on architecture selection
case $BUILD_ARCH in
x64) build_x64 ;;
arm64) build_arm64 ;;
all)
build_x64
# Clean between builds
rm -rf src-tauri/target/release/bundle
build_arm64
;;
esac
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} Linux Build Complete!${NC}"
echo -e "${GREEN}========================================${NC}"
echo -e "Output directory: $OUTPUT_DIR"
ls -la "$OUTPUT_DIR"/*.deb "$OUTPUT_DIR"/*.AppImage 2>/dev/null || true

97
scripts/build-macos.sh Executable file
View File

@@ -0,0 +1,97 @@
#!/bin/bash
set -e
# Quick macOS build script - builds both ARM64 and x86_64
cd "$(dirname "$0")/.."
# Parse arguments
BUILD_MODE="production"
CLEAN_BUILD=false
while [[ $# -gt 0 ]]; do
case $1 in
--dev) BUILD_MODE="development"; shift ;;
--prod) BUILD_MODE="production"; shift ;;
--clean) CLEAN_BUILD=true; shift ;;
*)
echo "Usage: $0 [--dev] [--prod] [--clean]"
echo " --dev Development build (debug symbols, context menu enabled)"
echo " --prod Production build (optimized) [default]"
echo " --clean Clean build artifacts before building"
exit 1
;;
esac
done
# Clean if requested
if [ "$CLEAN_BUILD" = true ]; then
echo "Cleaning build artifacts..."
rm -rf src-tauri/target
rm -rf dist
rm -rf releases
fi
# Set build flags
if [ "$BUILD_MODE" = "development" ]; then
echo "Building in DEVELOPMENT mode"
TAURI_FLAGS="--debug"
VITE_MODE="development"
else
echo "Building in PRODUCTION mode"
TAURI_FLAGS=""
VITE_MODE="production"
fi
# Disable GUI interactions
export CI=true
export NONINTERACTIVE=1
# Output directory
OUTPUT_DIR="./releases"
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"
echo "Building frontend (mode: $VITE_MODE)..."
npm run build -- --mode "$VITE_MODE"
echo ""
echo "========================================="
echo "Building macOS ARM64 (Apple Silicon)..."
echo "========================================="
cargo tauri build $TAURI_FLAGS --bundles dmg 2>&1 || {
echo "DMG failed, trying app bundle only..."
cargo tauri build $TAURI_FLAGS --bundles app
}
# Copy ARM64 artifacts
for f in src-tauri/target/release/bundle/dmg/*.dmg; do
[ -f "$f" ] && cp -v "$f" "$OUTPUT_DIR/$(basename "${f%.dmg}")_macos_arm64.dmg"
done
for f in src-tauri/target/release/bundle/macos/*.app; do
[ -d "$f" ] && cp -rv "$f" "$OUTPUT_DIR/$(basename "${f%.app}")_macos_arm64.app"
done
echo ""
echo "========================================="
echo "Building macOS x86_64 (Intel)..."
echo "========================================="
rustup target add x86_64-apple-darwin 2>/dev/null || true
cargo tauri build $TAURI_FLAGS --target x86_64-apple-darwin --bundles dmg 2>&1 || {
echo "DMG failed, trying app bundle only..."
cargo tauri build $TAURI_FLAGS --target x86_64-apple-darwin --bundles app
}
# Copy x64 artifacts
for f in src-tauri/target/x86_64-apple-darwin/release/bundle/dmg/*.dmg; do
[ -f "$f" ] && cp -v "$f" "$OUTPUT_DIR/$(basename "${f%.dmg}")_macos_x64.dmg"
done
for f in src-tauri/target/x86_64-apple-darwin/release/bundle/macos/*.app; do
[ -d "$f" ] && cp -rv "$f" "$OUTPUT_DIR/$(basename "${f%.app}")_macos_x64.app"
done
echo ""
echo "========================================="
echo "Build complete!"
echo "========================================="
echo "Output directory: $OUTPUT_DIR"
ls -la "$OUTPUT_DIR/"

50
src-tauri/Cargo.toml Normal file
View File

@@ -0,0 +1,50 @@
[package]
name = "armbian-imager"
version = "1.0.0"
description = "Armbian Imager - Flash Armbian OS images to SD cards and USB drives"
authors = ["Armbian", "SuperKali <hello@superkali.me>"]
edition = "2021"
rust-version = "1.77.2"
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = ["macos-private-api"] }
tauri-plugin-shell = "2"
tauri-plugin-dialog = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.12", features = ["json", "stream"] }
futures-util = "0.3"
xz2 = "0.1"
sha2 = "0.10"
hex = "0.4"
scraper = "0.22"
dirs = "5"
once_cell = "1.21.3"
chrono = "0.4"
[target.'cfg(target_os = "linux")'.dependencies]
# Linux-specific dependencies for block device access
[target.'cfg(target_os = "macos")'.dependencies]
# macOS-specific dependencies
libc = "0.2"
security-framework = "2.11"
security-framework-sys = "2.11"
[target.'cfg(target_os = "windows")'.dependencies]
# Windows-specific dependencies
[features]
default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]
[profile.release]
panic = "abort"
codegen-units = 1
lto = true
opt-level = "s"
strip = true

3
src-tauri/build.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -0,0 +1,14 @@
<?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>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.device.usb</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More