refactor: 统一构建产物输出目录
This commit is contained in:
+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