From e00e4c01303d113fd0582ad5703097370d22a012 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 20:59:59 +0800 Subject: [PATCH 01/36] fix(ci): fix Docker GHCR tags, add GUI to macOS/Windows releases, bundle OpenSSL DLLs on Windows - fix docker-bake.hcl: add REGISTRY variable (ghcr.io/airprofly/backer) so HCL generates correct GHCR tags; drop :latest tag per request - fix docker-publish.yml: remove redundant --set override, let HCL resolve REGISTRY from env var directly - fix publish-release.yml: install OpenSSL + Qt6 on macOS (brew) and Windows (choco), enable BUILD_GUI=ON, package backer-gui alongside backer-cli - fix publish-release.yml: bundle libcrypto-3-x64.dll and libssl-3-x64.dll into Windows ZIP to fix "missing DLL" popup - fix FetchQt6.cmake: add macOS/Windows platform detection (aqtinstall), fix Qt6_DIR path to use detected arch instead of hardcoded gcc_64 --- .github/workflows/docker-publish.yml | 1 - .github/workflows/publish-release.yml | 50 +++++++++++++++++++++++---- cmake/FetchQt6.cmake | 26 ++++++++++++-- 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index f981a9c..a912ebb 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -34,7 +34,6 @@ jobs: run: | docker buildx bake \ --set "default.tags=${REGISTRY}:${TAG}" \ - --set "default.tags=${REGISTRY}:latest" \ --push \ default diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index f4a842e..f0a363b 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -52,12 +52,22 @@ jobs: name: linux-artifacts path: ${{ env.PROJECT_NAME }}-v*-linux-x86_64.tar.gz - # ── macOS 构建 ────────────────────────────────────── + # ── macOS 构建(ARM64) ────────────────────────────── macos-build: runs-on: macos-14 steps: - uses: actions/checkout@v4 + - name: Install OpenSSL + run: | + brew install openssl + echo "OPENSSL_ROOT_DIR=$(brew --prefix openssl)" >> $GITHUB_ENV + + - name: Install Qt6 + run: | + brew install qt@6 + echo "Qt6_DIR=$(brew --prefix qt@6)" >> $GITHUB_ENV + - name: Cache CMake dependencies uses: actions/cache@v4 with: @@ -68,7 +78,7 @@ jobs: - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ - -DBUILD_TESTING=OFF + -DBUILD_TESTING=OFF -DBUILD_GUI=ON - name: Build run: cmake --build build -j$(sysctl -n hw.logicalcpu) @@ -78,10 +88,11 @@ jobs: VERSION=${GITHUB_REF_NAME#v} mkdir -p dist cp build/backer-cli dist/backer-cli + cp build/backer-gui dist/backer-gui cp LICENSE dist/ cd dist tar czf ../${{ env.PROJECT_NAME }}-v${VERSION}-macos-x86_64.tar.gz \ - backer-cli LICENSE + backer-cli backer-gui LICENSE - uses: actions/upload-artifact@v4 with: @@ -94,6 +105,16 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install OpenSSL + run: | + brew install openssl + echo "OPENSSL_ROOT_DIR=$(brew --prefix openssl)" >> $GITHUB_ENV + + - name: Install Qt6 + run: | + brew install qt@6 + echo "Qt6_DIR=$(brew --prefix qt@6)" >> $GITHUB_ENV + - name: Cache CMake dependencies uses: actions/cache@v4 with: @@ -104,7 +125,7 @@ jobs: - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ - -DBUILD_TESTING=OFF \ + -DBUILD_TESTING=OFF -DBUILD_GUI=ON \ -DCMAKE_OSX_ARCHITECTURES=arm64 - name: Build @@ -115,10 +136,11 @@ jobs: VERSION=${GITHUB_REF_NAME#v} mkdir -p dist cp build/backer-cli dist/backer-cli + cp build/backer-gui dist/backer-gui cp LICENSE dist/ cd dist tar czf ../${{ env.PROJECT_NAME }}-v${VERSION}-macos-arm64.tar.gz \ - backer-cli LICENSE + backer-cli backer-gui LICENSE - uses: actions/upload-artifact@v4 with: @@ -134,6 +156,11 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install OpenSSL + run: | + choco install openssl -y --no-progress + echo "OPENSSL_ROOT_DIR=C:\Program Files\OpenSSL" | Out-File -FilePath $env:GITHUB_ENV -Append + - name: Cache CMake dependencies uses: actions/cache@v4 with: @@ -144,17 +171,26 @@ jobs: - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} ` - -DBUILD_TESTING=OFF + -DBUILD_TESTING=OFF -DBUILD_GUI=ON - name: Build - run: cmake --build build -j $env:NUMBER_OF_PROCESSORS + run: cmake --build build -j $env:NUMBER_OF_PROCESSORS --config ${{ env.BUILD_TYPE }} - name: Package run: | $VERSION = "${{ github.ref_name }}".Substring(1) New-Item -ItemType Directory -Path dist -Force Copy-Item build/${{ env.BUILD_TYPE }}/backer-cli.exe dist/ + Copy-Item build/${{ env.BUILD_TYPE }}/backer-gui.exe dist/ Copy-Item LICENSE dist/ + # Bundle OpenSSL runtime DLLs for portable executables + $osslBin = "$env:OPENSSL_ROOT_DIR\bin" + if (Test-Path "$osslBin\libcrypto-3-x64.dll") { + Copy-Item "$osslBin\libcrypto-3-x64.dll" dist/ + } + if (Test-Path "$osslBin\libssl-3-x64.dll") { + Copy-Item "$osslBin\libssl-3-x64.dll" dist/ + } Compress-Archive -Path dist/* -DestinationPath ` "${{ env.PROJECT_NAME }}-v${VERSION}-windows-x86_64.zip" -Force diff --git a/cmake/FetchQt6.cmake b/cmake/FetchQt6.cmake index 63ff092..2191288 100644 --- a/cmake/FetchQt6.cmake +++ b/cmake/FetchQt6.cmake @@ -67,16 +67,36 @@ if(NOT _pip_ret EQUAL 0) return() endif() +# ── Detect platform for aqtinstall ──────────────────────────────────── +if(WIN32) + set(_aqt_platform "windows") + set(_aqt_arch "win64_msvc2022_64") +elseif(APPLE) + set(_aqt_platform "mac") + if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64") + set(_aqt_arch "macos_arm64") + else() + set(_aqt_arch "macos_x64") + endif() +else() + set(_aqt_platform "linux") + if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64") + set(_aqt_arch "gcc_arm64") + else() + set(_aqt_arch "gcc_64") + endif() +endif() + # ── Download Qt6 prebuilt binaries ──────────────────────────────────── set(_qt_dir "${CMAKE_BINARY_DIR}/_deps/qt6_prebuilt") file(MAKE_DIRECTORY "${_qt_dir}") -message(STATUS "FetchQt6: downloading Qt ${QT6_VERSION} (gcc_64)...") +message(STATUS "FetchQt6: downloading Qt ${QT6_VERSION} (${_aqt_arch})...") message(STATUS "FetchQt6: target: ${_qt_dir}") message(STATUS "FetchQt6: this may take several minutes...") execute_process(COMMAND ${_python} -m aqt install-qt - linux desktop "${QT6_VERSION}" gcc_64 + ${_aqt_platform} desktop "${QT6_VERSION}" ${_aqt_arch} -O "${_qt_dir}" --modules qtbase OUTPUT_VARIABLE _aqt_out ERROR_VARIABLE _aqt_err RESULT_VARIABLE _aqt_ret TIMEOUT 600) @@ -87,7 +107,7 @@ if(NOT _aqt_ret EQUAL 0) return() endif() -set(Qt6_DIR "${_qt_dir}/${QT6_VERSION}/gcc_64" +set(Qt6_DIR "${_qt_dir}/${QT6_VERSION}/${_aqt_arch}" CACHE PATH "Path to downloaded Qt6" FORCE) message(STATUS "FetchQt6: Qt6 downloaded to ${Qt6_DIR}") From 8524f2af8214b2d685b7be831d5f5bda8500e166 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 21:07:15 +0800 Subject: [PATCH 02/36] refactor(ci): move Docker registry tag from workflow override to HCL - add REGISTRY variable in docker-bake.hcl for configurable image tag - remove --set tag override from docker-publish.yml (now handled by HCL) --- .github/workflows/docker-publish.yml | 1 - docker-bake.hcl | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index a912ebb..96b49fa 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -33,7 +33,6 @@ jobs: REGISTRY: ghcr.io/${{ github.repository }} run: | docker buildx bake \ - --set "default.tags=${REGISTRY}:${TAG}" \ --push \ default diff --git a/docker-bake.hcl b/docker-bake.hcl index cda9a23..fcbdc07 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -2,6 +2,10 @@ variable "TAG" { default = "latest" } +variable "REGISTRY" { + default = "ghcr.io/airprofly/backer" +} + variable "GH_PROXY" { default = "" description = "GitHub proxy mirror for Chinese users (e.g. https://ghproxy.net/)" @@ -9,7 +13,7 @@ variable "GH_PROXY" { target "default" { dockerfile = "Dockerfile" - tags = ["backer:${TAG}"] + tags = ["${REGISTRY}:${TAG}"] platforms = ["linux/amd64", "linux/arm64"] args = { GH_PROXY = GH_PROXY From a1b160b1edec1c0fc2e258e63df6af000a7e4aa4 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 21:28:20 +0800 Subject: [PATCH 03/36] fix(ci): fix publish workflow failures - Linux: gracefully handle missing backer-gui (Qt6 download failed) - Windows: disable GUI build (Qt6 not installed on runner) - Docker: remove image field from docker-compose.yml to avoid overriding HCL tags --- .github/workflows/publish-release.yml | 21 ++++++++++++++------- docker-compose.yml | 1 - 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index f0a363b..1c64862 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -41,11 +41,19 @@ jobs: VERSION=${GITHUB_REF_NAME#v} mkdir -p dist cp build/backer-cli dist/backer-cli - cp build/backer-gui dist/backer-gui cp LICENSE dist/ - cd dist - tar czf ../${{ env.PROJECT_NAME }}-v${VERSION}-linux-x86_64.tar.gz \ - backer-cli backer-gui LICENSE + # GUI is optional — only include if built successfully + if [ -f build/backer-gui ]; then + cp build/backer-gui dist/backer-gui + cd dist + tar czf ../${{ env.PROJECT_NAME }}-v${VERSION}-linux-x86_64.tar.gz \ + backer-cli backer-gui LICENSE + else + echo "::warning::backer-gui not built, packaging CLI only" + cd dist + tar czf ../${{ env.PROJECT_NAME }}-v${VERSION}-linux-x86_64.tar.gz \ + backer-cli LICENSE + fi - uses: actions/upload-artifact@v4 with: @@ -147,7 +155,7 @@ jobs: name: macos-arm64-artifacts path: ${{ env.PROJECT_NAME }}-v*-macos-arm64.tar.gz - # ── Windows 构建 ──────────────────────────────────── + # ── Windows 构建(CLI only,Qt6 未适配 Windows) ───── windows-build: runs-on: windows-2022 defaults: @@ -171,7 +179,7 @@ jobs: - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} ` - -DBUILD_TESTING=OFF -DBUILD_GUI=ON + -DBUILD_TESTING=OFF -DBUILD_GUI=OFF - name: Build run: cmake --build build -j $env:NUMBER_OF_PROCESSORS --config ${{ env.BUILD_TYPE }} @@ -181,7 +189,6 @@ jobs: $VERSION = "${{ github.ref_name }}".Substring(1) New-Item -ItemType Directory -Path dist -Force Copy-Item build/${{ env.BUILD_TYPE }}/backer-cli.exe dist/ - Copy-Item build/${{ env.BUILD_TYPE }}/backer-gui.exe dist/ Copy-Item LICENSE dist/ # Bundle OpenSSL runtime DLLs for portable executables $osslBin = "$env:OPENSSL_ROOT_DIR\bin" diff --git a/docker-compose.yml b/docker-compose.yml index a99de96..b204f0c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,6 @@ services: build: context: . dockerfile: Dockerfile - image: backer:latest container_name: backer entrypoint: ["/usr/local/bin/backer"] command: ["--help"] From 0605c099b059792b1e011fff1784a6a37635cf2a Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 21:34:05 +0800 Subject: [PATCH 04/36] fix(ci): specify docker-bake.hcl explicitly to avoid docker-compose.yml interference --- .github/workflows/docker-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 96b49fa..a0f64b4 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -34,6 +34,7 @@ jobs: run: | docker buildx bake \ --push \ + --file docker-bake.hcl \ default - name: Verify image From 1c9dcf4bb7791141855167ae592357acaced628f Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 21:43:50 +0800 Subject: [PATCH 05/36] fix(ci): detect OpenSSL DLL version dynamically on Windows --- .github/workflows/publish-release.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 1c64862..573544c 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -191,12 +191,17 @@ jobs: Copy-Item build/${{ env.BUILD_TYPE }}/backer-cli.exe dist/ Copy-Item LICENSE dist/ # Bundle OpenSSL runtime DLLs for portable executables + # Detect version (3.x or 4.x) dynamically $osslBin = "$env:OPENSSL_ROOT_DIR\bin" - if (Test-Path "$osslBin\libcrypto-3-x64.dll") { - Copy-Item "$osslBin\libcrypto-3-x64.dll" dist/ + $cryptoDll = Get-ChildItem "$osslBin\libcrypto-*-x64.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 + $sslDll = Get-ChildItem "$osslBin\libssl-*-x64.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 + if ($cryptoDll) { + Copy-Item $cryptoDll.FullName dist/ + Write-Host "Bundled: $($cryptoDll.Name)" } - if (Test-Path "$osslBin\libssl-3-x64.dll") { - Copy-Item "$osslBin\libssl-3-x64.dll" dist/ + if ($sslDll) { + Copy-Item $sslDll.FullName dist/ + Write-Host "Bundled: $($sslDll.Name)" } Compress-Archive -Path dist/* -DestinationPath ` "${{ env.PROJECT_NAME }}-v${VERSION}-windows-x86_64.zip" -Force From 0355bd5a3d3e5e68e3c11f4461ea3d39b77489d0 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 21:45:18 +0800 Subject: [PATCH 06/36] perf(ci): add Docker layer caching to speed up builds --- .github/workflows/docker-publish.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index a0f64b4..ec6b7d3 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -20,6 +20,14 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + - name: Cache Docker layers + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: @@ -35,7 +43,12 @@ jobs: docker buildx bake \ --push \ --file docker-bake.hcl \ + --cache-from type=local,src=/tmp/.buildx-cache \ + --cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max \ default + # Move cache to avoid ever-growing cache + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache - name: Verify image run: | From bcca2c8e1803c01373df7f960707a3424a4a2983 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 21:48:18 +0800 Subject: [PATCH 07/36] fix(ci): remove unsupported cache flags from docker buildx bake --- .github/workflows/docker-publish.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index ec6b7d3..a0f64b4 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -20,14 +20,6 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Cache Docker layers - uses: actions/cache@v4 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: @@ -43,12 +35,7 @@ jobs: docker buildx bake \ --push \ --file docker-bake.hcl \ - --cache-from type=local,src=/tmp/.buildx-cache \ - --cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max \ default - # Move cache to avoid ever-growing cache - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache - name: Verify image run: | From 760d2fc1118cdad5917f716e5eec6c8a12615056 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 21:54:42 +0800 Subject: [PATCH 08/36] fix(ci): auto-delete existing release before creating new one --- .github/workflows/publish-release.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 573544c..1968edd 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -234,6 +234,15 @@ jobs: done ls -lh assets/ + - name: Delete existing release if present + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then + echo "Release ${{ github.ref_name }} already exists, deleting..." + gh release delete "${{ github.ref_name }}" --yes --cleanup-tag=false + fi + - name: Create Release uses: ncipollo/release-action@v1 with: From b99365fe26d27626ac26b4789b11391cad962c59 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:04:53 +0800 Subject: [PATCH 09/36] feat(ci): static OpenSSL linking on Windows, remove DLL dependencies --- .github/workflows/publish-release.yml | 27 ++++++++------------------- CMakeLists.txt | 5 +++++ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 1968edd..e1a87ea 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -155,7 +155,7 @@ jobs: name: macos-arm64-artifacts path: ${{ env.PROJECT_NAME }}-v*-macos-arm64.tar.gz - # ── Windows 构建(CLI only,Qt6 未适配 Windows) ───── + # ── Windows 构建(静态 OpenSSL,无 DLL 依赖) ──────── windows-build: runs-on: windows-2022 defaults: @@ -164,22 +164,24 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install OpenSSL + - name: Install static OpenSSL via vcpkg run: | - choco install openssl -y --no-progress - echo "OPENSSL_ROOT_DIR=C:\Program Files\OpenSSL" | Out-File -FilePath $env:GITHUB_ENV -Append + vcpkg install openssl:x64-windows-static + echo "OPENSSL_ROOT_DIR=C:\vcpkg\installed\x64-windows-static" | Out-File -FilePath $env:GITHUB_ENV -Append - name: Cache CMake dependencies uses: actions/cache@v4 with: path: build/_deps - key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-windows + key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-windows-static restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}- - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} ` - -DBUILD_TESTING=OFF -DBUILD_GUI=OFF + -DBUILD_TESTING=OFF -DBUILD_GUI=OFF ` + -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake ` + -DVCPKG_TARGET_TRIPLET=x64-windows-static - name: Build run: cmake --build build -j $env:NUMBER_OF_PROCESSORS --config ${{ env.BUILD_TYPE }} @@ -190,19 +192,6 @@ jobs: New-Item -ItemType Directory -Path dist -Force Copy-Item build/${{ env.BUILD_TYPE }}/backer-cli.exe dist/ Copy-Item LICENSE dist/ - # Bundle OpenSSL runtime DLLs for portable executables - # Detect version (3.x or 4.x) dynamically - $osslBin = "$env:OPENSSL_ROOT_DIR\bin" - $cryptoDll = Get-ChildItem "$osslBin\libcrypto-*-x64.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 - $sslDll = Get-ChildItem "$osslBin\libssl-*-x64.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 - if ($cryptoDll) { - Copy-Item $cryptoDll.FullName dist/ - Write-Host "Bundled: $($cryptoDll.Name)" - } - if ($sslDll) { - Copy-Item $sslDll.FullName dist/ - Write-Host "Bundled: $($sslDll.Name)" - } Compress-Archive -Path dist/* -DestinationPath ` "${{ env.PROJECT_NAME }}-v${VERSION}-windows-x86_64.zip" -Force diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a8fc72..c7474db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,11 @@ target_link_libraries(backer_core PRIVATE liblzma ) +# Static linking on Windows: define OPENSSL_STATIC to avoid DLL imports +if(WIN32 AND OPENSSL_STATIC) + target_compile_definitions(backer_core PUBLIC OPENSSL_STATIC) +endif() + # ccronexpr needs local-time mode for cron expressions in the user's timezone target_compile_definitions(backer_core PRIVATE $<$:CRON_USE_LOCAL_TIME=1>) From abfc60d3a766c547fbf45d42d96ae3e8fdef898d Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:06:46 +0800 Subject: [PATCH 10/36] feat(ci): add Qt6 GUI to Windows build via aqtinstall --- .github/workflows/publish-release.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index e1a87ea..8478453 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -155,7 +155,7 @@ jobs: name: macos-arm64-artifacts path: ${{ env.PROJECT_NAME }}-v*-macos-arm64.tar.gz - # ── Windows 构建(静态 OpenSSL,无 DLL 依赖) ──────── + # ── Windows 构建(静态 OpenSSL + Qt6 GUI) ─────────── windows-build: runs-on: windows-2022 defaults: @@ -169,6 +169,12 @@ jobs: vcpkg install openssl:x64-windows-static echo "OPENSSL_ROOT_DIR=C:\vcpkg\installed\x64-windows-static" | Out-File -FilePath $env:GITHUB_ENV -Append + - name: Install Qt6 via aqtinstall + run: | + pip install aqtinstall + python -m aqt install-qt windows desktop 6.5.0 win64_msvc2022_64 -O C:\Qt6 --modules qtbase + echo "Qt6_DIR=C:\Qt6\6.5.0\msvc2022_64" | Out-File -FilePath $env:GITHUB_ENV -Append + - name: Cache CMake dependencies uses: actions/cache@v4 with: @@ -179,7 +185,7 @@ jobs: - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} ` - -DBUILD_TESTING=OFF -DBUILD_GUI=OFF ` + -DBUILD_TESTING=OFF -DBUILD_GUI=ON ` -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake ` -DVCPKG_TARGET_TRIPLET=x64-windows-static @@ -191,6 +197,9 @@ jobs: $VERSION = "${{ github.ref_name }}".Substring(1) New-Item -ItemType Directory -Path dist -Force Copy-Item build/${{ env.BUILD_TYPE }}/backer-cli.exe dist/ + if (Test-Path "build/${{ env.BUILD_TYPE }}/backer-gui.exe") { + Copy-Item build/${{ env.BUILD_TYPE }}/backer-gui.exe dist/ + } Copy-Item LICENSE dist/ Compress-Archive -Path dist/* -DestinationPath ` "${{ env.PROJECT_NAME }}-v${VERSION}-windows-x86_64.zip" -Force From a18e470e9d1206976fd36acdc63330803418009e Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:12:08 +0800 Subject: [PATCH 11/36] fix(ci): use vcpkg for Qt6 on Windows, remove aqtinstall Switch Windows Qt6 installation from aqtinstall to vcpkg to unify dependency management with OpenSSL. Add vcpkg binary cache to speed up subsequent builds. --- .github/workflows/publish-release.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 8478453..33dbace 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -164,16 +164,18 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install static OpenSSL via vcpkg + - name: Install dependencies via vcpkg run: | - vcpkg install openssl:x64-windows-static + vcpkg install openssl:x64-windows-static qtbase:x64-windows-static echo "OPENSSL_ROOT_DIR=C:\vcpkg\installed\x64-windows-static" | Out-File -FilePath $env:GITHUB_ENV -Append - - name: Install Qt6 via aqtinstall - run: | - pip install aqtinstall - python -m aqt install-qt windows desktop 6.5.0 win64_msvc2022_64 -O C:\Qt6 --modules qtbase - echo "Qt6_DIR=C:\Qt6\6.5.0\msvc2022_64" | Out-File -FilePath $env:GITHUB_ENV -Append + - name: Cache vcpkg installed packages + uses: actions/cache@v4 + with: + path: C:\vcpkg\installed + key: vcpkg-${{ env.BUILD_TYPE }}-windows-${{ hashFiles('CMakeLists.txt') }} + restore-keys: | + vcpkg-${{ env.BUILD_TYPE }}-windows- - name: Cache CMake dependencies uses: actions/cache@v4 From 26440fc25862214bce785c5f33eb8f7336a19846 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:16:53 +0800 Subject: [PATCH 12/36] fix(ci): use correct Qt6 arch identifier for Windows Qt 6.5.0 provides win64_msvc2019_64, not win64_msvc2022_64. MSVC 2019 binaries are ABI-compatible with MSVC 2022. Also pass -DQt6_DIR explicitly to cmake for reliable discovery. --- .github/workflows/publish-release.yml | 16 +++++++--------- cmake/FetchQt6.cmake | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 33dbace..943b287 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -164,18 +164,15 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install dependencies via vcpkg + - name: Install static OpenSSL via vcpkg run: | - vcpkg install openssl:x64-windows-static qtbase:x64-windows-static + vcpkg install openssl:x64-windows-static echo "OPENSSL_ROOT_DIR=C:\vcpkg\installed\x64-windows-static" | Out-File -FilePath $env:GITHUB_ENV -Append - - name: Cache vcpkg installed packages - uses: actions/cache@v4 - with: - path: C:\vcpkg\installed - key: vcpkg-${{ env.BUILD_TYPE }}-windows-${{ hashFiles('CMakeLists.txt') }} - restore-keys: | - vcpkg-${{ env.BUILD_TYPE }}-windows- + - name: Install Qt6 via aqtinstall + run: | + pip install aqtinstall + python -m aqt install-qt windows desktop 6.5.0 win64_msvc2019_64 -O C:\Qt6 --modules qtbase - name: Cache CMake dependencies uses: actions/cache@v4 @@ -188,6 +185,7 @@ jobs: run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} ` -DBUILD_TESTING=OFF -DBUILD_GUI=ON ` + -DQt6_DIR=C:/Qt6/6.5.0/msvc2019_64 ` -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake ` -DVCPKG_TARGET_TRIPLET=x64-windows-static diff --git a/cmake/FetchQt6.cmake b/cmake/FetchQt6.cmake index 2191288..5fbf4f6 100644 --- a/cmake/FetchQt6.cmake +++ b/cmake/FetchQt6.cmake @@ -70,7 +70,7 @@ endif() # ── Detect platform for aqtinstall ──────────────────────────────────── if(WIN32) set(_aqt_platform "windows") - set(_aqt_arch "win64_msvc2022_64") + set(_aqt_arch "win64_msvc2019_64") elseif(APPLE) set(_aqt_platform "mac") if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64") From a41621b4a555a3b3f2a7e99000a3b5bb3634434f Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:26:47 +0800 Subject: [PATCH 13/36] perf(ci): add vcpkg binary cache for Windows OpenSSL Cache vcpkg compiled packages at %LOCALAPPDATA%\vcpkg\archives to skip recompilation on subsequent runs. --- .github/workflows/publish-release.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 943b287..37d5350 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -164,6 +164,14 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Cache vcpkg binaries + uses: actions/cache@v4 + with: + path: ${{ env.LOCALAPPDATA }}\vcpkg\archives + key: vcpkg-${{ env.BUILD_TYPE }}-windows-${{ hashFiles('CMakeLists.txt') }} + restore-keys: | + vcpkg-${{ env.BUILD_TYPE }}-windows- + - name: Install static OpenSSL via vcpkg run: | vcpkg install openssl:x64-windows-static From 6c0762138951e576548760bf408a2194a4ca9aa1 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:27:52 +0800 Subject: [PATCH 14/36] fix(ci): remove invalid --modules qtbase from aqtinstall qtbase is the default package, not a module. The --modules flag causes aqtinstall to fail with 'packages not found' error. --- .github/workflows/publish-release.yml | 2 +- cmake/FetchQt6.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 37d5350..dc8a87a 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -180,7 +180,7 @@ jobs: - name: Install Qt6 via aqtinstall run: | pip install aqtinstall - python -m aqt install-qt windows desktop 6.5.0 win64_msvc2019_64 -O C:\Qt6 --modules qtbase + python -m aqt install-qt windows desktop 6.5.0 win64_msvc2019_64 -O C:\Qt6 - name: Cache CMake dependencies uses: actions/cache@v4 diff --git a/cmake/FetchQt6.cmake b/cmake/FetchQt6.cmake index 5fbf4f6..2f4a05a 100644 --- a/cmake/FetchQt6.cmake +++ b/cmake/FetchQt6.cmake @@ -97,7 +97,7 @@ message(STATUS "FetchQt6: this may take several minutes...") execute_process(COMMAND ${_python} -m aqt install-qt ${_aqt_platform} desktop "${QT6_VERSION}" ${_aqt_arch} - -O "${_qt_dir}" --modules qtbase + -O "${_qt_dir}" OUTPUT_VARIABLE _aqt_out ERROR_VARIABLE _aqt_err RESULT_VARIABLE _aqt_ret TIMEOUT 600) From 3b68e442629fb59b00e04bb944cebe24430085d8 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:30:53 +0800 Subject: [PATCH 15/36] fix(ci): use install-qt-action for Windows Qt6 Replace manual aqtinstall with jurplel/install-qt-action@v4 which handles download, path setup, and caching automatically. --- .github/workflows/publish-release.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index dc8a87a..a9730c6 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -177,10 +177,13 @@ jobs: vcpkg install openssl:x64-windows-static echo "OPENSSL_ROOT_DIR=C:\vcpkg\installed\x64-windows-static" | Out-File -FilePath $env:GITHUB_ENV -Append - - name: Install Qt6 via aqtinstall - run: | - pip install aqtinstall - python -m aqt install-qt windows desktop 6.5.0 win64_msvc2019_64 -O C:\Qt6 + - name: Install Qt6 + uses: jurplel/install-qt-action@v4 + with: + version: '6.5.0' + host: 'windows' + target: 'desktop' + arch: 'win64_msvc2019_64' - name: Cache CMake dependencies uses: actions/cache@v4 @@ -193,7 +196,6 @@ jobs: run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} ` -DBUILD_TESTING=OFF -DBUILD_GUI=ON ` - -DQt6_DIR=C:/Qt6/6.5.0/msvc2019_64 ` -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake ` -DVCPKG_TARGET_TRIPLET=x64-windows-static From 7b6117fdf5571cd9cfab23da4843845f2ba9de64 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:33:33 +0800 Subject: [PATCH 16/36] fix(ci): simplify Windows build - choco OpenSSL + install-qt-action - Replace vcpkg static OpenSSL with choco install (faster, simpler) - Use jurplel/install-qt-action for Qt6 - Add windeployqt for automatic DLL packaging - Remove vcpkg toolchain and triplet from cmake --- .github/workflows/publish-release.yml | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index a9730c6..b24fb5c 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -155,7 +155,7 @@ jobs: name: macos-arm64-artifacts path: ${{ env.PROJECT_NAME }}-v*-macos-arm64.tar.gz - # ── Windows 构建(静态 OpenSSL + Qt6 GUI) ─────────── + # ── Windows 构建(Qt6 GUI + OpenSSL) ─────────────── windows-build: runs-on: windows-2022 defaults: @@ -164,18 +164,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Cache vcpkg binaries - uses: actions/cache@v4 - with: - path: ${{ env.LOCALAPPDATA }}\vcpkg\archives - key: vcpkg-${{ env.BUILD_TYPE }}-windows-${{ hashFiles('CMakeLists.txt') }} - restore-keys: | - vcpkg-${{ env.BUILD_TYPE }}-windows- - - - name: Install static OpenSSL via vcpkg + - name: Install OpenSSL run: | - vcpkg install openssl:x64-windows-static - echo "OPENSSL_ROOT_DIR=C:\vcpkg\installed\x64-windows-static" | Out-File -FilePath $env:GITHUB_ENV -Append + choco install openssl -y --no-progress + echo "OPENSSL_ROOT_DIR=C:\Program Files\OpenSSL" | Out-File -FilePath $env:GITHUB_ENV -Append - name: Install Qt6 uses: jurplel/install-qt-action@v4 @@ -189,15 +181,13 @@ jobs: uses: actions/cache@v4 with: path: build/_deps - key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-windows-static + key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-windows restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}- - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} ` - -DBUILD_TESTING=OFF -DBUILD_GUI=ON ` - -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake ` - -DVCPKG_TARGET_TRIPLET=x64-windows-static + -DBUILD_TESTING=OFF -DBUILD_GUI=ON - name: Build run: cmake --build build -j $env:NUMBER_OF_PROCESSORS --config ${{ env.BUILD_TYPE }} @@ -209,6 +199,7 @@ jobs: Copy-Item build/${{ env.BUILD_TYPE }}/backer-cli.exe dist/ if (Test-Path "build/${{ env.BUILD_TYPE }}/backer-gui.exe") { Copy-Item build/${{ env.BUILD_TYPE }}/backer-gui.exe dist/ + & "$env:Qt6_DIR\..\..\..\..\bin\windeployqt.exe" dist/backer-gui.exe } Copy-Item LICENSE dist/ Compress-Archive -Path dist/* -DestinationPath ` From 2486bd0dda0a3cbc77114671ced130c0394f15a8 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:34:35 +0800 Subject: [PATCH 17/36] fix(ci): enable Qt6 caching for Windows build Add cache: 'true' to install-qt-action to skip re-downloading Qt6 on subsequent runs. --- .github/workflows/publish-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index b24fb5c..cd090ed 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -176,6 +176,7 @@ jobs: host: 'windows' target: 'desktop' arch: 'win64_msvc2019_64' + cache: 'true' - name: Cache CMake dependencies uses: actions/cache@v4 From fde3606d5e2c441c9e8f7201560fffab98b470c5 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:40:47 +0800 Subject: [PATCH 18/36] fix(ci): use windeployqt directly from PATH install-qt-action adds Qt bin to PATH, no need for manual path construction. --- .github/workflows/publish-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index cd090ed..58d3ef6 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -200,7 +200,7 @@ jobs: Copy-Item build/${{ env.BUILD_TYPE }}/backer-cli.exe dist/ if (Test-Path "build/${{ env.BUILD_TYPE }}/backer-gui.exe") { Copy-Item build/${{ env.BUILD_TYPE }}/backer-gui.exe dist/ - & "$env:Qt6_DIR\..\..\..\..\bin\windeployqt.exe" dist/backer-gui.exe + windeployqt dist/backer-gui.exe } Copy-Item LICENSE dist/ Compress-Archive -Path dist/* -DestinationPath ` From a02ce809066d6f423f53bb7027fff8420eb293f4 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:44:24 +0800 Subject: [PATCH 19/36] fix(ci): disable Qt6 auto-download on Linux in publish-release System Qt6 from apt may have different version than FetchQt6.cmake expects, causing path conflicts. Disable auto-download to use the system package directly. --- .github/workflows/publish-release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 58d3ef6..b6b6ac4 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -31,7 +31,8 @@ jobs: - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ - -DBUILD_TESTING=OFF -DBUILD_GUI=ON + -DBUILD_TESTING=OFF -DBUILD_GUI=ON \ + -DQT6_AUTO_DOWNLOAD=OFF - name: Build run: cmake --build build -j$(nproc) From 6fc656cc4be5c49851a4a64200a6b1efa4a16498 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:49:20 +0800 Subject: [PATCH 20/36] fix(ci): disable Qt6 auto-download on all platforms in publish-release FetchQt6.cmake auto-download conflicts with system-installed Qt6 on Linux (apt), macOS (brew), and Windows (install-qt-action). Set QT6_AUTO_DOWNLOAD=OFF to use the pre-installed Qt6 directly. --- .github/workflows/publish-release.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index b6b6ac4..1c5a762 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -87,7 +87,8 @@ jobs: - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ - -DBUILD_TESTING=OFF -DBUILD_GUI=ON + -DBUILD_TESTING=OFF -DBUILD_GUI=ON \ + -DQT6_AUTO_DOWNLOAD=OFF - name: Build run: cmake --build build -j$(sysctl -n hw.logicalcpu) @@ -135,7 +136,8 @@ jobs: run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DBUILD_TESTING=OFF -DBUILD_GUI=ON \ - -DCMAKE_OSX_ARCHITECTURES=arm64 + -DCMAKE_OSX_ARCHITECTURES=arm64 \ + -DQT6_AUTO_DOWNLOAD=OFF - name: Build run: cmake --build build -j$(sysctl -n hw.logicalcpu) @@ -189,7 +191,8 @@ jobs: - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} ` - -DBUILD_TESTING=OFF -DBUILD_GUI=ON + -DBUILD_TESTING=OFF -DBUILD_GUI=ON ` + -DQT6_AUTO_DOWNLOAD=OFF - name: Build run: cmake --build build -j $env:NUMBER_OF_PROCESSORS --config ${{ env.BUILD_TYPE }} From 3f4553fbeb288e5e47f978a8befb4b7d5673918c Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:53:29 +0800 Subject: [PATCH 21/36] fix(ci): add runner.os to cache keys to prevent cross-platform pollution CMakeCache.txt contains absolute paths. Without runner.os in the key, macOS could restore Linux cache (different HOME paths), causing 'CMakeCache.txt directory is different' errors. --- .github/workflows/publish-release.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 1c5a762..93e2d80 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -25,8 +25,8 @@ jobs: uses: actions/cache@v4 with: path: build/_deps - key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-linux - restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}- + key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-${{ runner.os }} + restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}-${{ runner.os }}- - name: Configure CMake run: | @@ -81,8 +81,8 @@ jobs: uses: actions/cache@v4 with: path: build/_deps - key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-macos - restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}- + key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-${{ runner.os }} + restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}-${{ runner.os }}- - name: Configure CMake run: | @@ -129,8 +129,8 @@ jobs: uses: actions/cache@v4 with: path: build/_deps - key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-macos-arm64 - restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}- + key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-${{ runner.os }}-arm64 + restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}-${{ runner.os }}- - name: Configure CMake run: | @@ -185,8 +185,8 @@ jobs: uses: actions/cache@v4 with: path: build/_deps - key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-windows - restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}- + key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-${{ runner.os }} + restore-keys: deps-${{ hashFiles('CMakeLists.txt') }}-${{ runner.os }}- - name: Configure CMake run: | From dd24239d577f51b8240b5a4b248bc45f1eaa66fb Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 22:55:42 +0800 Subject: [PATCH 22/36] fix(ci): tolerate windeployqt non-zero exit code windeployqt successfully copies all DLLs but returns non-zero on translation file warnings. Use ; if ($LASTEXITCODE) to downgrade to a warning instead of failing the entire package step. --- .github/workflows/publish-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 93e2d80..23dd817 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -204,7 +204,7 @@ jobs: Copy-Item build/${{ env.BUILD_TYPE }}/backer-cli.exe dist/ if (Test-Path "build/${{ env.BUILD_TYPE }}/backer-gui.exe") { Copy-Item build/${{ env.BUILD_TYPE }}/backer-gui.exe dist/ - windeployqt dist/backer-gui.exe + windeployqt dist/backer-gui.exe; if ($LASTEXITCODE -ne 0) { Write-Warning "windeployqt exited with $LASTEXITCODE" } } Copy-Item LICENSE dist/ Compress-Archive -Path dist/* -DestinationPath ` From 04fe7a67731b3017018f4b593e1dc546999cfcd9 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 23:02:32 +0800 Subject: [PATCH 23/36] fix(ci): disable Qt6 auto-download on Linux in ci.yml Auto-downloaded Qt6 6.5.0 conflicts with system Qt6 6.2.4 from apt, causing 'Qt6Gui could not be found' errors in FetchQt6.cmake. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3933dc1..db88503 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,7 @@ jobs: -DCMAKE_C_COMPILER=${{ matrix.compiler.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -DBUILD_TESTING=ON -DBUILD_GUI=ON + -DQT6_AUTO_DOWNLOAD=OFF - name: Build run: cmake --build build -j$(nproc) From 96728aa62c306004e2bf47d350bda1e1775ede1f Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 23:03:58 +0800 Subject: [PATCH 24/36] feat(ci): test GUI build on macOS and Windows in ci.yml Add Qt6 installation and -DBUILD_GUI=ON to macOS and Windows CI jobs to ensure GUI builds are tested across all platforms. --- .github/workflows/ci.yml | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db88503..541470f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,20 +63,25 @@ jobs: brew install openssl echo "OPENSSL_ROOT_DIR=$(brew --prefix openssl)" >> $GITHUB_ENV + - name: Install Qt6 + run: | + brew install qt@6 + echo "Qt6_DIR=$(brew --prefix qt@6)" >> $GITHUB_ENV + - name: Cache CMake dependencies uses: actions/cache@v4 with: path: build/_deps - key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-macOS + key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-${{ runner.os }} restore-keys: | - deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-macOS- - deps-${{ hashFiles('CMakeLists.txt') }}-macOS- - deps-macOS- + deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-${{ runner.os }}- + deps-${{ hashFiles('CMakeLists.txt') }}-${{ runner.os }}- - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ - -DBUILD_TESTING=ON + -DBUILD_TESTING=ON -DBUILD_GUI=ON \ + -DQT6_AUTO_DOWNLOAD=OFF - name: Build run: cmake --build build -j$(sysctl -n hw.logicalcpu) @@ -96,20 +101,29 @@ jobs: echo "OPENSSL_ROOT_DIR=C:\Program Files\OpenSSL" | Out-File -FilePath $env:GITHUB_ENV -Append shell: pwsh + - name: Install Qt6 + uses: jurplel/install-qt-action@v4 + with: + version: '6.5.0' + host: 'windows' + target: 'desktop' + arch: 'win64_msvc2019_64' + cache: 'true' + - name: Cache CMake dependencies uses: actions/cache@v4 with: path: build/_deps - key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-Windows + key: deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-${{ runner.os }} restore-keys: | - deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-Windows- - deps-${{ hashFiles('CMakeLists.txt') }}-Windows- - deps-Windows- + deps-${{ hashFiles('CMakeLists.txt') }}-${{ env.BUILD_TYPE }}-${{ runner.os }}- + deps-${{ hashFiles('CMakeLists.txt') }}-${{ runner.os }}- - name: Configure CMake run: | cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} ` - -DBUILD_TESTING=ON + -DBUILD_TESTING=ON -DBUILD_GUI=ON ` + -DQT6_AUTO_DOWNLOAD=OFF - name: Build run: cmake --build build -j $env:NUMBER_OF_PROCESSORS --config ${{ env.BUILD_TYPE }} From a1f4411fae63fb60a2a703c7a542e7834d80c0e4 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 23:05:19 +0800 Subject: [PATCH 25/36] fix(ci): reset PowerShell exit code after windeployqt warning windeployqt returns non-zero on translation file issues but successfully copies all DLLs. Reset LASTEXITCODE to 0 to prevent PowerShell from propagating the error. --- .github/workflows/publish-release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 23dd817..0e61530 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -204,7 +204,8 @@ jobs: Copy-Item build/${{ env.BUILD_TYPE }}/backer-cli.exe dist/ if (Test-Path "build/${{ env.BUILD_TYPE }}/backer-gui.exe") { Copy-Item build/${{ env.BUILD_TYPE }}/backer-gui.exe dist/ - windeployqt dist/backer-gui.exe; if ($LASTEXITCODE -ne 0) { Write-Warning "windeployqt exited with $LASTEXITCODE" } + windeployqt dist/backer-gui.exe + if ($LASTEXITCODE -ne 0) { Write-Warning "windeployqt exited with $LASTEXITCODE"; $global:LASTEXITCODE = 0 } } Copy-Item LICENSE dist/ Compress-Archive -Path dist/* -DestinationPath ` From 7f6e361b42eab03ab3fc8ba5b43f65d017714349 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 23:18:42 +0800 Subject: [PATCH 26/36] fix(ci): copy OpenSSL DLLs to dist on Windows windeployqt only bundles Qt dependencies. Manually copy libcrypto-3-x64.dll and libssl-3-x64.dll from choco's OpenSSL installation to ensure the runtime has the correct SSL libraries. --- .github/workflows/publish-release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 0e61530..172743e 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -207,6 +207,8 @@ jobs: windeployqt dist/backer-gui.exe if ($LASTEXITCODE -ne 0) { Write-Warning "windeployqt exited with $LASTEXITCODE"; $global:LASTEXITCODE = 0 } } + Copy-Item "C:\Program Files\OpenSSL\bin\libcrypto-3-x64.dll" dist/ + Copy-Item "C:\Program Files\OpenSSL\bin\libssl-3-x64.dll" dist/ Copy-Item LICENSE dist/ Compress-Archive -Path dist/* -DestinationPath ` "${{ env.PROJECT_NAME }}-v${VERSION}-windows-x86_64.zip" -Force From a4e9c0d642cb6ee96402b28c9bd8b62b72f224fe Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 23:20:39 +0800 Subject: [PATCH 27/36] fix(ci): use correct OpenSSL 4.x DLL names for Windows package OpenSSL 4.x uses libcrypto-40.dll/libssl-40.dll, not libcrypto-3-x64.dll/libssl-3-x64.dll (3.x naming). --- .github/workflows/publish-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 172743e..f656d00 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -207,8 +207,8 @@ jobs: windeployqt dist/backer-gui.exe if ($LASTEXITCODE -ne 0) { Write-Warning "windeployqt exited with $LASTEXITCODE"; $global:LASTEXITCODE = 0 } } - Copy-Item "C:\Program Files\OpenSSL\bin\libcrypto-3-x64.dll" dist/ - Copy-Item "C:\Program Files\OpenSSL\bin\libssl-3-x64.dll" dist/ + Copy-Item "C:\Program Files\OpenSSL\bin\libcrypto-40.dll" dist/ + Copy-Item "C:\Program Files\OpenSSL\bin\libssl-40.dll" dist/ Copy-Item LICENSE dist/ Compress-Archive -Path dist/* -DestinationPath ` "${{ env.PROJECT_NAME }}-v${VERSION}-windows-x86_64.zip" -Force From 73ed53c022a89a98a0ce5e703122e2290b9f8458 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 23:21:17 +0800 Subject: [PATCH 28/36] fix(ci): OpenSSL 4.x DLL names are libcrypto-4.dll, not libcrypto-40.dll --- .github/workflows/publish-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index f656d00..542f110 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -207,8 +207,8 @@ jobs: windeployqt dist/backer-gui.exe if ($LASTEXITCODE -ne 0) { Write-Warning "windeployqt exited with $LASTEXITCODE"; $global:LASTEXITCODE = 0 } } - Copy-Item "C:\Program Files\OpenSSL\bin\libcrypto-40.dll" dist/ - Copy-Item "C:\Program Files\OpenSSL\bin\libssl-40.dll" dist/ + Copy-Item "C:\Program Files\OpenSSL\bin\libcrypto-4.dll" dist/ + Copy-Item "C:\Program Files\OpenSSL\bin\libssl-4.dll" dist/ Copy-Item LICENSE dist/ Compress-Archive -Path dist/* -DestinationPath ` "${{ env.PROJECT_NAME }}-v${VERSION}-windows-x86_64.zip" -Force From ae902dad1dac4547e6b8c1ec29d0152080fec2c2 Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 23:21:50 +0800 Subject: [PATCH 29/36] fix(ci): correct OpenSSL 4.x DLL name is libcrypto-4-x64.dll --- .github/workflows/publish-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 542f110..1831471 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -207,8 +207,8 @@ jobs: windeployqt dist/backer-gui.exe if ($LASTEXITCODE -ne 0) { Write-Warning "windeployqt exited with $LASTEXITCODE"; $global:LASTEXITCODE = 0 } } - Copy-Item "C:\Program Files\OpenSSL\bin\libcrypto-4.dll" dist/ - Copy-Item "C:\Program Files\OpenSSL\bin\libssl-4.dll" dist/ + Copy-Item "C:\Program Files\OpenSSL\bin\libcrypto-4-x64.dll" dist/ + Copy-Item "C:\Program Files\OpenSSL\bin\libssl-4-x64.dll" dist/ Copy-Item LICENSE dist/ Compress-Archive -Path dist/* -DestinationPath ` "${{ env.PROJECT_NAME }}-v${VERSION}-windows-x86_64.zip" -Force From a0f76e58da486339f2e128745f39cce09257a5af Mon Sep 17 00:00:00 2001 From: airprofly Date: Sun, 12 Jul 2026 23:30:34 +0800 Subject: [PATCH 30/36] fix(ci): delete existing tag before creating release to avoid 422 error Co-Authored-By: Claude --- .github/workflows/publish-release.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 1831471..4c0c533 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -241,13 +241,16 @@ jobs: done ls -lh assets/ - - name: Delete existing release if present + - name: Delete existing release and tag if present env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then echo "Release ${{ github.ref_name }} already exists, deleting..." - gh release delete "${{ github.ref_name }}" --yes --cleanup-tag=false + gh release delete "${{ github.ref_name }}" --yes --cleanup-tag=true + elif git ls-remote --tags origin "${{ github.ref_name }}" | grep -q "${{ github.ref_name }}"; then + echo "Tag ${{ github.ref_name }} exists without release, deleting tag..." + git push --delete origin "${{ github.ref_name }}" || true fi - name: Create Release From d0046c3fa890d6737e0b3c11e2bf6f1f345bbaf4 Mon Sep 17 00:00:00 2001 From: airprofly Date: Wed, 15 Jul 2026 01:27:15 +0800 Subject: [PATCH 31/36] feat(cli): support human-readable date format for --mtime-* options - add parseTimeOption helper accepting YYYY-MM-DD or YYYY-MM-DD HH:MM:SS - simplify setup-testdata.sh to minimal special-file test data - slim down usage docs to match current feature scope --- docs/usage.md | 692 ++++++++------------------------------ scripts/setup-testdata.sh | 325 ++---------------- src/cli/commands.cpp | 34 +- src/main.cpp | 8 +- 4 files changed, 197 insertions(+), 862 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index f1470e2..7a05e3f 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -4,650 +4,226 @@ --- -## 目录 - -- [构建](#构建) -- [功能详解](#功能详解) - - [图形界面(GUI)](#图形界面gui) - - [目录镜像备份](#目录镜像备份) - - [特殊文件处理](#特殊文件处理) - - [元数据保留](#元数据保留) - - [筛选器(6 维度)](#筛选器6-维度) - - [Tar 打包](#tar-打包) - - [Zip 打包](#zip-打包) - - [压缩解压](#压缩解压) - - [加密解密](#加密解密) -- [定时备份(计划任务)](#定时备份计划任务) -- [守护进程模式](#守护进程模式) -- [退出码](#退出码) -- [Docker 使用](#docker-使用) - ---- - ## 构建 ```bash -# CLI 版本(无外部依赖) cmake -B build -DCMAKE_BUILD_TYPE=Release cmake --build build -j$(nproc) - -# GUI 版本(自动下载 Qt6 预编译二进制,无需系统库) -cmake -B build -DBUILD_GUI=ON -DCMAKE_BUILD_TYPE=Release -cmake --build build -j$(nproc) ``` --- -## 功能详解 -### 目录镜像备份 - -**命令形式** +## 初始化测试数据 -```text -backer backup [OPTIONS] -backer restore [OPTIONS] -``` - -**说明** - -默认模式。Backer 将源目录递归扫描,在目标位置重建完整的目录结构,每个文件逐一复制: - -```text -源目录 备份目录 -data/source/ data/backup/ -├── docs/ ├── docs/ -│ ├── report.pdf │ ├── report.pdf -│ └── notes.txt │ └── notes.txt -├── src/ ├── src/ -│ └── main.cpp │ └── main.cpp -└── README.md └── README.md +```bash +rm -rf data/backup data/restore +./scripts/setup-testdata.sh ``` -备份完成后输出统计信息: - -```text -✓ Backup completed successfully - Files: 42 - Dirs: 8 - Size: 1234567 bytes - Skipped: 0 - Time: 123 ms -``` +--- -**示例** +## 目录镜像备份(基本要求 40分) +支持目录树的完整备份与还原,包含普通文件和目录结构。 ```bash -# 备份项目目录 +rm -rf data/backup data/restore ./build/backer-cli backup data/source data/backup - -# 还原备份 +ls -l data/backup ./build/backer-cli restore data/backup data/restore +ls -l data/restore ``` --- -### 特殊文件处理 - -Backer 使用 POSIX `lstat()` 检测文件类型,支持以下特殊文件的完整备份与还原: - -| 类型 | CLI 标识名 | 说明 | -|------|-----------|------| -| 符号链接 | `symlink`, `link`, `l` | 备份链接目标路径,还原时重建软链接 | -| 命名管道 | `fifo`, `pipe`, `p` | 通过 `mkfifo()` 创建 | -| 块设备 | `block`, `blockdev`, `b` | 通过 `mknod()` 创建,记录设备号(major/minor) | -| 字符设备 | `char`, `chardev`, `c` | 通过 `mknod()` 创建,记录设备号 | -| Socket | `socket`, `sock`, `s` | 备份条目存在,还原时创建空占位文件 | - -> **注意**:创建块/字符设备节点需要 root 权限。非 root 运行时相关设备会被跳过并记录警告。 - ---- - -### 元数据保留 - -Backer 自动保留并还原以下文件元数据: - -| 元数据 | 说明 | 还原条件 | -|--------|------|----------| -| 属主 (UID/GID) | 文件所有者和所属组 | 需要 `CAP_CHOWN` 能力(root) | -| 权限 (mode bits) | rwx + setuid/setgid/sticky | 始终还原(symlink 在 Linux 上跳过) | -| 访问时间 (atime) | 最后访问时间(纳秒精度) | 始终还原 | -| 修改时间 (mtime) | 最后修改时间(纳秒精度) | 始终还原 | -| 变更时间 (ctime) | 状态变更时间 | 记录但不还原 | - -元数据通过 JSON 文件(`backer_metadata.json`)存储在备份目录中。 - ---- - -### 筛选器(6 维度) - -筛选选项仅适用于 `backup` 子命令,`restore` 时不做筛选。 - -**命令形式** - -```text -backer-cli backup [--include-* ...] [--exclude-* ...] -``` - -**相关选项** - -| 维度 | 选项 | 说明 | 参数格式 | -|------|------|------|----------| -| 路径 | `--include-path ` | 仅包含匹配路径 glob 的文件(可重复) | `"src/*.cpp"` | -| | `--exclude-path ` | 排除匹配路径 glob 的文件(可重复) | `"build/*"` | -| 类型 | `--include-type ` | 仅包含指定类型的文件(可重复) | `file` / `dir` / `symlink` / `fifo` / `block` / `char` / `socket` | -| | `--exclude-type ` | 排除指定类型的文件(可重复) | 同上 | -| 名称 | `--include-name ` | 仅包含匹配文件名 glob 的文件(可重复) | `"*.txt"` | -| | `--exclude-name ` | 排除匹配文件名 glob 的文件(可重复) | `"*.tmp"` | -| 时间 | `--mtime-before ` | 排除修改时间在此时间戳**之后**的文件 | Unix 秒级时间戳 | -| | `--mtime-after ` | 排除修改时间在此时间戳**之前**的文件 | Unix 秒级时间戳 | -| 尺寸 | `--size-min ` | 最小文件大小(字节) | 数字 | -| | `--size-max ` | 最大文件大小(字节) | 数字 | -| 属主 | `--owner ` | 仅包含指定用户拥有的文件 | 系统用户名 | - -> **筛选逻辑**:相同维度的多个 `--include-*` 规则为**或**(OR)关系——满足任一即通过该维度;不同维度的规则为**与**(AND)关系——所有维度都必须通过。 - -筛选器在目录遍历之后、写入存储之前应用,支持 6 种独立的筛选维度: - -#### 1. 路径匹配 - -基于相对路径的 glob 匹配,使用 `fnmatch` 的 `FNM_PATHNAME` 语义——`*` 不匹配路径分隔符 `/`: +## 文件类型支持(10分) +支持符号链接、管道(FIFO)、字符设备、块设备等特殊文件的备份与还原。 ```bash -# 仅备份 subdir 目录下的文件 -./build/backer-cli backup data/source data/backup --include-path "subdir/*" - -# 排除 subdir 目录 -./build/backer-cli backup data/source data/backup --exclude-path "subdir/*" +rm -rf data/backup data/restore +./build/backer-cli backup data/source data/backup +ls -l data/backup +./build/backer-cli restore data/backup data/restore +ls -l data/restore ``` -#### 2. 文件类型 - -```bash -# 排除 FIFO 管道 -./build/backer-cli backup data/source data/backup --exclude-type fifo - -# 排除符号链接 -./build/backer-cli backup data/source data/backup --exclude-type symlink - -# 仅备份目录和普通文件 -./build/backer-cli backup data/source data/backup --include-type dir --include-type file -``` +--- -#### 3. 文件名 +## 元数据保留(10分) -基于文件名(不含路径部分)的 glob 匹配: +| 元数据 | 还原条件 | +|--------|----------| +| 属主 (UID/GID) | 需要 root | +| 权限 (mode bits) | 始终还原 | +| 访问/修改时间 | 始终还原(纳秒精度) | ```bash -# 仅备份 .txt 文件 -./build/backer-cli backup data/source data/backup --include-name "*.txt" - -# 排除 .fifo 文件 -./build/backer-cli backup data/source data/backup --exclude-name "*.fifo" +rm -rf data/backup data/restore +./build/backer-cli backup data/source data/backup +ls -l data/backup +./build/backer-cli restore data/backup data/restore +ls -l data/restore ``` -#### 4. 修改时间 +--- -基于 Unix 时间戳筛选: +## 筛选器(6维度各3分,共18分) ```bash -# 仅备份 2026 年 7 月 1 日之后修改过的文件 -./build/backer-cli backup data/source data/backup --mtime-after 1818000000 - -# 排除最近 7 天内修改过的文件 -./build/backer-cli backup data/source data/backup --mtime-before $(($(date +%s) - 7*86400)) +./build/backer-cli backup [--include-* ...] [--exclude-* ...] ``` -> `--mtime-after` 是包含下限,`--mtime-before` 是排他上限(修改时间在此之前的文件保留)。可用 `$(date +%s)` 获取当前 Unix 时间戳。 - -#### 5. 文件大小 +| 维度 | 选项 | 示例 | +|------|------|------| +| 路径 | `--include-path ` | `"src/*.cpp"` | +| | `--exclude-path ` | `"build/*"` | +| 类型 | `--include-type ` | `file`, `dir`, `symlink`, `fifo` | +| | `--exclude-type ` | 同上 | +| 名称 | `--include-name ` | `"*.txt"` | +| | `--exclude-name ` | `"*.tmp"` | +| 时间 | `--mtime-after