104 lines
7.3 KiB
Markdown
104 lines
7.3 KiB
Markdown
# 🚀 G-Launcher Updater & Bootstrap Build System
|
|
|
|
เอกสารนี้อธิบายรายละเอียดเชิงลึกของระบบ **Auto-Update & Local Build Bootstrap** ของ G-Launcher ซึ่งถูกออกแบบมาเพื่อรองรับกรณีที่ผู้ใช้หรือเซิร์ฟเวอร์ Git (เช่น Gitea) ไม่มี CI/CD Runner บนคลาวด์สำหรับคอมไพล์ไบนารีล่วงหน้า
|
|
|
|
---
|
|
|
|
## 🎯 กฎเหล็กของระบบอัปเดต (The Golden Updater Rule)
|
|
|
|
> **"โหลด Temp มา -> Build ใหม่ใน Temp -> นำมาแทนของเก่า -> ลบ Temp ทิ้ง 100%"**
|
|
|
|
### เหตุผลทางสถาปัตยกรรม (Architectural Rationale)
|
|
1. **ป้องกัน Windows File Lock:** ระบบปฏิบัติการ Windows จะล็อกไฟล์ `.exe` ที่กำลังทำงานอยู่ทันที ทำให้ไม่สามารถเขียนทับ (overwrite) ตัวเองได้โดยตรง แต่ Windows อนุญาตให้ **เปลี่ยนชื่อ (Rename)** ไฟล์ executable ที่กำลังทำงานอยู่ได้
|
|
2. **รักษาความสะอาดของโปรเจกต์ (Zero Pollution):** ไม่ทำการ build หรือ pull โค้ดทับโฟลเดอร์ทำงานหลักโดยตรง เพื่อป้องกันไฟล์ขยะหรือ node_modules ปนเปื้อน
|
|
3. **Atomic Rollback:** หากกระบวนการคอมไพล์ใน Temp ล้มเหลว โปรแกรมเวอร์ชันเดิมจะยังคงทำงานได้สมบูรณ์ ไม่เสียหาย
|
|
|
|
---
|
|
|
|
## 🔄 วงจรชีวิตของระบบอัปเดต (Updater Lifecycle)
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
autonumber
|
|
actor User as ผู้ใช้งาน / Contributor
|
|
participant Bootstrap as bootstrap.ps1 / Go GitService
|
|
participant TempDir as โฟลเดอร์ชั่วคราว (Temp)
|
|
participant Git as Git Repository (Dev Branch)
|
|
participant Target as bin/G-Launcher.exe
|
|
|
|
User->>Bootstrap: รัน update-and-build.bat หรือกด Update ใน UI
|
|
Note over Bootstrap: ตรวจสอบและเตรียม Portable Git, Go, Node.js (tools/)
|
|
Bootstrap->>TempDir: 1. สร้างโฟลเดอร์ชั่วคราว (temp/build_workspace)
|
|
Bootstrap->>Git: 2. Clone โค้ดสาขา Dev ลงใน TempDir
|
|
Git-->>TempDir: ดาวน์โหลดซอร์สโค้ดสำเร็จ
|
|
|
|
rect rgb(30, 40, 60)
|
|
Note over TempDir: 3. บิลด์ทั้งหมดภายใน TempDir
|
|
TempDir->>TempDir: npm install & npm run build (React Frontend)
|
|
TempDir->>TempDir: go mod tidy
|
|
TempDir->>TempDir: wails3 generate syso (Manifest & Icon)
|
|
TempDir->>TempDir: go build -tags production -> bin/G-Launcher.exe
|
|
end
|
|
|
|
rect rgb(40, 60, 40)
|
|
Note over Bootstrap,Target: 4. สลับไฟล์ไบนารี (Atomic Swap & Rollback)
|
|
Bootstrap->>Target: เปลี่ยนชื่อตัวเก่าเป็น G-Launcher.exe.old
|
|
Bootstrap->>Target: ย้ายตัวใหม่จาก TempDir มาแทนที่ Target
|
|
alt ย้ายไฟล์สำเร็จ
|
|
Bootstrap->>Target: ลบไฟล์ G-Launcher.exe.old
|
|
else เกิดข้อผิดพลาด
|
|
Bootstrap->>Target: Rollback ย้าย .old กลับมาเป็นตัวหลัก
|
|
end
|
|
end
|
|
|
|
rect rgb(60, 30, 30)
|
|
Note over Bootstrap,TempDir: 5. ล้างและทำลายโฟลเดอร์ชั่วคราว (finally / defer)
|
|
Bootstrap->>TempDir: ลบโฟลเดอร์ TempDir ทั้งหมด (Purge 100%)
|
|
end
|
|
|
|
Bootstrap->>Target: 6. รัน G-Launcher.exe เวอร์ชันใหม่
|
|
```
|
|
|
|
---
|
|
|
|
## 🛠️ ไฟล์ที่เกี่ยวข้องและการทำงาน
|
|
|
|
### 1. [`update-and-build.bat`](../update-and-build.bat)
|
|
* สคริปต์ Batch สั้นๆ สำหรับดับเบิลคลิกบน Windows
|
|
* ตั้งค่า UTF-8 (`chcp 65001`) และส่งต่อการทำงานไปยัง `scripts/bootstrap.ps1` ผ่านคำสั่ง:
|
|
```cmd
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\bootstrap.ps1" %*
|
|
```
|
|
|
|
### 2. [`scripts/bootstrap.ps1`](../scripts/bootstrap.ps1)
|
|
* **การตรวจหาและดาวน์โหลดเครื่องมือพกพา (Prerequisites):**
|
|
* `Git`: หากในเครื่องไม่มี จะดาวน์โหลด **Portable MinGit** มาไว้ที่ `tools/mingit/`
|
|
* `Go`: หากไม่มี Go compiler จะดาวน์โหลด **Portable Go 1.24** มาไว้ที่ `tools/go/`
|
|
* `Node.js & npm`: หากไม่มี Node.js จะดาวน์โหลด **Portable Node.js v22** มาไว้ที่ `tools/node/`
|
|
* `Wails v3 CLI`: ติดตั้งผ่าน `go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-alpha.74`
|
|
* **Isolated Temp Build:**
|
|
* ใช้โฟลเดอร์ `$tempBuildDir = Join-Path $rootDir "temp\build_workspace"`
|
|
* สั่ง `git clone --depth 1 --branch Dev <RepoUrl> $tempBuildDir`
|
|
* รัน `npm install`, `npm run build`, และ `go build` ภายใน Temp
|
|
* **Atomic Replacement & Rollback:**
|
|
* เปลี่ยนชื่อ `bin/G-Launcher.exe` เดิมเป็น `.old`
|
|
* ย้ายตัวใหม่เข้ามาแทนที่ หากล้มเหลวจะคืนค่า `.old` ทันที
|
|
* **Guaranteed Cleanup:**
|
|
* วางคำสั่งลบโฟลเดอร์ชั่วคราวไว้ในบล็อก `finally { ... }` เพื่อรับประกันว่าจะถูกลบออก 100% แม้สคริปต์จะหยุดทำงานกลางคัน
|
|
|
|
### 3. Go Backend: [`internal/git-service/launcher.go`](../internal/git-service/launcher.go)
|
|
* ฟังก์ชัน [`BuildAndUpdateFromSource(branch string)`](../internal/git-service/launcher.go#L95) ใน `GitService`:
|
|
```go
|
|
// 1. สร้างโฟลเดอร์ชั่วคราว
|
|
tempDir, err := os.MkdirTemp("", "g-launcher-build-*")
|
|
defer os.RemoveAll(tempDir) // รับประกันการลบโฟลเดอร์ Temp เสมอ
|
|
|
|
// 2. Clone โค้ดต้นทาง
|
|
cloneCmd := exec.Command(gitExe, "clone", "--depth", "1", "--branch", branch, constant.LauncherRepoURL, tempDir)
|
|
...
|
|
// 3. Build ใน Temp
|
|
...
|
|
// 4. สลับไฟล์ที่กำลังรันอยู่ด้วย selfupdate.Apply
|
|
err = selfupdate.Apply(builtFile, selfupdate.Options{})
|
|
```
|