mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-14 00:52:04 +00:00
WIP: auto update
This commit is contained in:
248
.github/workflows/build_all.yml
vendored
248
.github/workflows/build_all.yml
vendored
@@ -5,6 +5,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- release/*
|
- release/*
|
||||||
|
- feature/auto-update # TODO: Remove after auto-update testing is complete
|
||||||
paths:
|
paths:
|
||||||
- 'deps/**'
|
- 'deps/**'
|
||||||
- 'src/**'
|
- 'src/**'
|
||||||
@@ -48,25 +49,28 @@ concurrency:
|
|||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_linux: # Separate so unit tests can wait on just Linux builds to complete.
|
# TODO: Re-enable after auto-update testing is complete
|
||||||
name: Build Linux
|
# build_linux: # Separate so unit tests can wait on just Linux builds to complete.
|
||||||
strategy:
|
# name: Build Linux
|
||||||
fail-fast: false
|
# strategy:
|
||||||
# Don't run scheduled builds on forks:
|
# fail-fast: false
|
||||||
if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
# # Don't run scheduled builds on forks:
|
||||||
uses: ./.github/workflows/build_deps.yml
|
# if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||||
with:
|
# uses: ./.github/workflows/build_deps.yml
|
||||||
os: ubuntu-24.04
|
# with:
|
||||||
build-deps-only: ${{ inputs.build-deps-only || false }}
|
# os: ubuntu-24.04
|
||||||
force-build: ${{ github.event_name == 'schedule' }}
|
# build-deps-only: ${{ inputs.build-deps-only || false }}
|
||||||
secrets: inherit
|
# force-build: ${{ github.event_name == 'schedule' }}
|
||||||
|
# secrets: inherit
|
||||||
|
|
||||||
build_all:
|
build_all:
|
||||||
name: Build Non-Linux
|
name: Build macOS (testing auto-update)
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: windows-latest
|
# TODO: Re-enable Windows after auto-update testing is complete
|
||||||
|
# - os: windows-latest
|
||||||
- os: macos-14
|
- os: macos-14
|
||||||
arch: arm64
|
arch: arm64
|
||||||
# Don't run scheduled builds on forks:
|
# Don't run scheduled builds on forks:
|
||||||
@@ -78,109 +82,113 @@ jobs:
|
|||||||
build-deps-only: ${{ inputs.build-deps-only || false }}
|
build-deps-only: ${{ inputs.build-deps-only || false }}
|
||||||
force-build: ${{ github.event_name == 'schedule' }}
|
force-build: ${{ github.event_name == 'schedule' }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
unit_tests:
|
|
||||||
name: Unit Tests
|
# TODO: Re-enable after auto-update testing is complete (depends on build_linux)
|
||||||
runs-on: ubuntu-24.04
|
# unit_tests:
|
||||||
needs: build_linux
|
# name: Unit Tests
|
||||||
if: ${{ !cancelled() && success() }}
|
# runs-on: ubuntu-24.04
|
||||||
steps:
|
# needs: build_linux
|
||||||
- name: Checkout
|
# if: ${{ !cancelled() && success() }}
|
||||||
uses: actions/checkout@v6
|
# steps:
|
||||||
with:
|
# - name: Checkout
|
||||||
sparse-checkout: |
|
# uses: actions/checkout@v6
|
||||||
.github
|
# with:
|
||||||
scripts
|
# sparse-checkout: |
|
||||||
tests
|
# .github
|
||||||
- name: Apt-Install Dependencies
|
# scripts
|
||||||
uses: ./.github/actions/apt-install-deps
|
# tests
|
||||||
- name: Restore Test Artifact
|
# - name: Apt-Install Dependencies
|
||||||
uses: actions/download-artifact@v6
|
# uses: ./.github/actions/apt-install-deps
|
||||||
with:
|
# - name: Restore Test Artifact
|
||||||
name: ${{ github.sha }}-tests
|
# uses: actions/download-artifact@v6
|
||||||
- uses: lukka/get-cmake@latest
|
# with:
|
||||||
with:
|
# name: ${{ github.sha }}-tests
|
||||||
cmakeVersion: "~3.28.0" # use most recent 3.28.x version
|
# - uses: lukka/get-cmake@latest
|
||||||
- name: Unpackage and Run Unit Tests
|
# with:
|
||||||
timeout-minutes: 20
|
# cmakeVersion: "~3.28.0" # use most recent 3.28.x version
|
||||||
run: |
|
# - name: Unpackage and Run Unit Tests
|
||||||
tar -xvf build_tests.tar
|
# timeout-minutes: 20
|
||||||
scripts/run_unit_tests.sh
|
# run: |
|
||||||
- name: Upload Test Logs
|
# tar -xvf build_tests.tar
|
||||||
uses: actions/upload-artifact@v5
|
# scripts/run_unit_tests.sh
|
||||||
if: ${{ failure() }}
|
# - name: Upload Test Logs
|
||||||
with:
|
# uses: actions/upload-artifact@v5
|
||||||
name: unit-test-logs
|
# if: ${{ failure() }}
|
||||||
path: build/tests/**/*.log
|
# with:
|
||||||
- name: Publish Test Results
|
# name: unit-test-logs
|
||||||
if: always()
|
# path: build/tests/**/*.log
|
||||||
uses: EnricoMi/publish-unit-test-result-action/linux@v2
|
# - name: Publish Test Results
|
||||||
with:
|
# if: always()
|
||||||
files: "ctest_results.xml"
|
# uses: EnricoMi/publish-unit-test-result-action/linux@v2
|
||||||
flatpak:
|
# with:
|
||||||
name: "Flatpak"
|
# files: "ctest_results.xml"
|
||||||
container:
|
|
||||||
image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-48
|
# TODO: Re-enable after auto-update testing is complete
|
||||||
options: --privileged
|
# flatpak:
|
||||||
volumes:
|
# name: "Flatpak"
|
||||||
- /usr/local/lib/android:/usr/local/lib/android
|
# container:
|
||||||
- /usr/share/dotnet:/usr/share/dotnet
|
# image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-48
|
||||||
- /opt/ghc:/opt/ghc1
|
# options: --privileged
|
||||||
- /usr/local/share/boost:/usr/local/share/boost1
|
# volumes:
|
||||||
- /opt/hostedtoolcache:/opt/hostedtoolcache1
|
# - /usr/local/lib/android:/usr/local/lib/android
|
||||||
strategy:
|
# - /usr/share/dotnet:/usr/share/dotnet
|
||||||
fail-fast: false
|
# - /opt/ghc:/opt/ghc1
|
||||||
matrix:
|
# - /usr/local/share/boost:/usr/local/share/boost1
|
||||||
variant:
|
# - /opt/hostedtoolcache:/opt/hostedtoolcache1
|
||||||
- arch: x86_64
|
# strategy:
|
||||||
runner: ubuntu-24.04
|
# fail-fast: false
|
||||||
- arch: aarch64
|
# matrix:
|
||||||
runner: ubuntu-24.04-arm
|
# variant:
|
||||||
# Don't run scheduled builds on forks:
|
# - arch: x86_64
|
||||||
if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
# runner: ubuntu-24.04
|
||||||
runs-on: ${{ matrix.variant.runner }}
|
# - arch: aarch64
|
||||||
env:
|
# runner: ubuntu-24.04-arm
|
||||||
date:
|
# # Don't run scheduled builds on forks:
|
||||||
ver:
|
# if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }}
|
||||||
ver_pure:
|
# runs-on: ${{ matrix.variant.runner }}
|
||||||
steps:
|
# env:
|
||||||
- name: "Remove unneeded stuff to free disk space"
|
# date:
|
||||||
run:
|
# ver:
|
||||||
rm -rf /usr/local/lib/android/* /usr/share/dotnet/* /opt/ghc1/* "/usr/local/share/boost1/*" /opt/hostedtoolcache1/*
|
# ver_pure:
|
||||||
- uses: actions/checkout@v6
|
# steps:
|
||||||
- name: Get the version and date
|
# - name: "Remove unneeded stuff to free disk space"
|
||||||
run: |
|
# run:
|
||||||
ver_pure=$(grep 'set(SoftFever_VERSION' version.inc | cut -d '"' -f2)
|
# rm -rf /usr/local/lib/android/* /usr/share/dotnet/* /opt/ghc1/* "/usr/local/share/boost1/*" /opt/hostedtoolcache1/*
|
||||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
# - uses: actions/checkout@v6
|
||||||
ver="PR-${{ github.event.number }}"
|
# - name: Get the version and date
|
||||||
git_commit_hash="${{ github.event.pull_request.head.sha }}"
|
# run: |
|
||||||
else
|
# ver_pure=$(grep 'set(SoftFever_VERSION' version.inc | cut -d '"' -f2)
|
||||||
ver=V$ver_pure
|
# if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||||
git_commit_hash=""
|
# ver="PR-${{ github.event.number }}"
|
||||||
fi
|
# git_commit_hash="${{ github.event.pull_request.head.sha }}"
|
||||||
echo "ver=$ver" >> $GITHUB_ENV
|
# else
|
||||||
echo "ver_pure=$ver_pure" >> $GITHUB_ENV
|
# ver=V$ver_pure
|
||||||
echo "date=$(date +'%Y%m%d')" >> $GITHUB_ENV
|
# git_commit_hash=""
|
||||||
echo "git_commit_hash=$git_commit_hash" >> $GITHUB_ENV
|
# fi
|
||||||
shell: bash
|
# echo "ver=$ver" >> $GITHUB_ENV
|
||||||
- uses: flatpak/flatpak-github-actions/flatpak-builder@master
|
# echo "ver_pure=$ver_pure" >> $GITHUB_ENV
|
||||||
with:
|
# echo "date=$(date +'%Y%m%d')" >> $GITHUB_ENV
|
||||||
bundle: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
# echo "git_commit_hash=$git_commit_hash" >> $GITHUB_ENV
|
||||||
manifest-path: scripts/flatpak/io.github.softfever.OrcaSlicer.yml
|
# shell: bash
|
||||||
cache: true
|
# - uses: flatpak/flatpak-github-actions/flatpak-builder@master
|
||||||
arch: ${{ matrix.variant.arch }}
|
# with:
|
||||||
upload-artifact: false
|
# bundle: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
||||||
- name: Upload artifacts Flatpak
|
# manifest-path: scripts/flatpak/io.github.softfever.OrcaSlicer.yml
|
||||||
uses: actions/upload-artifact@v5
|
# cache: true
|
||||||
with:
|
# arch: ${{ matrix.variant.arch }}
|
||||||
name: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
# upload-artifact: false
|
||||||
path: '/__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak'
|
# - name: Upload artifacts Flatpak
|
||||||
- name: Deploy Flatpak to nightly release
|
# uses: actions/upload-artifact@v5
|
||||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main'
|
# with:
|
||||||
uses: WebFreak001/deploy-nightly@v3.2.0
|
# name: OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
||||||
with:
|
# path: '/__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak'
|
||||||
upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
# - name: Deploy Flatpak to nightly release
|
||||||
release_id: 137995723
|
# if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main'
|
||||||
asset_path: /__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
# uses: WebFreak001/deploy-nightly@v3.2.0
|
||||||
asset_name: OrcaSlicer-Linux-flatpak_nightly_${{ matrix.variant.arch }}.flatpak
|
# with:
|
||||||
asset_content_type: application/octet-stream
|
# upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label}
|
||||||
max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
# release_id: 137995723
|
||||||
|
# asset_path: /__w/OrcaSlicer/OrcaSlicer/OrcaSlicer-Linux-flatpak_${{ env.ver }}_${{ matrix.variant.arch }}.flatpak
|
||||||
|
# asset_name: OrcaSlicer-Linux-flatpak_nightly_${{ matrix.variant.arch }}.flatpak
|
||||||
|
# asset_content_type: application/octet-stream
|
||||||
|
# max_releases: 1 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted
|
||||||
|
|||||||
109
.github/workflows/build_orca.yml
vendored
109
.github/workflows/build_orca.yml
vendored
@@ -103,11 +103,13 @@ jobs:
|
|||||||
if: inputs.os == 'macos-14'
|
if: inputs.os == 'macos-14'
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: |
|
run: |
|
||||||
./build_release_macos.sh -s -n -x -a universal -t 10.15 -1
|
# TODO: Change back to -a universal after auto-update testing is complete
|
||||||
|
./build_release_macos.sh -s -n -x -a arm64 -t 10.15 -1
|
||||||
|
|
||||||
# Thanks to RaySajuuk, it's working now
|
# Thanks to RaySajuuk, it's working now
|
||||||
- name: Sign app and notary
|
- name: Sign app and notary
|
||||||
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && inputs.os == 'macos-14'
|
# TODO: Remove feature/auto-update after testing is complete
|
||||||
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/') || github.ref == 'refs/heads/feature/auto-update') && inputs.os == 'macos-14'
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
env:
|
env:
|
||||||
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
||||||
@@ -124,27 +126,28 @@ jobs:
|
|||||||
security import $CERTIFICATE_PATH -P $P12_PASSWORD -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
security import $CERTIFICATE_PATH -P $P12_PASSWORD -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $P12_PASSWORD $KEYCHAIN_PATH
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $P12_PASSWORD $KEYCHAIN_PATH
|
||||||
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer.app
|
# TODO: Change build/arm64 back to build/universal after auto-update testing is complete
|
||||||
|
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" ${{ github.workspace }}/build/arm64/OrcaSlicer/OrcaSlicer.app
|
||||||
# Sign OrcaSlicer_profile_validator.app if it exists
|
# Sign OrcaSlicer_profile_validator.app if it exists
|
||||||
if [ -f "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
if [ -f "${{ github.workspace }}/build/arm64/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
||||||
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app
|
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" ${{ github.workspace }}/build/arm64/OrcaSlicer/OrcaSlicer_profile_validator.app
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create main OrcaSlicer DMG without the profile validator helper
|
# Create main OrcaSlicer DMG without the profile validator helper
|
||||||
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_dmg
|
mkdir -p ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg
|
||||||
rm -rf ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/*
|
rm -rf ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg/*
|
||||||
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer.app ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/
|
cp -R ${{ github.workspace }}/build/arm64/OrcaSlicer/OrcaSlicer.app ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg/
|
||||||
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/Applications
|
ln -sfn /Applications ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg/Applications
|
||||||
hdiutil create -volname "OrcaSlicer" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_dmg -ov -format UDZO OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
hdiutil create -volname "OrcaSlicer" -srcfolder ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg -ov -format UDZO OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||||
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||||
|
|
||||||
# Create separate OrcaSlicer_profile_validator DMG if the app exists
|
# Create separate OrcaSlicer_profile_validator DMG if the app exists
|
||||||
if [ -f "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
if [ -f "${{ github.workspace }}/build/arm64/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
||||||
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg
|
mkdir -p ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg
|
||||||
rm -rf ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/*
|
rm -rf ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg/*
|
||||||
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/
|
cp -R ${{ github.workspace }}/build/arm64/OrcaSlicer/OrcaSlicer_profile_validator.app ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg/
|
||||||
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/Applications
|
ln -sfn /Applications ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg/Applications
|
||||||
hdiutil create -volname "OrcaSlicer Profile Validator" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg -ov -format UDZO OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
hdiutil create -volname "OrcaSlicer Profile Validator" -srcfolder ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg -ov -format UDZO OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||||
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
codesign --deep --force --verbose --options runtime --timestamp --entitlements ${{ github.workspace }}/scripts/disable_validation.entitlements --sign "$CERTIFICATE_ID" OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -159,23 +162,65 @@ jobs:
|
|||||||
xcrun stapler staple OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
xcrun stapler staple OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Sign DMG for Sparkle auto-update
|
||||||
|
# TODO: Remove feature/auto-update after testing is complete
|
||||||
|
if: github.repository == 'OrcaSlicer/OrcaSlicer' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/') || github.ref == 'refs/heads/feature/auto-update') && inputs.os == 'macos-14'
|
||||||
|
working-directory: ${{ github.workspace }}
|
||||||
|
env:
|
||||||
|
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
|
||||||
|
run: |
|
||||||
|
# Get the Sparkle sign_update tool from deps (installed to OrcaSlicer_dep/bin)
|
||||||
|
SIGN_UPDATE="${{ github.workspace }}/deps/build/arm64/OrcaSlicer_dep/bin/sign_update"
|
||||||
|
|
||||||
|
# Fallback to x86_64 if arm64 not found
|
||||||
|
if [ ! -f "$SIGN_UPDATE" ]; then
|
||||||
|
SIGN_UPDATE="${{ github.workspace }}/deps/build/x86_64/OrcaSlicer_dep/bin/sign_update"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$SIGN_UPDATE" ] && [ -n "$SPARKLE_PRIVATE_KEY" ]; then
|
||||||
|
# Write the private key to a temp file
|
||||||
|
echo "$SPARKLE_PRIVATE_KEY" > /tmp/sparkle_private_key
|
||||||
|
chmod 600 /tmp/sparkle_private_key
|
||||||
|
|
||||||
|
# Sign the DMG and capture the signature
|
||||||
|
SIGNATURE=$("$SIGN_UPDATE" "OrcaSlicer_Mac_universal_${{ env.ver }}.dmg" -f /tmp/sparkle_private_key)
|
||||||
|
|
||||||
|
# Clean up the key file
|
||||||
|
rm -f /tmp/sparkle_private_key
|
||||||
|
|
||||||
|
# Save signature to a file for later use in appcast generation
|
||||||
|
echo "$SIGNATURE" > OrcaSlicer_Mac_universal_${{ env.ver }}.dmg.sig
|
||||||
|
echo "Sparkle signature generated: $SIGNATURE"
|
||||||
|
|
||||||
|
# Also output as GitHub Actions output
|
||||||
|
echo "sparkle_signature=$SIGNATURE" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "Warning: Sparkle sign_update tool not found at $SIGN_UPDATE or private key not set, skipping signature generation"
|
||||||
|
if [ ! -f "$SIGN_UPDATE" ]; then
|
||||||
|
echo "sign_update not found. Available files:"
|
||||||
|
ls -la "${{ github.workspace }}/deps/build/arm64/OrcaSlicer_dep/" || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Create DMG without notary
|
- name: Create DMG without notary
|
||||||
if: github.ref != 'refs/heads/main' && inputs.os == 'macos-14'
|
# TODO: Remove feature/auto-update exclusion after testing is complete
|
||||||
|
if: github.ref != 'refs/heads/main' && github.ref != 'refs/heads/feature/auto-update' && !startsWith(github.ref, 'refs/heads/release/') && inputs.os == 'macos-14'
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_dmg
|
# TODO: Change build/arm64 back to build/universal after auto-update testing is complete
|
||||||
rm -rf ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/*
|
mkdir -p ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg
|
||||||
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer.app ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/
|
rm -rf ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg/*
|
||||||
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_dmg/Applications
|
cp -R ${{ github.workspace }}/build/arm64/OrcaSlicer/OrcaSlicer.app ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg/
|
||||||
hdiutil create -volname "OrcaSlicer" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_dmg -ov -format UDZO OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
ln -sfn /Applications ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg/Applications
|
||||||
|
hdiutil create -volname "OrcaSlicer" -srcfolder ${{ github.workspace }}/build/arm64/OrcaSlicer_dmg -ov -format UDZO OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||||
|
|
||||||
# Create separate OrcaSlicer_profile_validator DMG if the app exists
|
# Create separate OrcaSlicer_profile_validator DMG if the app exists
|
||||||
if [ -f "${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
if [ -f "${{ github.workspace }}/build/arm64/OrcaSlicer/OrcaSlicer_profile_validator.app/Contents/MacOS/OrcaSlicer_profile_validator" ]; then
|
||||||
mkdir -p ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg
|
mkdir -p ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg
|
||||||
rm -rf ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/*
|
rm -rf ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg/*
|
||||||
cp -R ${{ github.workspace }}/build/universal/OrcaSlicer/OrcaSlicer_profile_validator.app ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/
|
cp -R ${{ github.workspace }}/build/arm64/OrcaSlicer/OrcaSlicer_profile_validator.app ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg/
|
||||||
ln -sfn /Applications ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg/Applications
|
ln -sfn /Applications ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg/Applications
|
||||||
hdiutil create -volname "OrcaSlicer Profile Validator" -srcfolder ${{ github.workspace }}/build/universal/OrcaSlicer_profile_validator_dmg -ov -format UDZO OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
hdiutil create -volname "OrcaSlicer Profile Validator" -srcfolder ${{ github.workspace }}/build/arm64/OrcaSlicer_profile_validator_dmg -ov -format UDZO OrcaSlicer_profile_validator_Mac_universal_${{ env.ver }}.dmg
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload artifacts mac
|
- name: Upload artifacts mac
|
||||||
@@ -185,6 +230,14 @@ jobs:
|
|||||||
name: OrcaSlicer_Mac_universal_${{ env.ver }}
|
name: OrcaSlicer_Mac_universal_${{ env.ver }}
|
||||||
path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg
|
||||||
|
|
||||||
|
- name: Upload Sparkle signature mac
|
||||||
|
if: inputs.os == 'macos-14'
|
||||||
|
uses: actions/upload-artifact@v5
|
||||||
|
with:
|
||||||
|
name: OrcaSlicer_Mac_universal_${{ env.ver }}_sig
|
||||||
|
path: ${{ github.workspace }}/OrcaSlicer_Mac_universal_${{ env.ver }}.dmg.sig
|
||||||
|
if-no-files-found: ignore
|
||||||
|
|
||||||
- name: Upload OrcaSlicer_profile_validator DMG mac
|
- name: Upload OrcaSlicer_profile_validator DMG mac
|
||||||
if: inputs.os == 'macos-14'
|
if: inputs.os == 'macos-14'
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v5
|
||||||
|
|||||||
138
.github/workflows/generate_appcast.yml
vendored
Normal file
138
.github/workflows/generate_appcast.yml
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
name: Generate Appcast
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version to generate appcast for (e.g., 2.3.2)'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
generate_appcast:
|
||||||
|
name: Generate and Deploy Appcast
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: Get version from release or input
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" == "release" ]; then
|
||||||
|
VERSION="${{ github.event.release.tag_name }}"
|
||||||
|
VERSION="${VERSION#v}" # Remove 'v' prefix if present
|
||||||
|
else
|
||||||
|
VERSION="${{ github.event.inputs.version }}"
|
||||||
|
fi
|
||||||
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
echo "Version: $VERSION"
|
||||||
|
|
||||||
|
- name: Download release assets info
|
||||||
|
id: assets
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
TAG="v$VERSION"
|
||||||
|
|
||||||
|
# Get release info
|
||||||
|
RELEASE_URL="https://github.com/${{ github.repository }}/releases/tag/$TAG"
|
||||||
|
echo "release_url=$RELEASE_URL" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Get macOS DMG URL and size
|
||||||
|
# Use browser_download_url for public access (not .url which is the API endpoint)
|
||||||
|
MAC_ASSET=$(gh release view "$TAG" --json assets -q '.assets[] | select(.name | contains("Mac_universal")) | select(.name | endswith(".dmg"))')
|
||||||
|
if [ -n "$MAC_ASSET" ]; then
|
||||||
|
MAC_URL=$(echo "$MAC_ASSET" | jq -r '.browser_download_url // .url')
|
||||||
|
MAC_SIZE=$(echo "$MAC_ASSET" | jq -r '.size')
|
||||||
|
echo "mac_url=$MAC_URL" >> $GITHUB_OUTPUT
|
||||||
|
echo "mac_size=$MAC_SIZE" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get Windows installer URL and size
|
||||||
|
# Use browser_download_url for public access (not .url which is the API endpoint)
|
||||||
|
WIN_ASSET=$(gh release view "$TAG" --json assets -q '.assets[] | select(.name | contains("Windows_Installer")) | select(.name | endswith(".exe"))')
|
||||||
|
if [ -n "$WIN_ASSET" ]; then
|
||||||
|
WIN_URL=$(echo "$WIN_ASSET" | jq -r '.browser_download_url // .url')
|
||||||
|
WIN_SIZE=$(echo "$WIN_ASSET" | jq -r '.size')
|
||||||
|
echo "win_url=$WIN_URL" >> $GITHUB_OUTPUT
|
||||||
|
echo "win_size=$WIN_SIZE" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Download signatures
|
||||||
|
id: signatures
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
TAG="v$VERSION"
|
||||||
|
|
||||||
|
# Try to download macOS signature artifact
|
||||||
|
MAC_SIG_ARTIFACT="OrcaSlicer_Mac_universal_V${VERSION}_sig"
|
||||||
|
if gh run download --name "$MAC_SIG_ARTIFACT" -D /tmp/mac_sig 2>/dev/null; then
|
||||||
|
MAC_SIG=$(cat /tmp/mac_sig/*.sig)
|
||||||
|
echo "mac_signature=$MAC_SIG" >> $GITHUB_OUTPUT
|
||||||
|
echo "Found macOS signature: $MAC_SIG"
|
||||||
|
else
|
||||||
|
echo "No macOS signature artifact found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Windows, signature would come from WinSparkle signing (if implemented)
|
||||||
|
# echo "win_signature=$WIN_SIG" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Generate appcast.xml
|
||||||
|
run: |
|
||||||
|
python scripts/generate_appcast.py \
|
||||||
|
--version "${{ steps.version.outputs.version }}" \
|
||||||
|
--release-notes-url "${{ steps.assets.outputs.release_url }}" \
|
||||||
|
--mac-url "${{ steps.assets.outputs.mac_url }}" \
|
||||||
|
--mac-signature "${{ steps.signatures.outputs.mac_signature }}" \
|
||||||
|
--mac-length "${{ steps.assets.outputs.mac_size }}" \
|
||||||
|
--output appcast.xml
|
||||||
|
|
||||||
|
echo "Generated appcast.xml:"
|
||||||
|
cat appcast.xml
|
||||||
|
|
||||||
|
- name: Upload appcast artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: appcast
|
||||||
|
path: appcast.xml
|
||||||
|
|
||||||
|
# Deploy to Cloudflare KV (for check-version.orcaslicer.com Worker)
|
||||||
|
- name: Deploy appcast to Cloudflare KV
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
env:
|
||||||
|
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
||||||
|
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
||||||
|
KV_NAMESPACE_ID: ${{ secrets.CF_KV_NAMESPACE_ID }}
|
||||||
|
run: |
|
||||||
|
if [ -n "$CF_API_TOKEN" ] && [ -n "$CF_ACCOUNT_ID" ] && [ -n "$KV_NAMESPACE_ID" ]; then
|
||||||
|
# Deploy appcast.xml
|
||||||
|
curl -X PUT \
|
||||||
|
"https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/storage/kv/namespaces/$KV_NAMESPACE_ID/values/appcast.xml" \
|
||||||
|
-H "Authorization: Bearer $CF_API_TOKEN" \
|
||||||
|
-H "Content-Type: text/plain" \
|
||||||
|
--data-binary @appcast.xml
|
||||||
|
echo "Appcast deployed to Cloudflare KV"
|
||||||
|
|
||||||
|
# Deploy macOS signature file (for verification/auditing)
|
||||||
|
if [ -n "${{ steps.signatures.outputs.mac_signature }}" ]; then
|
||||||
|
echo "${{ steps.signatures.outputs.mac_signature }}" > mac_signature.txt
|
||||||
|
curl -X PUT \
|
||||||
|
"https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/storage/kv/namespaces/$KV_NAMESPACE_ID/values/signatures/${{ steps.version.outputs.version }}/mac.sig" \
|
||||||
|
-H "Authorization: Bearer $CF_API_TOKEN" \
|
||||||
|
-H "Content-Type: text/plain" \
|
||||||
|
--data-binary @mac_signature.txt
|
||||||
|
echo "macOS signature deployed to Cloudflare KV"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Cloudflare credentials not configured, skipping deployment"
|
||||||
|
fi
|
||||||
@@ -811,6 +811,11 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
|||||||
${TOP_LEVEL_PROJECT_DIR}/deps/WebView2/lib/win-${_arch}/WebView2Loader.dll
|
${TOP_LEVEL_PROJECT_DIR}/deps/WebView2/lib/win-${_arch}/WebView2Loader.dll
|
||||||
DESTINATION ${_out_dir})
|
DESTINATION ${_out_dir})
|
||||||
|
|
||||||
|
# WinSparkle for auto-updates
|
||||||
|
if(EXISTS "${CMAKE_PREFIX_PATH}/bin/WinSparkle.dll")
|
||||||
|
file(COPY ${CMAKE_PREFIX_PATH}/bin/WinSparkle.dll DESTINATION ${_out_dir})
|
||||||
|
endif()
|
||||||
|
|
||||||
file(COPY ${CMAKE_PREFIX_PATH}/bin/occt/TKBO.dll
|
file(COPY ${CMAKE_PREFIX_PATH}/bin/occt/TKBO.dll
|
||||||
${CMAKE_PREFIX_PATH}/bin/occt/TKBRep.dll
|
${CMAKE_PREFIX_PATH}/bin/occt/TKBRep.dll
|
||||||
${CMAKE_PREFIX_PATH}/bin/occt/TKCAF.dll
|
${CMAKE_PREFIX_PATH}/bin/occt/TKCAF.dll
|
||||||
|
|||||||
17
deps/CMakeLists.txt
vendored
17
deps/CMakeLists.txt
vendored
@@ -386,6 +386,16 @@ endif ()
|
|||||||
include(OCCT/OCCT.cmake)
|
include(OCCT/OCCT.cmake)
|
||||||
include(OpenCV/OpenCV.cmake)
|
include(OpenCV/OpenCV.cmake)
|
||||||
|
|
||||||
|
# WinSparkle for Windows auto-updates
|
||||||
|
if(WIN32)
|
||||||
|
include(WinSparkle/WinSparkle.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Sparkle 2 for macOS auto-updates
|
||||||
|
if(APPLE)
|
||||||
|
include(Sparkle/Sparkle.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(_dep_list
|
set(_dep_list
|
||||||
dep_Boost
|
dep_Boost
|
||||||
dep_TBB
|
dep_TBB
|
||||||
@@ -410,12 +420,19 @@ set(_dep_list
|
|||||||
if (MSVC)
|
if (MSVC)
|
||||||
# Experimental
|
# Experimental
|
||||||
#list(APPEND _dep_list "dep_qhull")
|
#list(APPEND _dep_list "dep_qhull")
|
||||||
|
# WinSparkle for auto-updates
|
||||||
|
list(APPEND _dep_list "dep_WinSparkle")
|
||||||
else()
|
else()
|
||||||
list(APPEND _dep_list "dep_Qhull")
|
list(APPEND _dep_list "dep_Qhull")
|
||||||
# Not working, static build has different Eigen
|
# Not working, static build has different Eigen
|
||||||
#list(APPEND _dep_list "dep_libigl")
|
#list(APPEND _dep_list "dep_libigl")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
# Sparkle 2 for auto-updates
|
||||||
|
list(APPEND _dep_list "dep_Sparkle")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_custom_target(deps ALL DEPENDS ${_dep_list})
|
add_custom_target(deps ALL DEPENDS ${_dep_list})
|
||||||
|
|
||||||
# Note: I'm not using any of the LOG_xxx options in ExternalProject_Add() commands
|
# Note: I'm not using any of the LOG_xxx options in ExternalProject_Add() commands
|
||||||
|
|||||||
27
deps/Sparkle/Sparkle.cmake
vendored
Normal file
27
deps/Sparkle/Sparkle.cmake
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Sparkle 2 - Auto-update framework for macOS
|
||||||
|
# https://sparkle-project.org/
|
||||||
|
# https://github.com/sparkle-project/Sparkle
|
||||||
|
#
|
||||||
|
# Sparkle is distributed as a pre-built framework, so we just download and extract.
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(SPARKLE_VERSION "2.8.1")
|
||||||
|
|
||||||
|
ExternalProject_Add(
|
||||||
|
dep_Sparkle
|
||||||
|
EXCLUDE_FROM_ALL ON
|
||||||
|
URL "https://github.com/sparkle-project/Sparkle/releases/download/${SPARKLE_VERSION}/Sparkle-${SPARKLE_VERSION}.tar.xz"
|
||||||
|
URL_HASH SHA256=5cddb7695674ef7704268f38eccaee80e3accbf19e61c1689efff5b6116d85be
|
||||||
|
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/Sparkle
|
||||||
|
# No build step needed - just install pre-built framework and tools
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DESTDIR}/Frameworks
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
<SOURCE_DIR>/Sparkle.framework ${DESTDIR}/Frameworks/Sparkle.framework
|
||||||
|
# Also install the Sparkle CLI tools (sign_update, generate_appcast) for CI/CD signing
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${DESTDIR}/bin
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/bin/sign_update ${DESTDIR}/bin/sign_update
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/bin/generate_appcast ${DESTDIR}/bin/generate_appcast
|
||||||
|
)
|
||||||
|
endif()
|
||||||
33
deps/WinSparkle/WinSparkle.cmake
vendored
Normal file
33
deps/WinSparkle/WinSparkle.cmake
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# WinSparkle - Auto-update framework for Windows
|
||||||
|
# https://winsparkle.org/
|
||||||
|
# https://github.com/vslavik/winsparkle
|
||||||
|
#
|
||||||
|
# WinSparkle is distributed as pre-built binaries, so we just download and extract.
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(WINSPARKLE_VERSION "0.8.3")
|
||||||
|
|
||||||
|
# Determine architecture
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(WINSPARKLE_ARCH "x64")
|
||||||
|
else()
|
||||||
|
set(WINSPARKLE_ARCH "x86")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
ExternalProject_Add(
|
||||||
|
dep_WinSparkle
|
||||||
|
EXCLUDE_FROM_ALL ON
|
||||||
|
URL "https://github.com/vslavik/winsparkle/releases/download/v${WINSPARKLE_VERSION}/WinSparkle-${WINSPARKLE_VERSION}.zip"
|
||||||
|
URL_HASH SHA256=5ff4a4604c78d57e01d83e22f79f5ffea0c4969defd48b45c69ccbd6b1a71e94
|
||||||
|
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/WinSparkle
|
||||||
|
# No build step needed - just install pre-built binaries
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
<SOURCE_DIR>/include ${DESTDIR}/include
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
<SOURCE_DIR>/${WINSPARKLE_ARCH}/Release/WinSparkle.dll ${DESTDIR}/bin/WinSparkle.dll
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
<SOURCE_DIR>/${WINSPARKLE_ARCH}/Release/WinSparkle.lib ${DESTDIR}/lib/WinSparkle.lib
|
||||||
|
)
|
||||||
|
endif()
|
||||||
208
scripts/generate_appcast.py
Executable file
208
scripts/generate_appcast.py
Executable file
@@ -0,0 +1,208 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Generate appcast.xml for Sparkle/WinSparkle auto-updates.
|
||||||
|
|
||||||
|
This script generates an appcast XML file that can be used by both
|
||||||
|
Sparkle (macOS) and WinSparkle (Windows) for auto-update functionality.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python generate_appcast.py --version 2.1.0 \
|
||||||
|
--win-url https://github.com/.../OrcaSlicer_Windows.exe \
|
||||||
|
--win-signature "BASE64_SIGNATURE" \
|
||||||
|
--win-length 150000000 \
|
||||||
|
--mac-url https://github.com/.../OrcaSlicer_Mac.dmg \
|
||||||
|
--mac-signature "BASE64_SIGNATURE" \
|
||||||
|
--mac-length 200000000 \
|
||||||
|
--release-notes-url https://github.com/.../releases/tag/v2.1.0 \
|
||||||
|
--output appcast.xml
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from xml.etree import ElementTree as ET
|
||||||
|
from xml.dom import minidom
|
||||||
|
|
||||||
|
|
||||||
|
SPARKLE_NS = "http://www.andymatuschak.org/xml-namespaces/sparkle"
|
||||||
|
DC_NS = "http://purl.org/dc/elements/1.1/"
|
||||||
|
|
||||||
|
|
||||||
|
def create_appcast(
|
||||||
|
version: str,
|
||||||
|
release_notes_url: str,
|
||||||
|
win_url: str = None,
|
||||||
|
win_signature: str = None,
|
||||||
|
win_length: int = None,
|
||||||
|
mac_url: str = None,
|
||||||
|
mac_signature: str = None,
|
||||||
|
mac_length: int = None,
|
||||||
|
title: str = "OrcaSlicer Updates",
|
||||||
|
description: str = "Most recent updates to OrcaSlicer",
|
||||||
|
link: str = "https://github.com/OrcaSlicer/OrcaSlicer",
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
Create an appcast XML string.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
version: Version string (e.g., "2.1.0")
|
||||||
|
release_notes_url: URL to release notes HTML page
|
||||||
|
win_url: Download URL for Windows installer
|
||||||
|
win_signature: EdDSA signature for Windows installer
|
||||||
|
win_length: File size in bytes for Windows installer
|
||||||
|
mac_url: Download URL for macOS DMG
|
||||||
|
mac_signature: EdDSA signature for macOS DMG
|
||||||
|
mac_length: File size in bytes for macOS DMG
|
||||||
|
title: Feed title
|
||||||
|
description: Feed description
|
||||||
|
link: Link to project homepage
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
XML string of the appcast
|
||||||
|
"""
|
||||||
|
# Register namespaces
|
||||||
|
ET.register_namespace("sparkle", SPARKLE_NS)
|
||||||
|
ET.register_namespace("dc", DC_NS)
|
||||||
|
|
||||||
|
# Create root RSS element
|
||||||
|
rss = ET.Element("rss")
|
||||||
|
rss.set("version", "2.0")
|
||||||
|
rss.set(f"xmlns:sparkle", SPARKLE_NS)
|
||||||
|
rss.set(f"xmlns:dc", DC_NS)
|
||||||
|
|
||||||
|
# Create channel
|
||||||
|
channel = ET.SubElement(rss, "channel")
|
||||||
|
ET.SubElement(channel, "title").text = title
|
||||||
|
ET.SubElement(channel, "link").text = link
|
||||||
|
ET.SubElement(channel, "description").text = description
|
||||||
|
ET.SubElement(channel, "language").text = "en"
|
||||||
|
|
||||||
|
# Create item for this release
|
||||||
|
item = ET.SubElement(channel, "item")
|
||||||
|
ET.SubElement(item, "title").text = f"Version {version}"
|
||||||
|
|
||||||
|
# Publication date in RFC 2822 format
|
||||||
|
pub_date = datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S +0000")
|
||||||
|
ET.SubElement(item, "pubDate").text = pub_date
|
||||||
|
|
||||||
|
# Release notes link
|
||||||
|
release_notes = ET.SubElement(item, f"{{{SPARKLE_NS}}}releaseNotesLink")
|
||||||
|
release_notes.text = release_notes_url
|
||||||
|
|
||||||
|
# Windows enclosure
|
||||||
|
if win_url and win_signature:
|
||||||
|
win_enclosure = ET.SubElement(item, "enclosure")
|
||||||
|
win_enclosure.set("url", win_url)
|
||||||
|
win_enclosure.set(f"{{{SPARKLE_NS}}}version", version)
|
||||||
|
win_enclosure.set(f"{{{SPARKLE_NS}}}os", "windows")
|
||||||
|
win_enclosure.set(f"{{{SPARKLE_NS}}}edSignature", win_signature)
|
||||||
|
if win_length:
|
||||||
|
win_enclosure.set("length", str(win_length))
|
||||||
|
win_enclosure.set("type", "application/octet-stream")
|
||||||
|
|
||||||
|
# macOS enclosure
|
||||||
|
if mac_url and mac_signature:
|
||||||
|
mac_enclosure = ET.SubElement(item, "enclosure")
|
||||||
|
mac_enclosure.set("url", mac_url)
|
||||||
|
mac_enclosure.set(f"{{{SPARKLE_NS}}}version", version)
|
||||||
|
mac_enclosure.set(f"{{{SPARKLE_NS}}}os", "macos")
|
||||||
|
mac_enclosure.set(f"{{{SPARKLE_NS}}}edSignature", mac_signature)
|
||||||
|
if mac_length:
|
||||||
|
mac_enclosure.set("length", str(mac_length))
|
||||||
|
mac_enclosure.set("type", "application/octet-stream")
|
||||||
|
|
||||||
|
# Convert to pretty-printed string
|
||||||
|
rough_string = ET.tostring(rss, encoding="unicode", method="xml")
|
||||||
|
reparsed = minidom.parseString(rough_string)
|
||||||
|
pretty_xml = reparsed.toprettyxml(indent=" ", encoding=None)
|
||||||
|
|
||||||
|
# Remove extra blank lines
|
||||||
|
lines = [line for line in pretty_xml.split("\n") if line.strip()]
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Generate appcast.xml for OrcaSlicer auto-updates",
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog=__doc__,
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--version", "-v", required=True, help="Version string (e.g., 2.1.0)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--release-notes-url",
|
||||||
|
"-r",
|
||||||
|
required=True,
|
||||||
|
help="URL to release notes page",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--win-url", help="Download URL for Windows installer"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--win-signature", help="EdDSA signature for Windows installer"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--win-length", type=int, help="File size in bytes for Windows installer"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--mac-url", help="Download URL for macOS DMG"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--mac-signature", help="EdDSA signature for macOS DMG"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--mac-length", type=int, help="File size in bytes for macOS DMG"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--output", "-o", default="appcast.xml", help="Output file path"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--title", default="OrcaSlicer Updates", help="Feed title"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--link",
|
||||||
|
default="https://github.com/OrcaSlicer/OrcaSlicer",
|
||||||
|
help="Project homepage URL",
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Validate that at least one platform is specified
|
||||||
|
has_windows = args.win_url and args.win_signature
|
||||||
|
has_macos = args.mac_url and args.mac_signature
|
||||||
|
|
||||||
|
if not has_windows and not has_macos:
|
||||||
|
print(
|
||||||
|
"Error: At least one platform (Windows or macOS) must have both URL and signature",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Generate appcast
|
||||||
|
xml_content = create_appcast(
|
||||||
|
version=args.version,
|
||||||
|
release_notes_url=args.release_notes_url,
|
||||||
|
win_url=args.win_url,
|
||||||
|
win_signature=args.win_signature,
|
||||||
|
win_length=args.win_length,
|
||||||
|
mac_url=args.mac_url,
|
||||||
|
mac_signature=args.mac_signature,
|
||||||
|
mac_length=args.mac_length,
|
||||||
|
title=args.title,
|
||||||
|
link=args.link,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write output
|
||||||
|
if args.output == "-":
|
||||||
|
print(xml_content)
|
||||||
|
else:
|
||||||
|
with open(args.output, "w", encoding="utf-8") as f:
|
||||||
|
f.write(xml_content)
|
||||||
|
print(f"Appcast written to: {args.output}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -131,6 +131,11 @@ if (APPLE)
|
|||||||
# add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE)
|
# add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE)
|
||||||
# -liconv: boost links to libiconv by default
|
# -liconv: boost links to libiconv by default
|
||||||
target_link_libraries(OrcaSlicer "-liconv -framework IOKit" "-framework CoreFoundation" "-framework AVFoundation" "-framework AVKit" "-framework CoreMedia" "-framework VideoToolbox" -lc++)
|
target_link_libraries(OrcaSlicer "-liconv -framework IOKit" "-framework CoreFoundation" "-framework AVFoundation" "-framework AVKit" "-framework CoreMedia" "-framework VideoToolbox" -lc++)
|
||||||
|
# Set rpath for embedded frameworks (Sparkle)
|
||||||
|
set_target_properties(OrcaSlicer PROPERTIES
|
||||||
|
INSTALL_RPATH "@executable_path/../Frameworks"
|
||||||
|
BUILD_WITH_INSTALL_RPATH TRUE
|
||||||
|
)
|
||||||
elseif (MSVC)
|
elseif (MSVC)
|
||||||
# Manifest is provided through OrcaSlicer.rc, don't generate your own.
|
# Manifest is provided through OrcaSlicer.rc, don't generate your own.
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
|
||||||
@@ -252,6 +257,24 @@ else ()
|
|||||||
COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${BIN_RESOURCES_DIR}"
|
COMMAND ln -sfn "${SLIC3R_RESOURCES_DIR}" "${BIN_RESOURCES_DIR}"
|
||||||
COMMENT "Symlinking the resources directory into the build tree"
|
COMMENT "Symlinking the resources directory into the build tree"
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
|
||||||
|
# Embed Sparkle framework for auto-updates
|
||||||
|
if (CMAKE_MACOSX_BUNDLE)
|
||||||
|
find_library(SPARKLE_FRAMEWORK Sparkle PATHS ${CMAKE_PREFIX_PATH}/Frameworks)
|
||||||
|
if(SPARKLE_FRAMEWORK)
|
||||||
|
if (CMAKE_CONFIGURATION_TYPES)
|
||||||
|
set(BUNDLE_FRAMEWORKS_DIR "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/OrcaSlicer.app/Contents/Frameworks")
|
||||||
|
else()
|
||||||
|
set(BUNDLE_FRAMEWORKS_DIR "${CMAKE_CURRENT_BINARY_DIR}/OrcaSlicer.app/Contents/Frameworks")
|
||||||
|
endif()
|
||||||
|
add_custom_command(TARGET OrcaSlicer POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${BUNDLE_FRAMEWORKS_DIR}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory "${SPARKLE_FRAMEWORK}" "${BUNDLE_FRAMEWORKS_DIR}/Sparkle.framework"
|
||||||
|
COMMENT "Embedding Sparkle.framework into app bundle"
|
||||||
|
VERBATIM)
|
||||||
|
message(STATUS "Sparkle framework will be embedded: ${SPARKLE_FRAMEWORK}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Slic3r binary install target. Default build type is release in case no CMAKE_BUILD_TYPE is provided.
|
# Slic3r binary install target. Default build type is release in case no CMAKE_BUILD_TYPE is provided.
|
||||||
|
|||||||
@@ -135,5 +135,14 @@
|
|||||||
<key>ASAN_OPTIONS</key>
|
<key>ASAN_OPTIONS</key>
|
||||||
<string>detect_container_overflow=0</string>
|
<string>detect_container_overflow=0</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<!-- Sparkle 2 Auto-Update Configuration -->
|
||||||
|
<key>SUFeedURL</key>
|
||||||
|
<string>https://check-version.orcaslicer.com/appcast.xml</string>
|
||||||
|
<key>SUPublicEDKey</key>
|
||||||
|
<string>eLFARgt9i0VZQR4FtXiTL6jdwjkGr2RMPjfYCCfBWeM=</string>
|
||||||
|
<key>SUEnableAutomaticChecks</key>
|
||||||
|
<true/>
|
||||||
|
<key>SUAllowsAutomaticUpdates</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -456,6 +456,8 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
GUI/UnsavedChangesDialog.hpp
|
GUI/UnsavedChangesDialog.hpp
|
||||||
GUI/UpdateDialogs.cpp
|
GUI/UpdateDialogs.cpp
|
||||||
GUI/UpdateDialogs.hpp
|
GUI/UpdateDialogs.hpp
|
||||||
|
GUI/UpdateManager.hpp
|
||||||
|
GUI/UpdateManager.cpp
|
||||||
GUI/UpgradePanel.cpp
|
GUI/UpgradePanel.cpp
|
||||||
GUI/UpgradePanel.hpp
|
GUI/UpgradePanel.hpp
|
||||||
GUI/UserManager.cpp
|
GUI/UserManager.cpp
|
||||||
@@ -648,6 +650,7 @@ if (APPLE)
|
|||||||
GUI/InstanceCheckMac.mm
|
GUI/InstanceCheckMac.mm
|
||||||
GUI/InstanceCheckMac.h
|
GUI/InstanceCheckMac.h
|
||||||
GUI/GUI_UtilsMac.mm
|
GUI/GUI_UtilsMac.mm
|
||||||
|
GUI/UpdateManagerMac.mm
|
||||||
GUI/wxMediaCtrl2.mm
|
GUI/wxMediaCtrl2.mm
|
||||||
GUI/wxMediaCtrl2.h
|
GUI/wxMediaCtrl2.h
|
||||||
)
|
)
|
||||||
@@ -672,11 +675,6 @@ string(REPLACE "\r" "" ORCA_UPDATER_SIG_KEY_B64 "${ORCA_UPDATER_SIG_KEY_B64}")
|
|||||||
string(REPLACE "\t" "" ORCA_UPDATER_SIG_KEY_B64 "${ORCA_UPDATER_SIG_KEY_B64}")
|
string(REPLACE "\t" "" ORCA_UPDATER_SIG_KEY_B64 "${ORCA_UPDATER_SIG_KEY_B64}")
|
||||||
string(REPLACE " " "" ORCA_UPDATER_SIG_KEY_B64 "${ORCA_UPDATER_SIG_KEY_B64}")
|
string(REPLACE " " "" ORCA_UPDATER_SIG_KEY_B64 "${ORCA_UPDATER_SIG_KEY_B64}")
|
||||||
|
|
||||||
set(ORCA_UPDATER_SIG_KEY_AVAILABLE 0)
|
|
||||||
if(ORCA_UPDATER_SIG_KEY_B64)
|
|
||||||
set(ORCA_UPDATER_SIG_KEY_AVAILABLE 1)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/GeneratedConfig.hpp.in
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/GeneratedConfig.hpp.in
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/GeneratedConfig.hpp
|
${CMAKE_CURRENT_BINARY_DIR}/GeneratedConfig.hpp
|
||||||
@ONLY)
|
@ONLY)
|
||||||
@@ -707,6 +705,16 @@ target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo mini
|
|||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
target_link_libraries(libslic3r_gui Setupapi.lib)
|
target_link_libraries(libslic3r_gui Setupapi.lib)
|
||||||
|
# WinSparkle for auto-updates
|
||||||
|
find_library(WINSPARKLE_LIB WinSparkle PATHS ${CMAKE_PREFIX_PATH}/lib)
|
||||||
|
if(WINSPARKLE_LIB)
|
||||||
|
target_link_libraries(libslic3r_gui ${WINSPARKLE_LIB})
|
||||||
|
target_include_directories(libslic3r_gui PRIVATE ${CMAKE_PREFIX_PATH}/include)
|
||||||
|
target_compile_definitions(libslic3r_gui PRIVATE ORCA_HAS_WINSPARKLE)
|
||||||
|
message(STATUS "WinSparkle found: ${WINSPARKLE_LIB}")
|
||||||
|
else()
|
||||||
|
message(STATUS "WinSparkle not found, auto-update disabled on Windows")
|
||||||
|
endif()
|
||||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server)
|
FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server)
|
||||||
FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl)
|
FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl)
|
||||||
@@ -722,6 +730,15 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|||||||
)
|
)
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY} "-framework Security")
|
target_link_libraries(libslic3r_gui ${DISKARBITRATION_LIBRARY} "-framework Security")
|
||||||
|
# Sparkle 2 for auto-updates
|
||||||
|
find_library(SPARKLE_FRAMEWORK Sparkle PATHS ${CMAKE_PREFIX_PATH}/Frameworks)
|
||||||
|
if(SPARKLE_FRAMEWORK)
|
||||||
|
target_link_libraries(libslic3r_gui ${SPARKLE_FRAMEWORK})
|
||||||
|
target_compile_definitions(libslic3r_gui PRIVATE ORCA_HAS_SPARKLE)
|
||||||
|
message(STATUS "Sparkle found: ${SPARKLE_FRAMEWORK}")
|
||||||
|
else()
|
||||||
|
message(STATUS "Sparkle not found, auto-update disabled on macOS")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (SLIC3R_STATIC)
|
if (SLIC3R_STATIC)
|
||||||
|
|||||||
@@ -91,6 +91,7 @@
|
|||||||
#include "Tab.hpp"
|
#include "Tab.hpp"
|
||||||
#include "SysInfoDialog.hpp"
|
#include "SysInfoDialog.hpp"
|
||||||
#include "UpdateDialogs.hpp"
|
#include "UpdateDialogs.hpp"
|
||||||
|
#include "UpdateManager.hpp"
|
||||||
#include "Mouse3DController.hpp"
|
#include "Mouse3DController.hpp"
|
||||||
#include "RemovableDriveManager.hpp"
|
#include "RemovableDriveManager.hpp"
|
||||||
#include "InstanceCheck.hpp"
|
#include "InstanceCheck.hpp"
|
||||||
@@ -984,6 +985,16 @@ void GUI_App::post_init()
|
|||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " sync_user_preset: false";
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " sync_user_preset: false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the auto-update manager
|
||||||
|
#if defined(ORCA_HAS_SPARKLE) || defined(ORCA_HAS_WINSPARKLE)
|
||||||
|
{
|
||||||
|
// Use the appcast URL for Sparkle/WinSparkle (different from version_check_url)
|
||||||
|
std::string appcast_url = "https://check-version.orcaslicer.com/appcast.xml";
|
||||||
|
UpdateManager::init(appcast_url, "");
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager initialized with appcast URL: " << appcast_url;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// The extra CallAfter() is needed because of Mac, where this is the only way
|
// The extra CallAfter() is needed because of Mac, where this is the only way
|
||||||
// to popup a modal dialog on start without screwing combo boxes.
|
// to popup a modal dialog on start without screwing combo boxes.
|
||||||
// This is ugly but I honestly found no better way to do it.
|
// This is ugly but I honestly found no better way to do it.
|
||||||
@@ -998,7 +1009,12 @@ void GUI_App::post_init()
|
|||||||
bool sys_preset = app_config->get("sync_system_preset") == "true";
|
bool sys_preset = app_config->get("sync_system_preset") == "true";
|
||||||
this->preset_updater->sync(http_url, language, network_ver, sys_preset ? preset_bundle : nullptr);
|
this->preset_updater->sync(http_url, language, network_ver, sys_preset ? preset_bundle : nullptr);
|
||||||
|
|
||||||
|
// Check for application updates
|
||||||
|
#if defined(ORCA_HAS_SPARKLE) || defined(ORCA_HAS_WINSPARKLE)
|
||||||
|
UpdateManager::check_for_updates_background();
|
||||||
|
#else
|
||||||
this->check_new_version_sf();
|
this->check_new_version_sf();
|
||||||
|
#endif
|
||||||
if (is_user_login() && !app_config->get_stealth_mode()) {
|
if (is_user_login() && !app_config->get_stealth_mode()) {
|
||||||
// this->check_privacy_version(0);
|
// this->check_privacy_version(0);
|
||||||
request_user_handle(0);
|
request_user_handle(0);
|
||||||
@@ -2240,6 +2256,11 @@ bool GUI_App::OnInit()
|
|||||||
|
|
||||||
int GUI_App::OnExit()
|
int GUI_App::OnExit()
|
||||||
{
|
{
|
||||||
|
// Shutdown the auto-update manager
|
||||||
|
#if defined(ORCA_HAS_SPARKLE) || defined(ORCA_HAS_WINSPARKLE)
|
||||||
|
UpdateManager::shutdown();
|
||||||
|
#endif
|
||||||
|
|
||||||
stop_sync_user_preset();
|
stop_sync_user_preset();
|
||||||
|
|
||||||
if (m_device_manager) {
|
if (m_device_manager) {
|
||||||
@@ -4630,7 +4651,7 @@ std::string base64url_encode(const unsigned char* data, std::size_t length)
|
|||||||
|
|
||||||
std::optional<std::vector<unsigned char>> load_signature_key()
|
std::optional<std::vector<unsigned char>> load_signature_key()
|
||||||
{
|
{
|
||||||
#if ORCA_UPDATER_SIG_KEY_AVAILABLE
|
#ifdef ORCA_UPDATER_SIG_KEY_B64
|
||||||
std::string key = ORCA_UPDATER_SIG_KEY_B64;
|
std::string key = ORCA_UPDATER_SIG_KEY_B64;
|
||||||
boost::algorithm::trim(key);
|
boost::algorithm::trim(key);
|
||||||
if (key.empty())
|
if (key.empty())
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
#include "MarkdownTip.hpp"
|
#include "MarkdownTip.hpp"
|
||||||
#include "NetworkTestDialog.hpp"
|
#include "NetworkTestDialog.hpp"
|
||||||
#include "ConfigWizard.hpp"
|
#include "ConfigWizard.hpp"
|
||||||
|
#include "UpdateManager.hpp"
|
||||||
#include "Widgets/WebView.hpp"
|
#include "Widgets/WebView.hpp"
|
||||||
#include "DailyTips.hpp"
|
#include "DailyTips.hpp"
|
||||||
#include "FilamentMapDialog.hpp"
|
#include "FilamentMapDialog.hpp"
|
||||||
@@ -2332,7 +2333,11 @@ static wxMenu* generate_help_menu()
|
|||||||
// Check New Version
|
// Check New Version
|
||||||
append_menu_item(helpMenu, wxID_ANY, _L("Check for Update"), _L("Check for Update"),
|
append_menu_item(helpMenu, wxID_ANY, _L("Check for Update"), _L("Check for Update"),
|
||||||
[](wxCommandEvent&) {
|
[](wxCommandEvent&) {
|
||||||
|
#if defined(ORCA_HAS_SPARKLE) || defined(ORCA_HAS_WINSPARKLE)
|
||||||
|
UpdateManager::check_for_updates_interactive();
|
||||||
|
#else
|
||||||
wxGetApp().check_new_version_sf(true, 1);
|
wxGetApp().check_new_version_sf(true, 1);
|
||||||
|
#endif
|
||||||
}, "", nullptr, []() {
|
}, "", nullptr, []() {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|||||||
174
src/slic3r/GUI/UpdateManager.cpp
Normal file
174
src/slic3r/GUI/UpdateManager.cpp
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
#include "UpdateManager.hpp"
|
||||||
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
// Windows implementation uses WinSparkle
|
||||||
|
#if defined(_WIN32) && defined(ORCA_HAS_WINSPARKLE)
|
||||||
|
#include <winsparkle.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
// Static member definitions (defined in UpdateManagerMac.mm for macOS)
|
||||||
|
#if !defined(__APPLE__)
|
||||||
|
bool UpdateManager::s_initialized = false;
|
||||||
|
std::string UpdateManager::s_appcast_url;
|
||||||
|
std::string UpdateManager::s_public_key;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) && defined(ORCA_HAS_WINSPARKLE)
|
||||||
|
// ============================================================================
|
||||||
|
// Windows Implementation (WinSparkle)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void UpdateManager::init(const std::string& appcast_url, const std::string& public_key)
|
||||||
|
{
|
||||||
|
if (s_initialized) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "UpdateManager::init called multiple times";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_appcast_url = appcast_url;
|
||||||
|
s_public_key = public_key;
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Initializing WinSparkle with appcast URL: " << appcast_url;
|
||||||
|
|
||||||
|
// Set application details for registry storage
|
||||||
|
win_sparkle_set_app_details(L"SoftFever", L"OrcaSlicer", L"" SLIC3R_VERSION);
|
||||||
|
|
||||||
|
// Set appcast URL
|
||||||
|
win_sparkle_set_appcast_url(appcast_url.c_str());
|
||||||
|
|
||||||
|
// Set EdDSA public key for signature verification
|
||||||
|
if (!public_key.empty()) {
|
||||||
|
win_sparkle_set_dsa_pub_pem(public_key.c_str());
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: EdDSA public key configured";
|
||||||
|
} else {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "UpdateManager: No public key provided, signature verification disabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize WinSparkle (starts background thread)
|
||||||
|
win_sparkle_init();
|
||||||
|
s_initialized = true;
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: WinSparkle initialized successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_interactive()
|
||||||
|
{
|
||||||
|
if (!s_initialized) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "UpdateManager::check_for_updates_interactive called before init";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: User-triggered update check";
|
||||||
|
win_sparkle_check_update_with_ui();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_background()
|
||||||
|
{
|
||||||
|
if (!s_initialized) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "UpdateManager::check_for_updates_background called before init";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Background update check";
|
||||||
|
win_sparkle_check_update_without_ui();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::shutdown()
|
||||||
|
{
|
||||||
|
if (!s_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Shutting down WinSparkle";
|
||||||
|
win_sparkle_cleanup();
|
||||||
|
s_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::set_automatic_check_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
// WinSparkle manages automatic checks via registry settings
|
||||||
|
// The user can configure this through WinSparkle's own preferences dialog
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Automatic check enabled: " << enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
// ============================================================================
|
||||||
|
// Linux Implementation (Stub - AppImageUpdate deferred)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void UpdateManager::init(const std::string& appcast_url, const std::string& public_key)
|
||||||
|
{
|
||||||
|
s_appcast_url = appcast_url;
|
||||||
|
s_public_key = public_key;
|
||||||
|
s_initialized = true;
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Linux auto-update not yet implemented (stub)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_interactive()
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Linux interactive update check not implemented";
|
||||||
|
// TODO: Implement AppImageUpdate integration
|
||||||
|
// For now, fall back to the old behavior (handled by caller)
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_background()
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Linux background update check not implemented";
|
||||||
|
// TODO: Implement AppImageUpdate integration
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::shutdown()
|
||||||
|
{
|
||||||
|
s_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::set_automatic_check_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Linux automatic check not implemented";
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif !defined(__APPLE__)
|
||||||
|
// ============================================================================
|
||||||
|
// Fallback Implementation (No auto-update support)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void UpdateManager::init(const std::string& appcast_url, const std::string& public_key)
|
||||||
|
{
|
||||||
|
s_appcast_url = appcast_url;
|
||||||
|
s_public_key = public_key;
|
||||||
|
s_initialized = true;
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: No auto-update support on this platform";
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_interactive()
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Interactive update check not available";
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_background()
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Background update check not available";
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::shutdown()
|
||||||
|
{
|
||||||
|
s_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::set_automatic_check_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Note: macOS implementation is in UpdateManagerMac.mm
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
||||||
41
src/slic3r/GUI/UpdateManager.hpp
Normal file
41
src/slic3r/GUI/UpdateManager.hpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
/// Cross-platform auto-update manager abstraction.
|
||||||
|
/// Uses WinSparkle on Windows, Sparkle 2 on macOS.
|
||||||
|
/// Linux support deferred (stub implementation).
|
||||||
|
class UpdateManager {
|
||||||
|
public:
|
||||||
|
/// Initialize the platform-specific updater.
|
||||||
|
/// Must be called once during application startup (GUI_App::on_init_inner).
|
||||||
|
/// @param appcast_url URL to the appcast XML feed
|
||||||
|
/// @param public_key Base64-encoded Ed25519 public key for signature verification
|
||||||
|
static void init(const std::string& appcast_url, const std::string& public_key);
|
||||||
|
|
||||||
|
/// Manual check triggered by user (Help -> Check for Updates).
|
||||||
|
/// Shows UI regardless of whether an update is available.
|
||||||
|
static void check_for_updates_interactive();
|
||||||
|
|
||||||
|
/// Background check called on application startup.
|
||||||
|
/// Only shows UI if an update is available.
|
||||||
|
static void check_for_updates_background();
|
||||||
|
|
||||||
|
/// Cleanup on application exit.
|
||||||
|
static void shutdown();
|
||||||
|
|
||||||
|
/// Enable or disable automatic update checks.
|
||||||
|
/// @param enabled If true, automatically check for updates periodically
|
||||||
|
static void set_automatic_check_enabled(bool enabled);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool s_initialized;
|
||||||
|
static std::string s_appcast_url;
|
||||||
|
static std::string s_public_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
||||||
204
src/slic3r/GUI/UpdateManagerMac.mm
Normal file
204
src/slic3r/GUI/UpdateManagerMac.mm
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
#include "UpdateManager.hpp"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
#ifdef ORCA_HAS_SPARKLE
|
||||||
|
#import <Sparkle/Sparkle.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// macOS Implementation (Sparkle 2)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
// Static member definitions (defined in UpdateManager.cpp for other platforms)
|
||||||
|
// For macOS, we need to define them here since UpdateManagerMac.mm is compiled instead
|
||||||
|
bool UpdateManager::s_initialized = false;
|
||||||
|
std::string UpdateManager::s_appcast_url;
|
||||||
|
std::string UpdateManager::s_public_key;
|
||||||
|
|
||||||
|
#ifdef ORCA_HAS_SPARKLE
|
||||||
|
|
||||||
|
// Sparkle updater delegate for custom behavior
|
||||||
|
@interface OrcaSparkleDelegate : NSObject <SPUUpdaterDelegate>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation OrcaSparkleDelegate
|
||||||
|
|
||||||
|
// Optional: Add custom parameters to the appcast request
|
||||||
|
- (NSArray<NSDictionary<NSString *, NSString *> *> *)feedParametersForUpdater:(SPUUpdater *)updater
|
||||||
|
sendingSystemProfile:(BOOL)sendingProfile
|
||||||
|
{
|
||||||
|
// Add OrcaSlicer-specific parameters to the update check request
|
||||||
|
NSString *version = [NSString stringWithUTF8String:SLIC3R_VERSION];
|
||||||
|
NSString *osVersion = [[NSProcessInfo processInfo] operatingSystemVersionString];
|
||||||
|
|
||||||
|
return @[
|
||||||
|
@{@"key": @"app_version", @"value": version ?: @"unknown"},
|
||||||
|
@{@"key": @"os_version", @"value": osVersion ?: @"unknown"}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Handle update errors
|
||||||
|
- (void)updater:(SPUUpdater *)updater didAbortWithError:(NSError *)error
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "UpdateManager: Sparkle update aborted with error: "
|
||||||
|
<< [[error localizedDescription] UTF8String];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Called when an update is found
|
||||||
|
- (void)updater:(SPUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)item
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Found update to version "
|
||||||
|
<< [[item displayVersionString] UTF8String];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Called when no update is available
|
||||||
|
- (void)updaterDidNotFindUpdate:(SPUUpdater *)updater
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: No update available";
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Static Sparkle controller and delegate instances
|
||||||
|
static SPUStandardUpdaterController *s_updater_controller = nil;
|
||||||
|
static OrcaSparkleDelegate *s_updater_delegate = nil;
|
||||||
|
|
||||||
|
void UpdateManager::init(const std::string& appcast_url, const std::string& public_key)
|
||||||
|
{
|
||||||
|
if (s_initialized) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "UpdateManager::init called multiple times";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_appcast_url = appcast_url;
|
||||||
|
s_public_key = public_key;
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Initializing Sparkle 2";
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
// Create the delegate
|
||||||
|
s_updater_delegate = [[OrcaSparkleDelegate alloc] init];
|
||||||
|
|
||||||
|
// Create the standard updater controller
|
||||||
|
// This reads SUFeedURL and SUPublicEDKey from Info.plist
|
||||||
|
s_updater_controller = [[SPUStandardUpdaterController alloc]
|
||||||
|
initWithStartingUpdater:YES
|
||||||
|
updaterDelegate:s_updater_delegate
|
||||||
|
userDriverDelegate:nil];
|
||||||
|
|
||||||
|
if (s_updater_controller) {
|
||||||
|
s_initialized = true;
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Sparkle 2 initialized successfully";
|
||||||
|
} else {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "UpdateManager: Failed to initialize Sparkle 2";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_interactive()
|
||||||
|
{
|
||||||
|
if (!s_initialized || !s_updater_controller) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "UpdateManager::check_for_updates_interactive called before init";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: User-triggered update check (Sparkle)";
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
[s_updater_controller checkForUpdates:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_background()
|
||||||
|
{
|
||||||
|
if (!s_initialized || !s_updater_controller) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "UpdateManager::check_for_updates_background called before init";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Background update check (Sparkle)";
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
SPUUpdater *updater = s_updater_controller.updater;
|
||||||
|
if (updater) {
|
||||||
|
[updater checkForUpdatesInBackground];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::shutdown()
|
||||||
|
{
|
||||||
|
if (!s_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Shutting down Sparkle";
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
// Sparkle handles cleanup automatically when the controller is released
|
||||||
|
s_updater_controller = nil;
|
||||||
|
s_updater_delegate = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::set_automatic_check_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (!s_initialized || !s_updater_controller) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
SPUUpdater *updater = s_updater_controller.updater;
|
||||||
|
if (updater) {
|
||||||
|
updater.automaticallyChecksForUpdates = enabled;
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Automatic check enabled: " << enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !ORCA_HAS_SPARKLE
|
||||||
|
|
||||||
|
// Stub implementation when Sparkle is not available
|
||||||
|
|
||||||
|
void UpdateManager::init(const std::string& appcast_url, const std::string& public_key)
|
||||||
|
{
|
||||||
|
s_appcast_url = appcast_url;
|
||||||
|
s_public_key = public_key;
|
||||||
|
s_initialized = true;
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Sparkle not available (stub)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_interactive()
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Interactive update check not available (no Sparkle)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::check_for_updates_background()
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "UpdateManager: Background update check not available (no Sparkle)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::shutdown()
|
||||||
|
{
|
||||||
|
s_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateManager::set_automatic_check_enabled(bool enabled)
|
||||||
|
{
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ORCA_HAS_SPARKLE
|
||||||
|
|
||||||
|
} // namespace GUI
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // __APPLE__
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// Ed25519 public key for verifying update signatures (used by load_signature_key)
|
||||||
#define ORCA_UPDATER_SIG_KEY_B64 "@ORCA_UPDATER_SIG_KEY_B64@"
|
#define ORCA_UPDATER_SIG_KEY_B64 "@ORCA_UPDATER_SIG_KEY_B64@"
|
||||||
#define ORCA_UPDATER_SIG_KEY_AVAILABLE @ORCA_UPDATER_SIG_KEY_AVAILABLE@
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user