refactor: 统一构建产物输出目录
This commit is contained in:
@@ -18,14 +18,11 @@ dist
|
||||
uploads
|
||||
CapacityReportData
|
||||
auth.ini
|
||||
Configure.json
|
||||
*.log
|
||||
*.tmp
|
||||
*.temp
|
||||
*.bak
|
||||
|
||||
build/temp
|
||||
build/pyinstaller
|
||||
target
|
||||
src-tauri/target
|
||||
src-tauri/binaries
|
||||
|
||||
@@ -35,8 +35,6 @@ dist/
|
||||
cache/
|
||||
logs/
|
||||
uploads/
|
||||
build/temp/
|
||||
build/pyinstaller/
|
||||
src-tauri/target/
|
||||
src-tauri/binaries/
|
||||
CapacityReportData/
|
||||
|
||||
@@ -37,7 +37,8 @@ CapaReport/
|
||||
├─ frontend/ # Vue 前端
|
||||
├─ src-tauri/ # Tauri 桌面壳
|
||||
├─ scripts/ # 一键构建脚本
|
||||
├─ build/ # Docker 和 PyInstaller 配置
|
||||
├─ packaging/ # Docker、Compose、PyInstaller 配置
|
||||
├─ dist/ # 一键构建后的最终产物
|
||||
├─ docs/project_context.md # 项目维护记录
|
||||
├─ Configure.json # 应用配置
|
||||
├─ ReportScript.sql # SQL 处理脚本
|
||||
@@ -117,6 +118,8 @@ scripts\build.bat docker -SkipDockerBuild
|
||||
scripts\build.bat all -SkipDesktopBuild
|
||||
```
|
||||
|
||||
构建完成后只保留 `dist/` 下的最终产物;`dist/.tmp`、`frontend/dist`、`src-tauri/target`、`src-tauri/binaries` 等中间产物会自动清理。
|
||||
|
||||
### Server Portable
|
||||
|
||||
```bat
|
||||
@@ -126,8 +129,8 @@ scripts\build.bat server
|
||||
输出:
|
||||
|
||||
```text
|
||||
dist\packages\CapacityReport-Server-windows-x64\
|
||||
dist\packages\CapacityReport-Server-windows-x64.zip
|
||||
dist\server\CapacityReport-Server-windows-x64\
|
||||
dist\server\CapacityReport-Server-windows-x64.zip
|
||||
```
|
||||
|
||||
便携版内包含后端可执行文件、前端构建产物、`Configure.json`、`ReportScript.sql`、`cache/`、`logs/` 和启动脚本。默认监听端口为 `9081`。
|
||||
@@ -141,8 +144,8 @@ scripts\build.bat desktop
|
||||
输出:
|
||||
|
||||
```text
|
||||
src-tauri\target\release\bundle\msi\*.msi
|
||||
src-tauri\target\release\bundle\nsis\*-setup.exe
|
||||
dist\desktop\*.msi
|
||||
dist\desktop\*-setup.exe
|
||||
```
|
||||
|
||||
桌面版使用 Tauri 启动 Python sidecar。sidecar 默认监听 `127.0.0.1:19082`,运行数据写入系统 app data 目录,不写入安装目录。
|
||||
@@ -159,16 +162,21 @@ cargo install tauri-cli --locked
|
||||
scripts\build.bat docker
|
||||
```
|
||||
|
||||
输出镜像:
|
||||
输出:
|
||||
|
||||
```text
|
||||
capacity-report-app:latest
|
||||
dist\docker\capacity-report-app-latest.tar
|
||||
dist\docker\docker-compose.yml
|
||||
dist\docker\Configure.json
|
||||
dist\docker\ReportScript.sql
|
||||
```
|
||||
|
||||
启动:
|
||||
|
||||
```bat
|
||||
docker compose -f build\docker-compose.yml up -d
|
||||
docker load -i dist\docker\capacity-report-app-latest.tar
|
||||
docker compose -f dist\docker\docker-compose.yml up -d
|
||||
```
|
||||
|
||||
访问:
|
||||
@@ -180,7 +188,7 @@ http://localhost:19081
|
||||
停止:
|
||||
|
||||
```bat
|
||||
docker compose -f build\docker-compose.yml down
|
||||
docker compose -f dist\docker\docker-compose.yml down
|
||||
```
|
||||
|
||||
## Linux / macOS 构建
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Python cache and virtual environments
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
.venv/
|
||||
venv/
|
||||
ENV/
|
||||
env/
|
||||
|
||||
# Frontend local artifacts
|
||||
frontend/node_modules/
|
||||
frontend/dist/
|
||||
frontend/.vite/
|
||||
|
||||
# Runtime and package output
|
||||
cache/
|
||||
logs/
|
||||
dist/
|
||||
uploads/
|
||||
CapacityReportData/
|
||||
error.log
|
||||
*.log
|
||||
|
||||
# Build helper output
|
||||
build/temp/
|
||||
|
||||
# Local-only files
|
||||
.env
|
||||
.env.local
|
||||
auth.ini
|
||||
|
||||
# Deployment files copied separately by build.py
|
||||
docker-compose*.yml
|
||||
Dockerfile*
|
||||
.dockerignore
|
||||
|
||||
# MySQL data
|
||||
mysql/
|
||||
|
||||
# Temporary and OS files
|
||||
*.tmp
|
||||
*.temp
|
||||
.temp/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Documentation is not required in the runtime image.
|
||||
*.md
|
||||
!README.md
|
||||
@@ -1,26 +0,0 @@
|
||||
# Build Notes
|
||||
|
||||
Use the root scripts for release builds:
|
||||
|
||||
```powershell
|
||||
scripts\build.bat server
|
||||
scripts\build.bat docker
|
||||
scripts\build.bat desktop
|
||||
```
|
||||
|
||||
On Linux or macOS:
|
||||
|
||||
```bash
|
||||
sh scripts/build.sh server
|
||||
sh scripts/build.sh docker
|
||||
sh scripts/build.sh desktop
|
||||
```
|
||||
|
||||
## Targets
|
||||
|
||||
- `server`: builds a portable server package for the current OS.
|
||||
- `docker`: builds the Docker image and validates the compose file.
|
||||
- `desktop`: builds a Tauri desktop package with the Python server sidecar.
|
||||
- `all`: runs all targets.
|
||||
|
||||
Native server and desktop packages must be built on the target OS. Build Windows packages on Windows, Linux packages on Linux, and macOS packages on macOS. Docker images can be built from the Windows development host.
|
||||
@@ -387,7 +387,7 @@
|
||||
- `app/config.py` supports `CAPAREPORT_BASE_DIR`; frozen PyInstaller server builds default `BASE_DIR` to the executable directory. The Tauri sidecar sets `CAPAREPORT_BASE_DIR` to the app data directory so runtime files are not written into the install directory.
|
||||
- Tauri startup creates app-data `cache/` and `logs/`, then copies bundled `Configure.json` and `ReportScript.sql` on first run. Resource lookup supports both normal Tauri resources and the `_up_` directory generated for bundled `../` resources.
|
||||
- Windows desktop shutdown uses `taskkill /F /T /PID` before killing the shell child, which avoids PyInstaller one-file sidecar process leftovers.
|
||||
- Docker build now copies only required app files and frontend build output. `.dockerignore` excludes local dependencies, caches, build output, and local config; `build/docker-compose.yml` mounts paths relative to the `build/` directory.
|
||||
- Docker build now copies only required app files and frontend build output. `.dockerignore` excludes local dependencies, caches, and generated output; deployment compose files are emitted under `dist/docker/`.
|
||||
- `app/main.py` accepts `--host` and `--port` and exposes `run_server()` so portable launchers, Docker, and the Tauri sidecar share the same backend entry point.
|
||||
- Windows verification completed: `scripts\build.bat server -NoArchive`, `scripts\build.bat server`, `scripts\build.bat docker`, and `scripts\build.bat desktop`. Server portable `/health`, Docker container `/health`, and desktop sidecar `/health` all returned HTTP 200; desktop first run also copied config and SQL into app data.
|
||||
- Cleanup verification completed: `.venv\Scripts\python.exe -m compileall app`, `npm run build`, PowerShell AST parse for `scripts/build.ps1`, Docker-hosted `sh -n scripts/build.sh`, and `cargo check --manifest-path src-tauri\Cargo.toml` with a temporary sidecar placeholder all passed. Linux/macOS native server and desktop packages still need native OS verification.
|
||||
@@ -397,6 +397,13 @@
|
||||
## 2026-05-20: Tauri desktop console and installer language
|
||||
|
||||
- `src-tauri/src/main.rs` uses `#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]` so Windows release builds use the GUI subsystem and do not open an extra console window when launched from Explorer or the installer shortcut.
|
||||
- `build/capareport-server.spec` keeps Server Portable in console mode, but desktop one-file sidecar builds (`CAPAREPORT_ONEFILE=1`) use PyInstaller `console=False`; PyInstaller should select `runw.exe` for the sidecar so it also stays hidden behind the Tauri window.
|
||||
- `packaging/capareport-server.spec` keeps Server Portable in console mode, but desktop one-file sidecar builds (`CAPAREPORT_ONEFILE=1`) use PyInstaller `console=False`; PyInstaller should select `runw.exe` for the sidecar so it also stays hidden behind the Tauri window.
|
||||
- `src-tauri/tauri.conf.json` sets Windows installer localization through `bundle.windows.wix.language = "zh-CN"` and `bundle.windows.nsis.languages = ["SimpChinese"]`. NSIS language keys must use NSIS names such as `SimpChinese`, while WiX/MSI uses locale names such as `zh-CN`.
|
||||
- Verification on Windows: `cargo check --manifest-path src-tauri\Cargo.toml` passed, `scripts\build.bat desktop` generated the MSI and NSIS bundles, PE subsystem checks reported `Windows GUI` for both `capacity-report-desktop.exe` and `capareport-server.exe`, and the generated NSIS script included `MUI_LANGUAGE "SimpChinese"`.
|
||||
|
||||
## 2026-05-20: Unified release output under dist
|
||||
|
||||
- The former `build/` packaging source directory was renamed to `packaging/` to avoid confusing source-side packaging recipes with generated output. `packaging/` now holds `Dockerfile`, `docker-compose.yml`, the PyInstaller spec, and MySQL container config.
|
||||
- `scripts/build.ps1` and `scripts/build.sh` now use `dist/.tmp/` for PyInstaller work output and copy final deliverables to `dist/server/`, `dist/desktop/`, and `dist/docker/`. Successful builds remove `dist/.tmp`, `frontend/dist`, `src-tauri/target`, and `src-tauri/binaries`.
|
||||
- Docker builds now include `Configure.json` in the image and also create a deployable `dist/docker/` bundle containing `capacity-report-app-latest.tar`, `docker-compose.yml`, `Configure.json`, `ReportScript.sql`, `mysql/`, `cache/`, and `logs/`.
|
||||
- Server Portable still includes `Configure.json` and `ReportScript.sql` inside `dist/server/CapacityReport-Server-<platform>-x64/`. Tauri desktop still bundles both files through `src-tauri/tauri.conf.json` resources and copies them to app data on first run.
|
||||
|
||||
@@ -31,7 +31,7 @@ RUN pip install --no-cache-dir -r requirements.txt
|
||||
RUN mkdir -p /var/log/supervisor /var/run /app/cache
|
||||
|
||||
COPY app ./app
|
||||
COPY ReportScript.sql start.sh supervisord.conf ./
|
||||
COPY Configure.json ReportScript.sql start.sh supervisord.conf ./
|
||||
COPY --from=frontend-build /frontend/dist /app/frontend/dist
|
||||
|
||||
RUN chmod +x /app/start.sh 2>/dev/null || true
|
||||
@@ -6,10 +6,10 @@ services:
|
||||
ports:
|
||||
- "19081:9081"
|
||||
volumes:
|
||||
- ../cache:/app/cache
|
||||
- ../Configure.json:/app/Configure.json
|
||||
- ../ReportScript.sql:/app/ReportScript.sql
|
||||
- ../logs:/var/log/supervisor
|
||||
- ./cache:/app/cache
|
||||
- ./Configure.json:/app/Configure.json
|
||||
- ./ReportScript.sql:/app/ReportScript.sql
|
||||
- ./logs:/var/log/supervisor
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- PYTHONUNBUFFERED=1
|
||||
+86
-20
@@ -17,13 +17,16 @@ $ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$Root = Resolve-Path (Join-Path $ScriptDir "..")
|
||||
$Root = (Resolve-Path (Join-Path $ScriptDir "..")).Path
|
||||
$DistDir = Join-Path $Root "dist"
|
||||
$PackageDir = Join-Path $DistDir "packages"
|
||||
$PyInstallerDir = Join-Path $Root "build\pyinstaller"
|
||||
$ServerDistDir = Join-Path $DistDir "server"
|
||||
$DesktopDistDir = Join-Path $DistDir "desktop"
|
||||
$DockerDistDir = Join-Path $DistDir "docker"
|
||||
$TempDir = Join-Path $DistDir ".tmp"
|
||||
$PyInstallerDir = Join-Path $TempDir "pyinstaller"
|
||||
$FrontendDir = Join-Path $Root "frontend"
|
||||
$PackagingDir = Join-Path $Root "packaging"
|
||||
$ServerName = "capareport-server"
|
||||
$AppVersion = "2.0.2"
|
||||
$DesktopApiBase = "http://127.0.0.1:19082"
|
||||
|
||||
function Write-Step($Message) {
|
||||
@@ -46,6 +49,21 @@ function Show-Usage {
|
||||
Write-Host " -SkipDesktopBuild"
|
||||
}
|
||||
|
||||
function Assert-InWorkspace($Path) {
|
||||
$resolved = (Resolve-Path -LiteralPath $Path).Path
|
||||
if (!$resolved.StartsWith($Root, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
throw "Refusing to operate outside workspace: $resolved"
|
||||
}
|
||||
return $resolved
|
||||
}
|
||||
|
||||
function Remove-Tree($Path) {
|
||||
if (Test-Path -LiteralPath $Path) {
|
||||
$resolved = Assert-InWorkspace $Path
|
||||
Remove-Item -LiteralPath $resolved -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-Checked($Command, $WorkingDirectory = $Root) {
|
||||
Write-Info $Command
|
||||
Push-Location $WorkingDirectory
|
||||
@@ -136,9 +154,15 @@ function Build-Frontend($ApiBase) {
|
||||
function Build-ServerBinary([switch]$OneFile) {
|
||||
Ensure-PythonEnvironment
|
||||
Write-Step "Building server binary"
|
||||
Remove-Item -LiteralPath $PyInstallerDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Remove-Tree $PyInstallerDir
|
||||
New-Item -ItemType Directory -Force -Path $PyInstallerDir | Out-Null
|
||||
|
||||
$python = Join-Path $Root ".venv\Scripts\python.exe"
|
||||
$workPath = Join-Path $PyInstallerDir "work"
|
||||
$distPath = Join-Path $PyInstallerDir "dist"
|
||||
$specPath = Join-Path $PackagingDir "capareport-server.spec"
|
||||
$previousOneFile = $env:CAPAREPORT_ONEFILE
|
||||
|
||||
if ($OneFile) {
|
||||
$env:CAPAREPORT_ONEFILE = "1"
|
||||
}
|
||||
@@ -147,7 +171,7 @@ function Build-ServerBinary([switch]$OneFile) {
|
||||
}
|
||||
|
||||
try {
|
||||
Invoke-Checked "`"$python`" -m PyInstaller --clean --noconfirm --workpath build\pyinstaller\work --distpath build\pyinstaller\dist build\capareport-server.spec" $Root
|
||||
Invoke-Checked "`"$python`" -m PyInstaller --clean --noconfirm --workpath `"$workPath`" --distpath `"$distPath`" `"$specPath`"" $Root
|
||||
}
|
||||
finally {
|
||||
if ($null -ne $previousOneFile) {
|
||||
@@ -159,14 +183,14 @@ function Build-ServerBinary([switch]$OneFile) {
|
||||
}
|
||||
|
||||
if ($OneFile) {
|
||||
$binaryDir = Join-Path $PyInstallerDir "dist"
|
||||
$binaryDir = $distPath
|
||||
$binaryPath = Join-Path $binaryDir (Get-ExecutableName (Get-CurrentPlatform))
|
||||
if (!(Test-Path $binaryPath)) {
|
||||
throw "PyInstaller output not found: $binaryPath"
|
||||
}
|
||||
}
|
||||
else {
|
||||
$binaryDir = Join-Path $PyInstallerDir "dist\$ServerName"
|
||||
$binaryDir = Join-Path $distPath $ServerName
|
||||
if (!(Test-Path $binaryDir)) {
|
||||
throw "PyInstaller output not found: $binaryDir"
|
||||
}
|
||||
@@ -237,11 +261,14 @@ function Build-ServerPortable {
|
||||
$platformName = "windows"
|
||||
}
|
||||
|
||||
$outputDir = Join-Path $ServerDistDir "CapacityReport-Server-$platformName-x64"
|
||||
$archive = "$outputDir.zip"
|
||||
Remove-Tree $outputDir
|
||||
Remove-Item -LiteralPath $archive -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Build-Frontend $null
|
||||
$binaryDir = Build-ServerBinary
|
||||
|
||||
$outputDir = Join-Path $PackageDir "CapacityReport-Server-$platformName-x64"
|
||||
Remove-Item -LiteralPath $outputDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
|
||||
|
||||
Copy-Item -Path (Join-Path $binaryDir "*") -Destination $outputDir -Recurse -Force
|
||||
@@ -249,8 +276,6 @@ function Build-ServerPortable {
|
||||
Write-ServerLaunchers $outputDir $platformName
|
||||
|
||||
if (!$NoArchive) {
|
||||
$archive = "$outputDir.zip"
|
||||
Remove-Item -LiteralPath $archive -Force -ErrorAction SilentlyContinue
|
||||
Compress-Archive -Path (Join-Path $outputDir "*") -DestinationPath $archive -Force
|
||||
Write-Info "Archive: $archive"
|
||||
}
|
||||
@@ -258,15 +283,36 @@ function Build-ServerPortable {
|
||||
Write-Info "Server package: $outputDir"
|
||||
}
|
||||
|
||||
function Copy-DockerBundle {
|
||||
Remove-Tree $DockerDistDir
|
||||
New-Item -ItemType Directory -Force -Path $DockerDistDir | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $DockerDistDir "cache") | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $DockerDistDir "logs") | Out-Null
|
||||
Copy-Item -Path (Join-Path $PackagingDir "docker-compose.yml") -Destination (Join-Path $DockerDistDir "docker-compose.yml") -Force
|
||||
Copy-Item -Path (Join-Path $PackagingDir "mysql") -Destination (Join-Path $DockerDistDir "mysql") -Recurse -Force
|
||||
Copy-Item -Path (Join-Path $Root "Configure.json") -Destination (Join-Path $DockerDistDir "Configure.json") -Force
|
||||
Copy-Item -Path (Join-Path $Root "ReportScript.sql") -Destination (Join-Path $DockerDistDir "ReportScript.sql") -Force
|
||||
}
|
||||
|
||||
function Build-DockerImage {
|
||||
Remove-Tree $DockerDistDir
|
||||
|
||||
if ($SkipDockerBuild) {
|
||||
Write-Host "Docker build skipped."
|
||||
Write-Host "Docker image build skipped."
|
||||
Copy-DockerBundle
|
||||
Invoke-Checked "docker compose -f `"$DockerDistDir\docker-compose.yml`" config" $Root
|
||||
Write-Info "Docker package: $DockerDistDir"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Step "Building Docker image"
|
||||
Invoke-Checked "docker build --progress=plain -f build\Dockerfile -t capacity-report-app:latest ." $Root
|
||||
Invoke-Checked "docker compose -f build\docker-compose.yml config" $Root
|
||||
Invoke-Checked "docker build --progress=plain -f `"$PackagingDir\Dockerfile`" -t capacity-report-app:latest ." $Root
|
||||
|
||||
Write-Step "Packaging Docker output"
|
||||
Copy-DockerBundle
|
||||
Invoke-Checked "docker save -o `"$DockerDistDir\capacity-report-app-latest.tar`" capacity-report-app:latest" $Root
|
||||
Invoke-Checked "docker compose -f `"$DockerDistDir\docker-compose.yml`" config" $Root
|
||||
Write-Info "Docker package: $DockerDistDir"
|
||||
}
|
||||
|
||||
function Build-DesktopPackage {
|
||||
@@ -279,6 +325,8 @@ function Build-DesktopPackage {
|
||||
throw "Rust is required for the Tauri desktop build"
|
||||
}
|
||||
|
||||
Remove-Tree $DesktopDistDir
|
||||
|
||||
Build-Frontend $DesktopApiBase
|
||||
$binaryDir = Build-ServerBinary -OneFile
|
||||
$platformName = Get-CurrentPlatform
|
||||
@@ -294,8 +342,23 @@ function Build-DesktopPackage {
|
||||
Invoke-Checked "cargo install tauri-cli --locked" $Root
|
||||
}
|
||||
|
||||
Remove-Tree (Join-Path $Root "src-tauri\target\release\bundle")
|
||||
Write-Step "Building Tauri desktop package"
|
||||
Invoke-Checked "cargo tauri build" (Join-Path $Root "src-tauri")
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $DesktopDistDir | Out-Null
|
||||
$bundleDir = Join-Path $Root "src-tauri\target\release\bundle"
|
||||
Get-ChildItem -Path $bundleDir -Recurse -File -Include "*.msi", "*.exe" |
|
||||
Copy-Item -Destination $DesktopDistDir -Force
|
||||
Write-Info "Desktop package: $DesktopDistDir"
|
||||
}
|
||||
|
||||
function Clean-Intermediates {
|
||||
Write-Step "Cleaning intermediate output"
|
||||
Remove-Tree $TempDir
|
||||
Remove-Tree (Join-Path $Root "frontend\dist")
|
||||
Remove-Tree (Join-Path $Root "src-tauri\binaries")
|
||||
Remove-Tree (Join-Path $Root "src-tauri\target")
|
||||
}
|
||||
|
||||
if ($Help) {
|
||||
@@ -304,13 +367,14 @@ if ($Help) {
|
||||
}
|
||||
|
||||
if ($Clean) {
|
||||
Write-Step "Cleaning build output"
|
||||
Remove-Item -LiteralPath $DistDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -LiteralPath $PyInstallerDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -LiteralPath (Join-Path $Root "src-tauri\binaries") -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Write-Step "Cleaning dist output"
|
||||
Remove-Tree $DistDir
|
||||
Remove-Tree (Join-Path $Root "frontend\dist")
|
||||
Remove-Tree (Join-Path $Root "src-tauri\binaries")
|
||||
Remove-Tree (Join-Path $Root "src-tauri\target")
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $PackageDir | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path $DistDir | Out-Null
|
||||
|
||||
switch ($Target) {
|
||||
"server" { Build-ServerPortable }
|
||||
@@ -323,4 +387,6 @@ switch ($Target) {
|
||||
}
|
||||
}
|
||||
|
||||
Clean-Intermediates
|
||||
|
||||
Write-Step "Build finished"
|
||||
|
||||
+65
-15
@@ -4,7 +4,15 @@ set -eu
|
||||
TARGET="${1:-server}"
|
||||
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||
ROOT="$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)"
|
||||
DIST_DIR="$ROOT/dist"
|
||||
SERVER_DIST_DIR="$DIST_DIR/server"
|
||||
DESKTOP_DIST_DIR="$DIST_DIR/desktop"
|
||||
DOCKER_DIST_DIR="$DIST_DIR/docker"
|
||||
TMP_DIR="$DIST_DIR/.tmp"
|
||||
PYINSTALLER_DIR="$TMP_DIR/pyinstaller"
|
||||
PACKAGING_DIR="$ROOT/packaging"
|
||||
DESKTOP_API_BASE="http://127.0.0.1:19082"
|
||||
SERVER_NAME="capareport-server"
|
||||
cd "$ROOT"
|
||||
|
||||
log() {
|
||||
@@ -24,6 +32,18 @@ platform_name() {
|
||||
esac
|
||||
}
|
||||
|
||||
server_exe_name() {
|
||||
case "$(platform_name)" in
|
||||
windows) printf '%s.exe' "$SERVER_NAME" ;;
|
||||
*) printf '%s' "$SERVER_NAME" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
clean_intermediates() {
|
||||
log "Cleaning intermediate output"
|
||||
rm -rf "$TMP_DIR" "$ROOT/frontend/dist" "$ROOT/src-tauri/binaries" "$ROOT/src-tauri/target"
|
||||
}
|
||||
|
||||
ensure_python() {
|
||||
log "Preparing Python environment"
|
||||
if [ ! -x ".venv/bin/python" ]; then
|
||||
@@ -49,20 +69,22 @@ build_server_binary() {
|
||||
mode="${1:-onedir}"
|
||||
ensure_python
|
||||
log "Building server binary"
|
||||
rm -rf build/pyinstaller
|
||||
rm -rf "$PYINSTALLER_DIR"
|
||||
mkdir -p "$PYINSTALLER_DIR"
|
||||
|
||||
if [ "$mode" = "onefile" ]; then
|
||||
CAPAREPORT_ONEFILE=1
|
||||
export CAPAREPORT_ONEFILE
|
||||
run .venv/bin/python -m PyInstaller --clean --noconfirm \
|
||||
--workpath build/pyinstaller/work \
|
||||
--distpath build/pyinstaller/dist \
|
||||
build/capareport-server.spec
|
||||
--workpath "$PYINSTALLER_DIR/work" \
|
||||
--distpath "$PYINSTALLER_DIR/dist" \
|
||||
"$PACKAGING_DIR/capareport-server.spec"
|
||||
unset CAPAREPORT_ONEFILE
|
||||
else
|
||||
run .venv/bin/python -m PyInstaller --clean --noconfirm \
|
||||
--workpath build/pyinstaller/work \
|
||||
--distpath build/pyinstaller/dist \
|
||||
build/capareport-server.spec
|
||||
--workpath "$PYINSTALLER_DIR/work" \
|
||||
--distpath "$PYINSTALLER_DIR/dist" \
|
||||
"$PACKAGING_DIR/capareport-server.spec"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -85,38 +107,64 @@ EOF
|
||||
|
||||
build_server() {
|
||||
platform="$(platform_name)"
|
||||
exe_name="$(server_exe_name)"
|
||||
out_dir="$SERVER_DIST_DIR/CapacityReport-Server-$platform-x64"
|
||||
rm -rf "$out_dir" "$SERVER_DIST_DIR/$(basename "$out_dir").tar.gz"
|
||||
|
||||
build_frontend server
|
||||
build_server_binary onedir
|
||||
|
||||
out_dir="dist/packages/CapacityReport-Server-$platform-x64"
|
||||
rm -rf "$out_dir"
|
||||
mkdir -p "$out_dir/cache" "$out_dir/logs" "$out_dir/frontend"
|
||||
cp -R build/pyinstaller/dist/capareport-server/. "$out_dir/"
|
||||
cp -R "$PYINSTALLER_DIR/dist/$SERVER_NAME/." "$out_dir/"
|
||||
cp Configure.json ReportScript.sql "$out_dir/"
|
||||
cp -R frontend/dist "$out_dir/frontend/"
|
||||
write_launchers "$out_dir" "capareport-server"
|
||||
(cd "$out_dir/.." && tar -czf "$(basename "$out_dir").tar.gz" "$(basename "$out_dir")")
|
||||
write_launchers "$out_dir" "$exe_name"
|
||||
(cd "$SERVER_DIST_DIR" && tar -czf "$(basename "$out_dir").tar.gz" "$(basename "$out_dir")")
|
||||
log "Server package: $out_dir"
|
||||
}
|
||||
|
||||
copy_docker_bundle() {
|
||||
rm -rf "$DOCKER_DIST_DIR"
|
||||
mkdir -p "$DOCKER_DIST_DIR/cache" "$DOCKER_DIST_DIR/logs"
|
||||
cp "$PACKAGING_DIR/docker-compose.yml" "$DOCKER_DIST_DIR/docker-compose.yml"
|
||||
cp Configure.json ReportScript.sql "$DOCKER_DIST_DIR/"
|
||||
cp -R "$PACKAGING_DIR/mysql" "$DOCKER_DIST_DIR/mysql"
|
||||
}
|
||||
|
||||
build_docker() {
|
||||
rm -rf "$DOCKER_DIST_DIR"
|
||||
|
||||
log "Building Docker image"
|
||||
run docker build --progress=plain -f build/Dockerfile -t capacity-report-app:latest .
|
||||
run docker compose -f build/docker-compose.yml config
|
||||
run docker build --progress=plain -f "$PACKAGING_DIR/Dockerfile" -t capacity-report-app:latest .
|
||||
log "Packaging Docker output"
|
||||
copy_docker_bundle
|
||||
run docker save -o "$DOCKER_DIST_DIR/capacity-report-app-latest.tar" capacity-report-app:latest
|
||||
run docker compose -f "$DOCKER_DIST_DIR/docker-compose.yml" config
|
||||
log "Docker package: $DOCKER_DIST_DIR"
|
||||
}
|
||||
|
||||
build_desktop() {
|
||||
rm -rf "$DESKTOP_DIST_DIR"
|
||||
|
||||
build_frontend desktop
|
||||
build_server_binary onefile
|
||||
triple="$(rustc -vV | awk '/^host:/ {print $2}')"
|
||||
mkdir -p src-tauri/binaries
|
||||
cp build/pyinstaller/dist/capareport-server "src-tauri/binaries/capareport-server-$triple"
|
||||
cp "$PYINSTALLER_DIR/dist/$(server_exe_name)" "src-tauri/binaries/$SERVER_NAME-$triple"
|
||||
if ! cargo tauri --version >/dev/null 2>&1; then
|
||||
run cargo install tauri-cli --locked
|
||||
fi
|
||||
rm -rf src-tauri/target/release/bundle
|
||||
(cd src-tauri && run cargo tauri build)
|
||||
|
||||
rm -rf "$DESKTOP_DIST_DIR"
|
||||
mkdir -p "$DESKTOP_DIST_DIR"
|
||||
find src-tauri/target/release/bundle -type f \( -name '*.msi' -o -name '*.exe' \) -exec cp {} "$DESKTOP_DIST_DIR/" \;
|
||||
log "Desktop package: $DESKTOP_DIST_DIR"
|
||||
}
|
||||
|
||||
mkdir -p "$DIST_DIR"
|
||||
|
||||
case "$TARGET" in
|
||||
server) build_server ;;
|
||||
docker) build_docker ;;
|
||||
@@ -125,4 +173,6 @@ case "$TARGET" in
|
||||
*) echo "Usage: scripts/build.sh [server|docker|desktop|all]" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
clean_intermediates
|
||||
|
||||
log "Build finished"
|
||||
|
||||
Reference in New Issue
Block a user