Merge pull request #19960 from Ultimaker/CURA-11622_conan_v2

Cura 11622 conan v2
This commit is contained in:
Erwan MATHIEU 2024-12-04 15:14:39 +01:00 committed by GitHub
commit 3547f8671a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 724 additions and 1254 deletions

View File

@ -20,21 +20,12 @@ on:
- '[0-9].[0-9]*' - '[0-9].[0-9]*'
- '[0-9].[0-9][0-9]*' - '[0-9].[0-9][0-9]*'
env:
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
jobs: jobs:
conan-recipe-version: conan-package:
uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-version.yml@main uses: ultimaker/cura-workflows/.github/workflows/conan-package.yml@main
with: with:
project_name: cura_resources
conan-package-export:
needs: [ conan-recipe-version ]
uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-export.yml@main
with:
recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }}
recipe_id_latest: ${{ needs.conan-recipe-version.outputs.recipe_id_latest }}
conan_recipe_root: "./resources/" conan_recipe_root: "./resources/"
platform_windows: false
platform_mac: false
install_system_dependencies: false
secrets: inherit secrets: inherit

View File

@ -32,28 +32,7 @@ on:
- '[0-9].[0-9]*' - '[0-9].[0-9]*'
- '[0-9].[0-9][0-9]*' - '[0-9].[0-9][0-9]*'
env:
CONAN_LOGIN_USERNAME_CURA: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD_CURA: ${{ secrets.CONAN_PASS }}
jobs: jobs:
conan-recipe-version: conan-package:
uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-version.yml@main uses: ultimaker/cura-workflows/.github/workflows/conan-package.yml@main
with:
project_name: cura
conan-package-export:
needs: [ conan-recipe-version ]
uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-export.yml@main
with:
recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }}
recipe_id_latest: ${{ needs.conan-recipe-version.outputs.recipe_id_latest }}
secrets: inherit
conan-package-create:
needs: [ conan-recipe-version, conan-package-export ]
uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-linux.yml@main
with:
recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }}
conan_extra_args: "-o cura:enable_i18n=True"
secrets: inherit secrets: inherit

View File

@ -6,290 +6,29 @@ on:
inputs: inputs:
cura_conan_version: cura_conan_version:
description: 'Cura Conan Version' description: 'Cura Conan Version'
default: 'cura/latest@ultimaker/testing' default: 'cura/[*]@ultimaker/testing'
required: true
type: string type: string
conan_args: conan_args:
description: 'Conan args: eq.: --require-override' description: 'Conan args, e.g. --requires'
default: '' default: ''
required: false
type: string type: string
enterprise: enterprise:
description: 'Build Cura as an Enterprise edition' description: 'Build Cura as an Enterprise edition'
default: false default: false
required: true
type: boolean type: boolean
staging: staging:
description: 'Use staging API' description: 'Use staging API'
default: false default: false
required: true
type: boolean
nightly:
description: 'Upload to nightly release'
default: false
required: true
type: boolean type: boolean
workflow_call:
inputs:
cura_conan_version:
default: 'cura/latest@ultimaker/testing'
required: true
type: string
conan_args:
default: ''
required: false
type: string
enterprise:
default: false
required: true
type: boolean
staging:
default: false
required: true
type: boolean
nightly:
default: false
required: true
type: boolean
schedule:
# Daily at 4:15 CET (main-branch) and 5:15 CET (release-branch)
- cron: '15 3 * * *'
- cron: '15 4 * * *'
env:
CONAN_ARGS: ${{ inputs.conan_args || '' }}
ENTERPRISE: ${{ inputs.enterprise || false }}
STAGING: ${{ inputs.staging || false }}
jobs: jobs:
default_values: installers:
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-default-value.yml@main name: Create installers
uses: ultimaker/cura-workflows/.github/workflows/cura-installers.yml@main
with: with:
cura_conan_version: ${{ inputs.cura_conan_version }} cura_conan_version: ${{ inputs.cura_conan_version }}
latest_release: '5.6' conan_args: ${{ inputs.conan_args }}
latest_release_schedule_hour: 4 enterprise: ${{ inputs.enterprise }}
latest_release_tag: 'nightly' staging: ${{ inputs.staging }}
windows-installer:
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-windows.yml@main
needs: [ default_values ]
with:
cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }}
conan_args: ${{ github.event.inputs.conan_args }}
enterprise: ${{ github.event.inputs.enterprise == 'true' }}
staging: ${{ github.event.inputs.staging == 'true' }}
architecture: X64
operating_system: self-hosted-Windows-X64
secrets: inherit secrets: inherit
linux-installer:
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-linux.yml@main
needs: [ default_values ]
with:
cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }}
conan_args: ${{ github.event.inputs.conan_args }}
enterprise: ${{ github.event.inputs.enterprise == 'true' }}
staging: ${{ github.event.inputs.staging == 'true' }}
architecture: X64
operating_system: self-hosted-Ubuntu22-X64
secrets: inherit
macos-installer:
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.yml@main
needs: [ default_values ]
with:
cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }}
conan_args: ${{ github.event.inputs.conan_args }}
enterprise: ${{ github.event.inputs.enterprise == 'true' }}
staging: ${{ github.event.inputs.staging == 'true' }}
architecture: X64
operating_system: self-hosted-X64
secrets: inherit
macos-arm-installer:
uses: ultimaker/cura-workflows/.github/workflows/cura-installer-macos.yml@main
needs: [ default_values ]
with:
cura_conan_version: ${{ needs.default_values.outputs.cura_conan_version }}
conan_args: ${{ github.event.inputs.conan_args }}
enterprise: ${{ github.event.inputs.enterprise == 'true' }}
staging: ${{ github.event.inputs.staging == 'true' }}
architecture: ARM64
operating_system: self-hosted-ARM64
secrets: inherit
# Run and update nightly release when the nightly input is set to true or if the schedule is triggered
update-nightly-release:
if: ${{ inputs.nightly || github.event_name == 'schedule' }}
runs-on: ubuntu-latest
needs: [ default_values, windows-installer, linux-installer, macos-installer, macos-arm-installer ]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Download the run info
uses: actions/download-artifact@v4
with:
name: linux-run-info
- name: Set the run info as environment variables
run: |
. run_info.sh
- name: Output the name file name and extension
id: filename
shell: python
run: |
import os
import datetime
enterprise = "-Enterprise" if "${{ github.event.inputs.enterprise }}" == "true" else ""
linux = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-linux-X64"
mac_x64_dmg = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-macos-X64"
mac_x64_pkg = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-macos-X64"
mac_arm_dmg = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-macos-ARM64"
mac_arm_pkg = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-macos-ARM64"
win_msi = installer_filename = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-win64-X64"
win_exe = installer_filename = f"UltiMaker-Cura-{os.getenv('CURA_VERSION_FULL')}{enterprise}-win64-X64"
nightly_name = "UltiMaker-Cura-" + os.getenv('CURA_VERSION_FULL').split("+")[0]
nightly_creation_time = str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
output_env = os.environ["GITHUB_OUTPUT"]
content = ""
if os.path.exists(output_env):
with open(output_env, "r") as f:
content = f.read()
with open(output_env, "w") as f:
f.write(content)
f.writelines(f"LINUX={linux}\n")
f.writelines(f"MAC_X64_DMG={mac_x64_dmg}\n")
f.writelines(f"MAC_X64_PKG={mac_x64_pkg}\n")
f.writelines(f"MAC_ARM_DMG={mac_arm_dmg}\n")
f.writelines(f"MAC_ARM_PKG={mac_arm_pkg}\n")
f.writelines(f"WIN_MSI={win_msi}\n")
f.writelines(f"WIN_EXE={win_exe}\n")
f.writelines(f"NIGHTLY_NAME={nightly_name}\n")
f.writelines(f"NIGHTLY_TIME={nightly_creation_time}\n")
- name: Download linux installer jobs artifacts
uses: actions/download-artifact@v4
with:
name: ${{ steps.filename.outputs.LINUX }}-AppImage
path: installers
- name: Download linux installer jobs asc artifacts
uses: actions/download-artifact@v4
with:
name: ${{ steps.filename.outputs.LINUX }}-asc
path: installers
- name: Rename Linux installer to nightlies
run: |
mv installers/${{ steps.filename.outputs.LINUX }}.AppImage installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-linux-X64.AppImage
mv installers/${{ steps.filename.outputs.LINUX }}.AppImage.asc installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-linux-X64.AppImage.asc
- name: Update nightly release for Linux
run: |
gh release upload ${{ needs.default_values.outputs.release_tag }} installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-linux-X64.AppImage --clobber
gh release upload ${{ needs.default_values.outputs.release_tag }} installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-linux-X64.AppImage.asc --clobber
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download win msi installer jobs artifacts
uses: actions/download-artifact@v4
with:
name: ${{ steps.filename.outputs.WIN_MSI }}-msi
path: installers
- name: Download win exe installer jobs artifacts
uses: actions/download-artifact@v4
with:
name: ${{ steps.filename.outputs.WIN_EXE }}-exe
path: installers
- name: Rename Windows installers to nightlies
run: |
mv installers/${{ steps.filename.outputs.WIN_MSI }}.msi installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-win64-X64.msi
mv installers/${{ steps.filename.outputs.WIN_EXE }}.exe installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-win64-X64.exe
- name: Update nightly release for Windows
run: |
gh release upload ${{ needs.default_values.outputs.release_tag }} installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-win64-X64.msi --clobber
gh release upload ${{ needs.default_values.outputs.release_tag }} installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-win64-X64.exe --clobber
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download MacOS (X64) dmg installer jobs artifacts
uses: actions/download-artifact@v4
with:
name: ${{ steps.filename.outputs.MAC_X64_DMG }}-dmg
path: installers
- name: Download MacOS (X64) pkg installer jobs artifacts
uses: actions/download-artifact@v4
with:
name: ${{ steps.filename.outputs.MAC_X64_PKG }}-pkg
path: installers
- name: Rename MacOS (X64) installers to nightlies
run: |
mv installers/${{ steps.filename.outputs.MAC_X64_DMG }}.dmg installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-macos-X64.dmg
mv installers/${{ steps.filename.outputs.MAC_X64_PKG }}.pkg installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-macos-X64.pkg
- name: Update nightly release for MacOS (X64)
run: |
gh release upload ${{ needs.default_values.outputs.release_tag }} installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-macos-X64.dmg --clobber
gh release upload ${{ needs.default_values.outputs.release_tag }} installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-macos-X64.pkg --clobber
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Download MacOS (ARM-64) dmg installer jobs artifacts
uses: actions/download-artifact@v4
with:
name: ${{ steps.filename.outputs.MAC_ARM_DMG }}-dmg
path: installers
- name: Download MacOS (ARM-64) pkg installer jobs artifacts
uses: actions/download-artifact@v4
with:
name: ${{ steps.filename.outputs.MAC_ARM_PKG }}-pkg
path: installers
- name: Rename MacOS (ARM-64) installers to nightlies
run: |
mv installers/${{ steps.filename.outputs.MAC_ARM_DMG }}.dmg installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-macos-ARM64.dmg
mv installers/${{ steps.filename.outputs.MAC_ARM_PKG }}.pkg installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-macos-ARM64.pkg
- name: Update nightly release for MacOS (ARM-64)
run: |
gh release upload ${{ needs.default_values.outputs.release_tag }} installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-macos-ARM64.dmg --clobber
gh release upload ${{ needs.default_values.outputs.release_tag }} installers/${{ steps.filename.outputs.NIGHTLY_NAME }}-macos-ARM64.pkg --clobber
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: create the release notes
shell: python
run: |
import os
import datetime
from jinja2 import Template
with open(".github/workflows/release_notes.md.jinja", "r") as f:
release_notes = Template(f.read())
current_nightly_beta = "${{ needs.default_values.outputs.release_tag }}".split("nightly-")[-1]
with open("release-notes.md", "w") as f:
f.write(release_notes.render(
timestamp="${{ steps.filename.outputs.NIGHTLY_TIME }}",
branch="" if "${{ needs.default-values.outputs.release_tag == 'nightly' }}" == 'true' else current_nightly_beta,
branch_specific="" if os.getenv("GITHUB_REF") == "refs/heads/main" else f"?branch={current_nightly_beta}",
))
- name: Update nightly release description (with date)
if: always()
run: |
gh release edit ${{ needs.default_values.outputs.release_tag }} --title "${{ steps.filename.outputs.NIGHTLY_NAME }}" --notes-file release-notes.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -10,7 +10,7 @@ on:
required: true required: true
type: string type: string
conan_args: conan_args:
description: 'Conan args: eq.: --require-override' description: 'Conan args, e.g. --requires'
default: '' default: ''
required: false required: false
type: string type: string
@ -24,13 +24,6 @@ on:
default: false default: false
required: true required: true
type: boolean type: boolean
architecture:
description: 'Architecture'
required: true
default: 'X64'
type: choice
options:
- X64
operating_system: operating_system:
description: 'OS' description: 'OS'
required: true required: true
@ -48,6 +41,5 @@ jobs:
conan_args: ${{ inputs.conan_args }} conan_args: ${{ inputs.conan_args }}
enterprise: ${{ inputs.enterprise }} enterprise: ${{ inputs.enterprise }}
staging: ${{ inputs.staging }} staging: ${{ inputs.staging }}
architecture: ${{ inputs.architecture }}
operating_system: ${{ inputs.operating_system }} operating_system: ${{ inputs.operating_system }}
secrets: inherit secrets: inherit

15
.github/workflows/nightly-stable.yml vendored Normal file
View File

@ -0,0 +1,15 @@
name: Nightly build - stable release
run-name: Nightly build - stable release
on:
schedule:
# Daily at 5:15 CET
- cron: '15 4 * * *'
jobs:
build-nightly:
uses: ./.github/workflows/nightly.yml
with:
cura_conan_version: "cura/[*]@ultimaker/stable"
release_tag: "nightly"
caller_workflow: "nightly-stable.yml"

15
.github/workflows/nightly-testing.yml vendored Normal file
View File

@ -0,0 +1,15 @@
name: Nightly build - dev release
run-name: Nightly build - dev release
on:
schedule:
# Daily at 4:15 CET
- cron: '15 3 * * *'
jobs:
build-nightly:
uses: ./.github/workflows/nightly.yml
with:
cura_conan_version: "cura/[*]@ultimaker/testing"
release_tag: "nightly-stable" # Fixed version, we reuse the same tag forever
caller_workflow: "nightly-testing.yml"

78
.github/workflows/nightly.yml vendored Normal file
View File

@ -0,0 +1,78 @@
name: Nightly build
run-name: Nightly build
on:
workflow_call:
inputs:
cura_conan_version:
required: true
type: string
release_tag:
required: true
type: string
caller_workflow:
required: true
type: string
jobs:
create-installers:
name: Create installers
id: create-installers
uses: ultimaker/cura-workflows/.github/workflows/cura-installers.yml@main
with:
cura_conan_version: ${{ inputs.cura_conan_version }}
secrets: inherit
update-nightly-release:
name: Upload installers
runs-on: ubuntu-latest
needs: [ create-installers ]
steps:
- name: Setup the build environment
uses: ultimaker/cura-workflows/.github/actions/setup-build-environment@main
- name: Download installers jobs artifacts
uses: actions/download-artifact@v4
with:
pattern: UltiMaker-Cura-*
path: installers
merge-multiple: true
- name: Rename the installers
id: rename-installers
working-directory: installers
run: python ./Cura-workflows/runner_scripts/rename_installers.py --tag "nightly" >> $GITHUB_OUTPUT
- name: create the release notes
shell: python
run: |
import os
import datetime
from jinja2 import Template
with open(".github/workflows/nightly_release_notes.md.jinja", "r") as f:
release_notes = Template(f.read())
short_version = "${{ steps.rename-installers.outputs.short_version }}"
caller_workflow = "${{ inputs.caller_workflow }}"
is_main = os.getenv("GITHUB_REF") == "refs/heads/main"
with open("release-notes.md", "w") as f:
f.write(release_notes.render(
timestamp=str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
caller_workflow=caller_workflow,
branch="" if is_main else short_version,
branch_specific="" is_main else f"?branch={short_version}",
))
- name: Update nightly release description and binaries
working-directory: installers
run: |
gh release edit ${{ inputs.release_tag }} --title "${{ steps.rename-installers.outputs.cura_version }}" --notes-file release-notes.md
for file in "*"; do
gh release upload ${{ inputs.release_tag }} $file --clobber
done
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -4,7 +4,7 @@
| | | | | |
|--------------:|--------------------------------------------------------------------------------------------| |--------------:|--------------------------------------------------------------------------------------------|
| **Nightlies** | [![nightly {{ branch }}](https://github.com/Ultimaker/Cura/actions/workflows/installers.yml/badge.svg{{ branch_specific }} | **Nightlies** | [![nightly {{ branch }}](https://github.com/Ultimaker/Cura/actions/workflows/{{ caller_workflow }}/badge.svg{{ branch_specific }}
?event=schedule)](https://github.com/Ultimaker/Cura/actions/workflows/installers.yml) | ?event=schedule)](https://github.com/Ultimaker/Cura/actions/workflows/installers.yml) |
# Unit Test results # Unit Test results

View File

@ -1,36 +0,0 @@
name: notify_on_print_profile_change
on:
push:
branches: [ "main" ]
paths:
- 'resources/definitions/fdmprinter.def.json'
- 'resources/definitions/ultimaker**'
- 'resources/extruders/ultimaker**'
- 'resources/intent/ultimaker**'
- 'resources/quality/ultimaker**'
- 'resources/variants/ultimaker**'
pull_request:
branches: [ "main" ]
paths:
- 'resources/definitions/fdmprinter.def.json'
- 'resources/definitions/ultimaker**'
- 'resources/extruders/ultimaker**'
- 'resources/intent/ultimaker**'
- 'resources/quality/ultimaker**'
- 'resources/variants/ultimaker**'
permissions: {}
jobs:
slackNotification:
name: Slack Notification
runs-on: ubuntu-latest
steps:
- name: Ultimaker Print Profile Changed
uses: rtCamp/action-slack-notify@v2
env:
SLACK_CHANNEL: profile-changes
SLACK_USERNAME: ${{ github.repository }}
SLACK_COLOR: '#00FF00'
SLACK_TITLE: Print profiles changed
MSG_MINIMAL: commit
SLACK_WEBHOOK: ${{ secrets.SLACK_CURA_PPM_HOOK }}

View File

@ -15,27 +15,15 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Setup the build environment
uses: actions/checkout@v4 uses: ultimaker/cura-workflows/.github/actions/setup-build-environment@main
- uses: technote-space/get-diff-action@v6 - uses: greguintow/get-diff-action@v7
with: with:
PATTERNS: | PATTERNS: |
resources/+(definitions|extruders)/*.def.json resources/+(definitions|extruders)/*.def.json
resources/+(intent|quality|variants)/**/*.inst.cfg resources/+(intent|quality|variants)/**/*.inst.cfg
- name: Setup Python and pip
if: env.GIT_DIFF && !env.MATCHED_FILES # If nothing happens with python and/or pip after, the clean-up crashes.
uses: actions/setup-python@v4
with:
python-version: 3.11.x
cache: 'pip'
cache-dependency-path: .github/workflows/requirements-printer-linter.txt
- name: Install Python requirements for runner
if: env.GIT_DIFF && !env.MATCHED_FILES
run: pip install -r .github/workflows/requirements-printer-linter.txt
- name: Format file - name: Format file
if: env.GIT_DIFF && !env.MATCHED_FILES if: env.GIT_DIFF && !env.MATCHED_FILES
run: python printer-linter/src/terminal.py --format ${{ env.GIT_DIFF_FILTERED }} run: python printer-linter/src/terminal.py --format ${{ env.GIT_DIFF_FILTERED }}

View File

@ -14,30 +14,16 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Setup the build environment
uses: actions/checkout@v4 uses: ultimaker/cura-workflows/.github/actions/setup-build-environment@main
with:
fetch-depth: 2
- uses: technote-space/get-diff-action@v6 - uses: greguintow/get-diff-action@v7
with: with:
DIFF_FILTER: AMRCD DIFF_FILTER: AMRCD
PATTERNS: | PATTERNS: |
resources/+(extruders|definitions)/*.def.json resources/+(extruders|definitions)/*.def.json
resources/+(intent|quality|variants)/**/*.inst.cfg resources/+(intent|quality|variants)/**/*.inst.cfg
- name: Setup Python and pip
if: env.GIT_DIFF && !env.MATCHED_FILES # If nothing happens with python and/or pip after, the clean-up crashes.
uses: actions/setup-python@v4
with:
python-version: 3.11.x
cache: "pip"
cache-dependency-path: .github/workflows/requirements-printer-linter.txt
- name: Install Python requirements for runner
if: env.GIT_DIFF && !env.MATCHED_FILES
run: pip install -r .github/workflows/requirements-printer-linter.txt
- name: Create results directory - name: Create results directory
run: mkdir printer-linter-result run: mkdir printer-linter-result

View File

@ -15,6 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
package_version: ${{ steps.version_parser.outputs.major }}.${{ steps.version_parser.outputs.minor }}.0-alpha.1 package_version: ${{ steps.version_parser.outputs.major }}.${{ steps.version_parser.outputs.minor }}.0-alpha.1
branch: ${{ steps.version_parser.outputs.major }}.${{ steps.version_parser.outputs.minor }}
steps: steps:
- name: Parse version string - name: Parse version string
id: version_parser id: version_parser
@ -28,5 +29,6 @@ jobs:
needs: [parse-version] needs: [parse-version]
with: with:
cura_version: ${{ needs.parse-version.outputs.package_version }} cura_version: ${{ needs.parse-version.outputs.package_version }}
branch: ${{ needs.parse-version.outputs.branch }}
create_feature_branch: true create_feature_branch: true
secrets: inherit secrets: inherit

View File

@ -36,6 +36,7 @@ jobs:
needs: [parse-version] needs: [parse-version]
with: with:
cura_version: ${{ inputs.cura_version }} cura_version: ${{ inputs.cura_version }}
branch: ${{ needs.parse-version.outputs.branch_name }}
create_feature_branch: false create_feature_branch: false
secrets: inherit secrets: inherit
@ -99,9 +100,8 @@ jobs:
run: | run: |
echo "main_commit=`git rev-parse HEAD`" >> "$GITHUB_OUTPUT" echo "main_commit=`git rev-parse HEAD`" >> "$GITHUB_OUTPUT"
create-packages:
create-dependencies-packages: name: Create conan packages
name: Create conan packages for dependencies
uses: ultimaker/cura-workflows/.github/workflows/conan-package-release.yml@main uses: ultimaker/cura-workflows/.github/workflows/conan-package-release.yml@main
needs: [parse-version, freeze-packages-versions] needs: [parse-version, freeze-packages-versions]
strategy: strategy:
@ -113,38 +113,17 @@ jobs:
conan_recipe_root: "resources" conan_recipe_root: "resources"
with: with:
repository: ${{ matrix.repository }} repository: ${{ matrix.repository }}
ref_name: ${{ needs.parse-version.outputs.branch_name }} branch: ${{ needs.parse-version.outputs.branch_name }}
version: ${{ inputs.cura_version }}
conan_release: true
conan_user_channel: ultimaker/stable
conan_internal: false
conan_latest: true
conan_recipe_root: ${{ matrix.conan_recipe_root }} conan_recipe_root: ${{ matrix.conan_recipe_root }}
secrets: inherit secrets: inherit
create-cura-package:
name: Create conan package for Cura
uses: ultimaker/cura-workflows/.github/workflows/conan-package-release.yml@main
needs: [parse-version, create-dependencies-packages]
with:
repository: Cura
ref_name: ${{ needs.parse-version.outputs.branch_name }}
version: ${{ inputs.cura_version }}
conan_release: true
conan_user_channel: ultimaker/stable
conan_internal: false
conan_latest: true
secrets: inherit
create-installers: create-installers:
name: Create installers name: Create installers
uses: ./.github/workflows/installers.yml uses: ultimaker/cura-workflows/.github/workflows/cura-installers.yml@main
needs: [parse-version, create-cura-package] needs: [parse-version, create-packages]
with: with:
cura_conan_version: cura/${{ inputs.cura_version }}@/ cura_conan_version: cura/${{ inputs.cura_version }}@ultimaker/stable
enterprise: false conan_args: "-c user.sentry:environment=production"
staging: false
nightly: false
secrets: inherit secrets: inherit
create-release-draft: create-release-draft:
@ -174,7 +153,7 @@ jobs:
body: formatted_changelog.txt body: formatted_changelog.txt
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v4
with: with:
path: artifacts path: artifacts
merge-multiple: true merge-multiple: true

View File

@ -1,2 +0,0 @@
conan>=1.60.2,<2.0.0
sip<=6.7.12

View File

@ -1 +0,0 @@
pyyaml

View File

@ -37,26 +37,9 @@ on:
- main - main
- '[0-9]+.[0-9]+' - '[0-9]+.[0-9]+'
permissions:
contents: read
env:
CONAN_LOGIN_USERNAME: ${{ secrets.CONAN_USER }}
CONAN_PASSWORD: ${{ secrets.CONAN_PASS }}
jobs: jobs:
conan-recipe-version:
uses: ultimaker/cura-workflows/.github/workflows/conan-recipe-version.yml@main
with:
project_name: cura
testing: testing:
name: Run unit tests
uses: ultimaker/cura-workflows/.github/workflows/unit-test.yml@main uses: ultimaker/cura-workflows/.github/workflows/unit-test.yml@main
needs: [ conan-recipe-version ]
with: with:
recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} test_use_pytest: true
conan_extra_args: '-g VirtualPythonEnv -o cura:devtools=True -c tools.build:skip_test=False --options "*:enable_sentry=False"'
unit_test_cmd: 'pytest --junitxml=junit_cura.xml'
unit_test_dir: 'tests'
conan_generator_dir: './venv/bin'
secrets: inherit

View File

@ -1,87 +1,15 @@
name: update-translations name: Update translations
on: on:
push: workflow_dispatch:
paths: inputs:
- 'plugins/**' branch:
- 'resources/**' description: 'Specific branch to update translations on'
- 'cura/**' required: false
- 'icons/**' type: string
- 'tests/**'
- 'packaging/**'
- '.github/workflows/conan-*.yml'
- '.github/workflows/notify.yml'
- '.github/workflows/requirements-conan-package.txt'
- 'requirements*.txt'
- 'conanfile.py'
- 'conandata.yml'
- 'GitVersion.yml'
- '*.jinja'
branches:
- '[1-9].[0-9]'
- '[1-9].[0-9][0-9]'
tags:
- '[1-9].[0-9].[0-9]*'
- '[1-9].[0-9].[0-9]'
- '[1-9].[0-9][0-9].[0-9]*'
jobs: jobs:
update-translations: update-translations:
name: Update translations uses: ultimaker/cura-workflows/.github/workflows/update-translations.yml@main
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache Conan data
id: cache-conan
uses: actions/cache@v3
with: with:
path: ~/.conan branch: ${{ inputs.branch }}
key: ${{ runner.os }}-conan
- name: Setup Python and pip
uses: actions/setup-python@v4
with:
python-version: 3.11.x
cache: pip
cache-dependency-path: .github/workflows/requirements-conan-package.txt
- name: Install Python requirements for runner
run: pip install -r .github/workflows/requirements-conan-package.txt
# NOTE: Due to what are probably github issues, we have to remove the cache and reconfigure before the rest.
# This is maybe because grub caches the disk it uses last time, which is recreated each time.
- name: Install Linux system requirements
if: ${{ runner.os == 'Linux' }}
run: |
sudo rm /var/cache/debconf/config.dat
sudo dpkg --configure -a
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt update
sudo apt upgrade
sudo apt install efibootmgr build-essential checkinstall libegl-dev zlib1g-dev libssl-dev ninja-build autoconf libx11-dev libx11-xcb-dev libfontenc-dev libice-dev libsm-dev libxau-dev libxaw7-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxdmcp-dev libxext-dev libxfixes-dev libxi-dev libxinerama-dev libxkbfile-dev libxmu-dev libxmuu-dev libxpm-dev libxrandr-dev libxrender-dev libxres-dev libxss-dev libxt-dev libxtst-dev libxv-dev libxvmc-dev libxxf86vm-dev xtrans-dev libxcb-render0-dev libxcb-render-util0-dev libxcb-xkb-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-xinerama0-dev xkb-data libxcb-dri3-dev uuid-dev libxcb-util-dev libxkbcommon-x11-dev pkg-config flex bison g++-12 gcc-12 -y
- name: Install GCC-13
run: |
sudo apt install g++-13 gcc-13 -y
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
- name: Create the default Conan profile
run: conan profile new default --detect --force
- name: Get Conan configuration
run: |
conan config install https://github.com/Ultimaker/conan-config.git
conan config install https://github.com/Ultimaker/conan-config.git -a "-b runner/${{ runner.os }}/${{ runner.arch }}"
- name: generate the files using Conan install
run: conan install . --build=missing --update -o cura:devtools=True
- uses: stefanzweifel/git-auto-commit-action@v4
with:
file_pattern: resources/i18n/*.po resources/i18n/*.pot
status_options: --untracked-files=no
commit_message: update translations

View File

@ -10,7 +10,7 @@ on:
required: true required: true
type: string type: string
conan_args: conan_args:
description: 'Conan args: eq.: --require-override' description: 'Conan args: eq.: --requires'
default: '' default: ''
required: false required: false
type: string type: string
@ -24,13 +24,6 @@ on:
default: false default: false
required: true required: true
type: boolean type: boolean
architecture:
description: 'Architecture'
required: true
default: 'X64'
type: choice
options:
- X64
operating_system: operating_system:
description: 'OS' description: 'OS'
required: true required: true
@ -48,6 +41,5 @@ jobs:
conan_args: ${{ inputs.conan_args }} conan_args: ${{ inputs.conan_args }}
enterprise: ${{ inputs.enterprise }} enterprise: ${{ inputs.enterprise }}
staging: ${{ inputs.staging }} staging: ${{ inputs.staging }}
architecture: ${{ inputs.architecture }}
operating_system: ${{ inputs.operating_system }} operating_system: ${{ inputs.operating_system }}
secrets: inherit secrets: inherit

View File

@ -4,6 +4,7 @@
CuraAppName = "{{ cura_app_name }}" CuraAppName = "{{ cura_app_name }}"
CuraAppDisplayName = "{{ cura_app_display_name }}" CuraAppDisplayName = "{{ cura_app_display_name }}"
CuraVersion = "{{ cura_version }}" CuraVersion = "{{ cura_version }}"
CuraVersionFull = "{{ cura_version_full }}"
CuraBuildType = "{{ cura_build_type }}" CuraBuildType = "{{ cura_build_type }}"
CuraDebugMode = {{ cura_debug_mode }} CuraDebugMode = {{ cura_debug_mode }}
CuraCloudAPIRoot = "{{ cura_cloud_api_root }}" CuraCloudAPIRoot = "{{ cura_cloud_api_root }}"
@ -14,4 +15,5 @@ CuraDigitalFactoryURL = "{{ cura_digital_factory_url }}"
CuraLatestURL = "{{ cura_latest_url }}" CuraLatestURL = "{{ cura_latest_url }}"
ConanInstalls = {{ conan_installs }} ConanInstalls = {{ conan_installs }}
PythonInstalls = {{ python_installs }} PythonInstalls = {{ python_installs }}

View File

@ -1,17 +1,18 @@
version: "5.10.0-alpha.0" version: "5.10.0-alpha.0"
requirements: requirements:
- "cura_resources/(latest)@ultimaker/testing" - "cura_resources/5.10.0-alpha.0@ultimaker/testing"
- "uranium/(latest)@ultimaker/testing" - "uranium/5.10.0-alpha.0@ultimaker/testing"
- "curaengine/(latest)@ultimaker/testing" - "curaengine/5.10.0-alpha.0@ultimaker/testing"
- "cura_binary_data/(latest)@ultimaker/testing" - "cura_binary_data/5.10.0-alpha.0@ultimaker/testing"
- "fdm_materials/(latest)@ultimaker/testing" - "fdm_materials/5.10.0-alpha.0@ultimaker/testing"
- "dulcificum/0.2.1" - "dulcificum/0.2.1@ultimaker/stable"
- "pysavitar/5.3.0" - "pysavitar/5.4.0-alpha.0@ultimaker/stable"
- "pynest2d/5.3.0" - "pynest2d/5.4.0-alpha.0@ultimaker/stable"
- "native_cad_plugin/2.0.0"
requirements_internal: requirements_internal:
- "fdm_materials/(latest)@ultimaker/testing" - "fdm_materials/5.8.1"
- "cura_private_data/(latest)@internal/testing" - "cura_private_data/5.10.0-alpha.0@internal/testing"
requirements_enterprise:
- "native_cad_plugin/2.0.0"
urls: urls:
default: default:
cloud_api_root: "https://api.ultimaker.com" cloud_api_root: "https://api.ultimaker.com"
@ -25,6 +26,7 @@ urls:
marketplace_root: "https://marketplace-staging.ultimaker.com" marketplace_root: "https://marketplace-staging.ultimaker.com"
digital_factory_url: "https://digitalfactory-staging.ultimaker.com" digital_factory_url: "https://digitalfactory-staging.ultimaker.com"
cura_latest_url: "https://software.ultimaker.com/latest.json" cura_latest_url: "https://software.ultimaker.com/latest.json"
pyinstaller: pyinstaller:
runinfo: runinfo:
entrypoint: "cura_app.py" entrypoint: "cura_app.py"
@ -37,10 +39,12 @@ pyinstaller:
package: "native_cad_plugin" package: "native_cad_plugin"
src: "res/plugins/NativeCADplugin" src: "res/plugins/NativeCADplugin"
dst: "share/cura/plugins/NativeCADplugin" dst: "share/cura/plugins/NativeCADplugin"
enterprise_only: true
native_cad_plugin_bundled: native_cad_plugin_bundled:
package: "native_cad_plugin" package: "native_cad_plugin"
src: "res/bundled_packages" src: "res/bundled_packages"
dst: "share/cura/resources/bundled_packages" dst: "share/cura/resources/bundled_packages"
enterprise_only: true
cura_resources: cura_resources:
package: "cura" package: "cura"
src: "resources" src: "resources"
@ -78,18 +82,12 @@ pyinstaller:
package: "cura_binary_data" package: "cura_binary_data"
src: "windows" src: "windows"
dst: "share/windows" dst: "share/windows"
oses:
- "Windows"
fdm_materials: fdm_materials:
package: "fdm_materials" package: "fdm_materials"
src: "res/resources/materials" src: "res/resources/materials"
dst: "share/cura/resources/materials" dst: "share/cura/resources/materials"
tcl:
package: "tcl"
src: "lib/tcl8.6"
dst: "tcl"
tk:
package: "tk"
src: "lib/tk8.6"
dst: "tk"
binaries: binaries:
curaengine: curaengine:
package: "curaengine" package: "curaengine"
@ -137,6 +135,7 @@ pyinstaller:
- [ "qt", "virt", "key" ] - [ "qt", "virt", "key" ]
- [ "qt", "wayland", "compos" ] - [ "qt", "wayland", "compos" ]
- [ "qt", "5", "compat" ] - [ "qt", "5", "compat" ]
pycharm_targets: pycharm_targets:
- jinja_path: .run_templates/pycharm_cura_run.run.xml.jinja - jinja_path: .run_templates/pycharm_cura_run.run.xml.jinja
module_name: Cura module_name: Cura
@ -255,3 +254,351 @@ pycharm_targets:
module_name: Cura module_name: Cura
name: pytest in TestSettingVisibilityPresets.py name: pytest in TestSettingVisibilityPresets.py
script_name: tests/Settings/TestSettingVisibilityPresets.py script_name: tests/Settings/TestSettingVisibilityPresets.py
pip_requirements_core:
any_os:
charon:
url: "git+https://github.com/ultimaker/libcharon@master/s-line#egg=charon"
certifi:
version: "2023.5.7"
hashes:
- sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716
- sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7
zeroconf:
version: "0.31.0"
hashes:
- sha256:5a468da018bc3f04bbce77ae247924d802df7aeb4c291bbbb5a9616d128800b0
- sha256:53a180248471c6f81bd1fffcbce03ed93d7d8eaf10905c9121ac1ea996d19844
importlib-metadata:
version: "4.10.0"
hashes:
- sha256:b7cf7d3fef75f1e4c80a96ca660efbd51473d7e8f39b5ab9210febc7809012a4
- sha256:92a8b58ce734b2a4494878e0ecf7d79ccd7a128b5fc6014c401e0b61f006f0f6
keyring:
version: "23.0.1"
hashes:
- sha256:8f607d7d1cc502c43a932a275a56fe47db50271904513a379d39df1af277ac48
- sha256:045703609dd3fccfcdb27da201684278823b72af515aedec1a8515719a038cb8
trimesh:
version: "3.9.36"
hashes:
- sha256:8ac8bea693b3ee119f11b022fc9b9481c9f1af06cb38bc859bf5d16bbbe49b23
- sha256:f01e8edab14d1999700c980c21a1546f37417216ad915a53be649d263130181e
setuptools:
version: "75.6.0"
hashes:
- sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d
- sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6
sentry-sdk:
version: "0.13.5"
hashes:
- sha256:05285942901d38c7ce2498aba50d8e87b361fc603281a5902dda98f3f8c5e145
- sha256:c6b919623e488134a728f16326c6f0bcdab7e3f59e7f4c472a90eea4d6d8fe82
pyserial:
version: "3.4"
hashes:
- sha256:e0770fadba80c31013896c7e6ef703f72e7834965954a78e71a3049488d4d7d8
- sha256:6e2d401fdee0eab996cf734e67773a0143b932772ca8b42451440cfed942c627
chardet:
version: "3.0.4"
hashes:
- sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
- sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae
idna:
version: "2.8"
hashes:
- sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c
- sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407
attrs:
version: "21.3.0"
hashes:
- sha256:8f7335278dedd26b58c38e006338242cc0977f06d51579b2b8b87b9b33bff66c
- sha256:50f3c9b216dc9021042f71b392859a773b904ce1a029077f58f6598272432045
requests:
version: "2.32.3"
hashes:
- sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
- sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760
twisted:
version: "21.2.0"
hashes:
- sha256:aab38085ea6cda5b378b519a0ec99986874921ee8881318626b0a3414bb2631e
- sha256:77544a8945cf69b98d2946689bbe0c75de7d145cdf11f391dd487eae8fc95a12
constantly:
version: "15.1.0"
hashes:
- sha256:dd2fa9d6b1a51a83f0d7dd76293d734046aa176e384bf6e33b7e44880eb37c5d
- sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35
hyperlink:
version: "21.0.0"
hashes:
- sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4
- sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b
incremental:
version: "22.10.0"
hashes:
- sha256:b864a1f30885ee72c5ac2835a761b8fe8aa9c28b9395cacf27286602688d3e51
- sha256:912feeb5e0f7e0188e6f42241d2f450002e11bbc0937c65865045854c24c0bd0
zope.interface:
version: "5.4.0"
hashes:
- sha256:7df1e1c05304f26faa49fa752a8c690126cf98b40b91d54e6e9cc3b7d6ffe8b7
- sha256:2c98384b254b37ce50eddd55db8d381a5c53b4c10ee66e1e7fe749824f894021
- sha256:08f9636e99a9d5410181ba0729e0408d3d8748026ea938f3b970a0249daa8192
- sha256:0ea1d73b7c9dcbc5080bb8aaffb776f1c68e807767069b9ccdd06f27a161914a
- sha256:273f158fabc5ea33cbc936da0ab3d4ba80ede5351babc4f577d768e057651531
- sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263
- sha256:b0297b1e05fd128d26cc2460c810d42e205d16d76799526dfa8c8ccd50e74959
- sha256:af310ec8335016b5e52cae60cda4a4f2a60a788cbb949a4fbea13d441aa5a09e
- sha256:9a9845c4c6bb56e508651f005c4aeb0404e518c6f000d5a1123ab077ab769f5c
- sha256:a1e6e96217a0f72e2b8629e271e1b280c6fa3fe6e59fa8f6701bec14e3354325
- sha256:877473e675fdcc113c138813a5dd440da0769a2d81f4d86614e5d62b69497155
- sha256:0b465ae0962d49c68aa9733ba92a001b2a0933c317780435f00be7ecb959c702
- sha256:5dd9ca406499444f4c8299f803d4a14edf7890ecc595c8b1c7115c2342cadc5f
- sha256:469e2407e0fe9880ac690a3666f03eb4c3c444411a5a5fddfdabc5d184a79f05
- sha256:52de7fc6c21b419078008f697fd4103dbc763288b1406b4562554bd47514c004
- sha256:3dd4952748521205697bc2802e4afac5ed4b02909bb799ba1fe239f77fd4e117
- sha256:dd93ea5c0c7f3e25335ab7d22a507b1dc43976e1345508f845efc573d3d779d8
- sha256:3748fac0d0f6a304e674955ab1365d515993b3a0a865e16a11ec9d86fb307f63
- sha256:66c0061c91b3b9cf542131148ef7ecbecb2690d48d1612ec386de9d36766058f
- sha256:d0c1bc2fa9a7285719e5678584f6b92572a5b639d0e471bb8d4b650a1a910920
- sha256:2876246527c91e101184f63ccd1d716ec9c46519cc5f3d5375a3351c46467c46
- sha256:334701327f37c47fa628fc8b8d28c7d7730ce7daaf4bda1efb741679c2b087fc
- sha256:71aace0c42d53abe6fc7f726c5d3b60d90f3c5c055a447950ad6ea9cec2e37d9
- sha256:5bb3489b4558e49ad2c5118137cfeaf59434f9737fa9c5deefc72d22c23822e2
- sha256:1c0e316c9add0db48a5b703833881351444398b04111188069a26a61cfb4df78
- sha256:6f0c02cbb9691b7c91d5009108f975f8ffeab5dff8f26d62e21c493060eff2a1
- sha256:7d97a4306898b05404a0dcdc32d9709b7d8832c0c542b861d9a826301719794e
- sha256:867a5ad16892bf20e6c4ea2aab1971f45645ff3102ad29bd84c86027fa99997b
- sha256:5f931a1c21dfa7a9c573ec1f50a31135ccce84e32507c54e1ea404894c5eb96f
- sha256:194d0bcb1374ac3e1e023961610dc8f2c78a0f5f634d0c737691e215569e640d
- sha256:8270252effc60b9642b423189a2fe90eb6b59e87cbee54549db3f5562ff8d1b8
- sha256:15e7d1f7a6ee16572e21e3576d2012b2778cbacf75eb4b7400be37455f5ca8bf
- sha256:8892f89999ffd992208754851e5a052f6b5db70a1e3f7d54b17c5211e37a98c7
- sha256:2e5a26f16503be6c826abca904e45f1a44ff275fdb7e9d1b75c10671c26f8b94
- sha256:0f91b5b948686659a8e28b728ff5e74b1be6bf40cb04704453617e5f1e945ef3
- sha256:4de4bc9b6d35c5af65b454d3e9bc98c50eb3960d5a3762c9438df57427134b8e
- sha256:bf68f4b2b6683e52bec69273562df15af352e5ed25d1b6641e7efddc5951d1a7
- sha256:63b82bb63de7c821428d513607e84c6d97d58afd1fe2eb645030bdc185440120
- sha256:db1fa631737dab9fa0b37f3979d8d2631e348c3b4e8325d6873c2541d0ae5a48
- sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4
- sha256:a9506a7e80bcf6eacfff7f804c0ad5350c8c95b9010e4356a4b36f5322f09abb
- sha256:3c02411a3b62668200910090a0dff17c0b25aaa36145082a5a6adf08fa281e54
- sha256:0cee5187b60ed26d56eb2960136288ce91bcf61e2a9405660d271d1f122a69a4
- sha256:a8156e6a7f5e2a0ff0c5b21d6bcb45145efece1909efcbbbf48c56f8da68221d
- sha256:205e40ccde0f37496904572035deea747390a8b7dc65146d30b96e2dd1359a83
- sha256:3f24df7124c323fceb53ff6168da70dbfbae1442b4f3da439cd441681f54fe25
- sha256:5208ebd5152e040640518a77827bdfcc73773a15a33d6644015b763b9c9febc1
- sha256:17776ecd3a1fdd2b2cd5373e5ef8b307162f581c693575ec62e7c5399d80794c
- sha256:d4d9d6c1a455d4babd320203b918ccc7fcbefe308615c521062bc2ba1aa4d26e
- sha256:0cba8477e300d64a11a9789ed40ee8932b59f9ee05f85276dbb4b59acee5dd09
- sha256:5dba5f530fec3f0988d83b78cc591b58c0b6eb8431a85edd1569a0539a8a5a0e
automat:
version: "20.2.0"
hashes:
- sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111
- sha256:7979803c74610e11ef0c0d68a2942b152df52da55336e0c9d58daf1831cbdf33
shapely:
version: "2.0.6"
hashes:
- sha256:29a34e068da2d321e926b5073539fd2a1d4429a2c656bd63f0bd4c8f5b236d0b
- sha256:e1c84c3f53144febf6af909d6b581bc05e8785d57e27f35ebaa5c1ab9baba13b
- sha256:2ad2fae12dca8d2b727fa12b007e46fbc522148a584f5d6546c539f3464dccde
- sha256:b3304883bd82d44be1b27a9d17f1167fda8c7f5a02a897958d86c59ec69b705e
- sha256:3ec3a0eab496b5e04633a39fa3d5eb5454628228201fb24903d38174ee34565e
- sha256:28f87cdf5308a514763a5c38de295544cb27429cfa655d50ed8431a4796090c4
- sha256:5aeb0f51a9db176da9a30cb2f4329b6fbd1e26d359012bb0ac3d3c7781667a9e
- sha256:9a7a78b0d51257a367ee115f4d41ca4d46edbd0dd280f697a8092dd3989867b2
- sha256:f32c23d2f43d54029f986479f7c1f6e09c6b3a19353a3833c2ffb226fb63a855
- sha256:b3dc9fb0eb56498912025f5eb352b5126f04801ed0e8bdbd867d21bdbfd7cbd0
- sha256:d93b7e0e71c9f095e09454bf18dad5ea716fb6ced5df3cb044564a00723f339d
- sha256:c02eb6bf4cfb9fe6568502e85bb2647921ee49171bcd2d4116c7b3109724ef9b
- sha256:cec9193519940e9d1b86a3b4f5af9eb6910197d24af02f247afbfb47bcb3fab0
- sha256:83b94a44ab04a90e88be69e7ddcc6f332da7c0a0ebb1156e1c4f568bbec983c3
- sha256:537c4b2716d22c92036d00b34aac9d3775e3691f80c7aa517c2c290351f42cd8
- sha256:98fea108334be345c283ce74bf064fa00cfdd718048a8af7343c59eb40f59726
- sha256:42fd4cd4834747e4990227e4cbafb02242c0cffe9ce7ef9971f53ac52d80d55f
- sha256:665990c84aece05efb68a21b3523a6b2057e84a1afbef426ad287f0796ef8a48
- sha256:42805ef90783ce689a4dde2b6b2f261e2c52609226a0438d882e3ced40bb3013
- sha256:6d2cb146191a47bd0cee8ff5f90b47547b82b6345c0d02dd8b25b88b68af62d7
- sha256:e3fdef0a1794a8fe70dc1f514440aa34426cc0ae98d9a1027fb299d45741c381
- sha256:2c665a0301c645615a107ff7f52adafa2153beab51daf34587170d85e8ba6805
- sha256:0334bd51828f68cd54b87d80b3e7cee93f249d82ae55a0faf3ea21c9be7b323a
- sha256:d37d070da9e0e0f0a530a621e17c0b8c3c9d04105655132a87cfff8bd77cc4c2
- sha256:fa7468e4f5b92049c0f36d63c3e309f85f2775752e076378e36c6387245c5462
- sha256:ed5867e598a9e8ac3291da6cc9baa62ca25706eea186117034e8ec0ea4355653
- sha256:81d9dfe155f371f78c8d895a7b7f323bb241fb148d848a2bf2244f79213123fe
- sha256:fbb7bf02a7542dba55129062570211cfb0defa05386409b3e306c39612e7fbcc
- sha256:837d395fac58aa01aa544495b97940995211e3e25f9aaf87bc3ba5b3a8cd1ac7
- sha256:c6d88ade96bf02f6bfd667ddd3626913098e243e419a0325ebef2bbd481d1eb6
- sha256:8b3b818c4407eaa0b4cb376fd2305e20ff6df757bf1356651589eadc14aab41b
- sha256:1bbc783529a21f2bd50c79cef90761f72d41c45622b3e57acf78d984c50a5d13
- sha256:2423f6c0903ebe5df6d32e0066b3d94029aab18425ad4b07bf98c3972a6e25a1
- sha256:2de00c3bfa80d6750832bde1d9487e302a6dd21d90cb2f210515cefdb616e5f5
- sha256:3a82d58a1134d5e975f19268710e53bddd9c473743356c90d97ce04b73e101ee
- sha256:392f66f458a0a2c706254f473290418236e52aa4c9b476a072539d63a2460595
- sha256:eba5bae271d523c938274c61658ebc34de6c4b33fdf43ef7e938b5776388c1be
- sha256:7060566bc4888b0c8ed14b5d57df8a0ead5c28f9b69fb6bed4476df31c51b0af
- sha256:b02154b3e9d076a29a8513dffcb80f047a5ea63c897c0cd3d3679f29363cf7e5
- sha256:44246d30124a4f1a638a7d5419149959532b99dfa25b54393512e6acc9c211ac
- sha256:2b542d7f1dbb89192d3512c52b679c822ba916f93479fa5d4fc2fe4fa0b3c9e8
- sha256:997f6159b1484059ec239cacaa53467fd8b5564dabe186cd84ac2944663b0bf6
cython:
version: "0.29.26"
hashes:
- sha256:c4b003b6b7aa9e74552ef8d4e6009b3e3c3e8fa585710b3a6d062e088e460c1b
- sha256:ce804a021c92fea66c8c100781a111706f21bade7a546895c5a9c57fe2df8b24
- sha256:93840f2071c1f15e613509eadee1fbcd335e8666772437fe5038e24059edd48c
- sha256:10402f0f1564ffc6ecb9c45e07f995771d05bb0b0e1d151e40574638292ee3a5
- sha256:8e07121b34221458a2151d37e137b8f5b011a9c51dd38db2499a6198590aa319
- sha256:233a87db76941626f1db08f4b25a4a5b425b13b64ed0e673c3641f7b650a48d8
- sha256:6773cce9d4b3b6168d8feb2b6f06b658ef1e11cbfec075041745666d8e2a5e45
- sha256:c813799d533194b7d85203d881d8b4f567a8c644a67f50d47f1ffbf316df412f
- sha256:362fbb9cb4627c7786231429768b54aaba5459a2a0e46c25e59f202ca6155437
- sha256:2b834ff6e4d10ba6d7a0d676dd71c1b427a181ddbbbbf79e91d1861557aab59f
- sha256:0c3093bc99facfc97e5019f6c5bc39987663792265c1334d9fc9e37c3a3dcd6f
- sha256:bbf0149680c1fca07200a3ed372b22e6bad7851d191b717a61f9a68af370e180
- sha256:a1cc55db32cd39474081d478263b96e036552cdbbab8831c90ea43fb385a9b66
- sha256:ebe32e002a9e6553de399033e259ece72aa17c77f740b265e66f122572a8a278
- sha256:6b385f68789c3e8a75b4827e8a4970ff04605ad3cb1c0b41005cc69368dad65d
- sha256:1519eb639de308f5763eb0666b4cc7bd3958268f3f6228cc610b7b4d6c94b68b
- sha256:e118525defec3f67471d8ee5ce04340d43195410a87e5d7ec8a1a9e953c0066a
- sha256:706ea55f58c2722206e51cd9a8754ed0995c4c4231d24b095875d2641d745222
- sha256:77913fe27c5e22c995bac090d01e200ff91e5f58aa944e2d2e94cbf67ea2ae34
- sha256:51923120f57a42c59f5ee6bba9e89a31a394ae8cd419c753f64d8a3aea1ee8b7
- sha256:82881565d04027728d7762edd8c085927a840873af7ee049d703e0ca226bc08d
- sha256:531303085503959338e6cdac630626280ef111aecbb22d48321673a8c3897c0a
- sha256:0205b685802eb4c039b14f67b7ac3f00c55ff04b9e3871df2249576d3e59ba42
- sha256:7df94e56872df8f396ca669466fee60256f69f678654239f706b1e643c2ac4a5
- sha256:4b7d04b393d9a4b5fec0cbc4b0f29fe083a9d862d95231a6e7608978bd661d7e
- sha256:af91dd63ac5f1f7fc70dc91ea063f727db42b5eb934d1f3832611be18e25171e
- sha256:d83dad8dc6c63706cb3178dc79010b3865b1345090727189d2cd61758a825ee8
- sha256:ca10e9fde0eaba1407ab353ff07a26daaa3e4dbe356108a149e482d441f070dd
- sha256:fec66cd0a48697fab903854566235aecf1084f62e3163d6589ae7335a1b4d448
- sha256:b3041e45aefaa4449fd671902132c0ac1f72eedaedac745c0e1a70a13bf990bb
- sha256:ed76fb98979f02b5e89079906071983a36f3634d3028b86f935cf0196f24fcaa
- sha256:4d868e1a41f5123f51a20c1b8e82f7cb6fa3370c104e98e707f7c910e8cadad1
- sha256:868f309095e557f06dc58723ae865e8c65cfedb2646a562bd8080c92d69e4e4b
- sha256:be550b566345bf53b95616334793ce42a128cf1d9dcde1e28cbf7ce52ea61d6d
- sha256:be13be1e2b9b7395588f2a23bfa692f2f3e6f7936ccf7825c83431b8c8c3452b
- sha256:41ee918480371ae5e5851ba9b1ead5a183e24aedb27bf807c7405d124e943f40
- sha256:c91b1ba0d43f7f7ccde8121c672207c7891735ddcc83496af1e0ab617ddc4aba
- sha256:5ecf5cf5b57086cc6c1cfc76d6353bbd7023e95da32e0883f1302ca50e481c33
- sha256:0ffce25bf50fa926ec6bf8d6f29650e7cb33fae445938c9880e1ce9b776353ef
- sha256:5041adfef502d67ecd5e291a7cf645a37fed7a9dac557f40d491053f35204d00
- sha256:5fd5db458c9d3d2c2abd047f3190624d9cce8a80a8e0ca0baa69cfd133a523bc
- sha256:75eaa22911d2ec37a3841f77b710b178c805cd378b5e1c4fb82dbc35620d2062
- sha256:3aed8c642e8fb27024bca46830b7f62335a44a92354acf708d6b8d050f945a3a
- sha256:b5ca05c2bfba0c2480b5fd390ecffe46b8da574d887d600388d6e3caf3f99a88
- sha256:f5e15ff892c8afad64931ee3dd723c4755c2c516606f9aae7613bebfac62b0f6
- sha256:af377d543a762867da11fcf6e558f7a4a535ff8693f30cce123fab10c00fa312
pybind11:
version: "2.6.2"
hashes:
- sha256:2d8aebe1709bc367e34e3b23d8eccbf3f387ee9d5640548c6260d33b59f02405
- sha256:d0e0aed9279656f21501243b707eb6e3b951e89e10c3271dedf3ae41c365e5ed
wheel:
version: "0.37.1"
hashes:
- sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a
- sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4
ifaddr:
version: "0.1.7"
hashes:
- sha256:d1f603952f0a71c9ab4e705754511e4e03b02565bc4cec7188ad6415ff534cd3
- sha256:1f9e8a6ca6f16db5a37d3356f07b6e52344f6f9f7e806d618537731669eb1a94
pycparser:
version: "2.20"
hashes:
- sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705
- sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0
zipp:
version: "3.5.0"
hashes:
- sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3
- sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4
urllib3:
version: "2.2.3"
hashes:
- sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac
- sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9
jeepney:
version: "0.8.0"
hashes:
- sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755
- sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806
SecretStorage:
version: "3.3.3"
hashes:
- sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99
- sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77
keyring:
version: "25.5.0"
hashes:
- sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741
- sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6
jaraco.classes:
version: "3.4.0"
hashes:
- sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790
- sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd
jaraco.functools:
version: "4.1.0"
hashes:
- sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649
- sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d
jaraco.context:
version: "6.0.1"
hashes:
- sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4
- sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3
more_itertools:
version: "10.5.0"
hashes:
- sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef
- sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6
charset-normalizer:
version: "2.1.0"
hashes:
- sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5
- sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413
Windows:
twisted-iocpsupport:
version: "1.0.2"
hashes:
- sha256:985c06a33f5c0dae92c71a036d1ea63872ee86a21dd9b01e1f287486f15524b4
- sha256:81b3abe3527b367da0220482820cb12a16c661672b7bcfcde328902890d63323
- sha256:9dbb8823b49f06d4de52721b47de4d3b3026064ef4788ce62b1a21c57c3fff6f
- sha256:b9fed67cf0f951573f06d560ac2f10f2a4bbdc6697770113a2fc396ea2cb2565
- sha256:b76b4eed9b27fd63ddb0877efdd2d15835fdcb6baa745cb85b66e5d016ac2878
- sha256:851b3735ca7e8102e661872390e3bce88f8901bece95c25a0c8bb9ecb8a23d32
- sha256:bf4133139d77fc706d8f572e6b7d82871d82ec7ef25d685c2351bdacfb701415
- sha256:306becd6e22ab6e8e4f36b6bdafd9c92e867c98a5ce517b27fdd27760ee7ae41
- sha256:3c61742cb0bc6c1ac117a7e5f422c129832f0c295af49e01d8a6066df8cfc04d
- sha256:b435857b9efcbfc12f8c326ef0383f26416272260455bbca2cd8d8eca470c546
- sha256:7d972cfa8439bdcb35a7be78b7ef86d73b34b808c74be56dfa785c8a93b851bf
- sha256:72068b206ee809c9c596b57b5287259ea41ddb4774d86725b19f35bf56aa32a9
pywin32-ctypes:
version: "0.2.3"
hashes:
- sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8
- sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755
pip_requirements_dev:
any_os:
pytest: {}
pyyaml: {}
sip: { version: "6.5.1" }
jinja2: {}
pip_requirements_installer:
any_os:
pyinstaller: { version: "6.11.1" }
pyinstaller-hooks-contrib: {}
python_translation_source_folders:
- cura
- plugins
qml_translation_source_folders:
- resources/qml
- plugins

View File

@ -11,7 +11,7 @@ from conan.tools.env import VirtualRunEnv, Environment, VirtualBuildEnv
from conan.tools.scm import Version from conan.tools.scm import Version
from conan.errors import ConanInvalidConfiguration, ConanException from conan.errors import ConanInvalidConfiguration, ConanException
required_conan_version = ">=1.58.0 <2.0.0" required_conan_version = ">=2.7.0"
class CuraConan(ConanFile): class CuraConan(ConanFile):
@ -24,99 +24,54 @@ class CuraConan(ConanFile):
build_policy = "missing" build_policy = "missing"
exports = "LICENSE*", "*.jinja" exports = "LICENSE*", "*.jinja"
settings = "os", "compiler", "build_type", "arch" settings = "os", "compiler", "build_type", "arch"
generators = "VirtualPythonEnv"
tool_requires = "gettext/0.22.5"
# FIXME: Remove specific branch once merged to main # FIXME: Remove specific branch once merged to main
python_requires = "translationextractor/[>=2.2.0]@ultimaker/stable" python_requires = "translationextractor/[>=2.2.0]@ultimaker/stable"
options = { options = {
"enterprise": ["True", "False", "true", "false"], # Workaround for GH Action passing boolean as lowercase string "enterprise": [True, False],
"staging": ["True", "False", "true", "false"], # Workaround for GH Action passing boolean as lowercase string "staging": [True, False],
"devtools": [True, False], # FIXME: Split this up in testing and (development / build (pyinstaller) / system installer) tools "cloud_api_version": ["ANY"],
"cloud_api_version": "ANY", "display_name": ["ANY"], # TODO: should this be an option??
"display_name": "ANY", # TODO: should this be an option??
"cura_debug_mode": [True, False], # FIXME: Use profiles "cura_debug_mode": [True, False], # FIXME: Use profiles
"internal": ["True", "False", "true", "false"], # Workaround for GH Action passing boolean as lowercase string "internal": [True, False],
"enable_i18n": [True, False], "i18n_extract": [True, False],
} }
default_options = { default_options = {
"enterprise": "False", "enterprise": False,
"staging": "False", "staging": False,
"devtools": False,
"cloud_api_version": "1", "cloud_api_version": "1",
"display_name": "UltiMaker Cura", "display_name": "UltiMaker Cura",
"cura_debug_mode": False, # Not yet implemented "cura_debug_mode": False, # Not yet implemented
"internal": "False", "internal": False,
"enable_i18n": False, "i18n_extract": False,
} }
def set_version(self): def set_version(self):
if not self.version: if not self.version:
self.version = self.conan_data["version"] self.version = self.conan_data["version"]
@property
def _i18n_options(self):
return self.conf.get("user.i18n:options", default = {"extract": True, "build": True}, check_type = dict)
@property
def _pycharm_targets(self):
return self.conan_data["pycharm_targets"]
# FIXME: These env vars should be defined in the runenv.
_cura_env = None
@property
def _cura_run_env(self):
if self._cura_env:
return self._cura_env
self._cura_env = Environment()
self._cura_env.define("QML2_IMPORT_PATH", str(self._site_packages.joinpath("PyQt6", "Qt6", "qml")))
self._cura_env.define("QT_PLUGIN_PATH", str(self._site_packages.joinpath("PyQt6", "Qt6", "plugins")))
if not self.in_local_cache:
self._cura_env.define("CURA_DATA_ROOT", str(self._share_dir.joinpath("cura")))
if self.settings.os == "Linux":
self._cura_env.define("QT_QPA_FONTDIR", "/usr/share/fonts")
self._cura_env.define("QT_QPA_PLATFORMTHEME", "xdgdesktopportal")
self._cura_env.define("QT_XKB_CONFIG_ROOT", "/usr/share/X11/xkb")
return self._cura_env
@property
def _enterprise(self):
return self.options.enterprise in ["True", 'true']
@property
def _internal(self):
return self.options.internal in ["True", 'true']
@property @property
def _app_name(self): def _app_name(self):
if self._enterprise: if self.options.enterprise:
return str(self.options.display_name) + " Enterprise" return str(self.options.display_name) + " Enterprise"
return str(self.options.display_name) return str(self.options.display_name)
@property @property
def _urls(self): def _urls(self):
if self.options.staging in ["True", 'true']: if self.options.staging:
return "staging" return "staging"
return "default" return "default"
@property @property
def requirements_txts(self): def _root_dir(self):
if self.options.devtools: return Path(self.deploy_folder if hasattr(self, "deploy_folder") else self.source_folder)
return ["requirements.txt", "requirements-ultimaker.txt", "requirements-dev.txt"]
return ["requirements.txt", "requirements-ultimaker.txt"]
@property @property
def _base_dir(self): def _base_dir(self):
if self.install_folder is None: return self._root_dir.joinpath("venv")
if self.build_folder is not None:
return Path(self.build_folder)
return Path(os.getcwd(), "venv")
if self.in_local_cache:
return Path(self.install_folder)
else:
return Path(self.source_folder, "venv")
@property @property
def _share_dir(self): def _share_dir(self):
@ -132,7 +87,7 @@ class CuraConan(ConanFile):
def _site_packages(self): def _site_packages(self):
if self.settings.os == "Windows": if self.settings.os == "Windows":
return self._base_dir.joinpath("Lib", "site-packages") return self._base_dir.joinpath("Lib", "site-packages")
py_version = Version(self.deps_cpp_info["cpython"].version) py_version = Version(self.dependencies["cpython"].ref.version)
return self._base_dir.joinpath("lib", f"python{py_version.major}.{py_version.minor}", "site-packages") return self._base_dir.joinpath("lib", f"python{py_version.major}.{py_version.minor}", "site-packages")
@property @property
@ -157,7 +112,7 @@ class CuraConan(ConanFile):
# list of conan installs # list of conan installs
for dependency in self.dependencies.host.values(): for dependency in self.dependencies.host.values():
conan_installs[dependency.ref.name] = { conan_installs[dependency.ref.name] = {
"version": dependency.ref.version, "version": str(dependency.ref.version),
"revision": dependency.ref.revision "revision": dependency.ref.revision
} }
return conan_installs return conan_installs
@ -166,22 +121,15 @@ class CuraConan(ConanFile):
self.output.info("Collecting python installs") self.output.info("Collecting python installs")
python_installs = {} python_installs = {}
# list of python installs collect_python_installs = "collect_python_installs.py"
run_env = VirtualRunEnv(self) code = f"import importlib.metadata; print(';'.join([(package.metadata['Name']+','+ package.metadata['Version']) for package in importlib.metadata.distributions()]))"
env = run_env.environment() save(self, collect_python_installs, code)
env.prepend_path("PYTHONPATH", str(self._site_packages.as_posix()))
venv_vars = env.vars(self, scope = "run")
outer = '"' if self.settings.os == "Windows" else "'"
inner = "'" if self.settings.os == "Windows" else '"'
buffer = StringIO() buffer = StringIO()
with venv_vars.apply(): self.run(f"""python {collect_python_installs}""", env = "virtual_python_env", stdout = buffer)
self.run(f"""python -c {outer}import pkg_resources; print({inner};{inner}.join([(s.key+{inner},{inner}+ s.version) for s in pkg_resources.working_set])){outer}""", rm(self, collect_python_installs, ".")
env = "conanrun",
output = buffer)
packages = str(buffer.getvalue()).split("-----------------\n") packages = str(buffer.getvalue()).strip('\r\n').split(";")
packages = packages[1].strip('\r\n').split(";")
for package in packages: for package in packages:
name, version = package.split(",") name, version = package.split(",")
python_installs[name] = {"version": version} python_installs[name] = {"version": version}
@ -197,15 +145,18 @@ class CuraConan(ConanFile):
cura_version = Version(self.conf.get("user.cura:version", default = self.version, check_type = str)) cura_version = Version(self.conf.get("user.cura:version", default = self.version, check_type = str))
pre_tag = f"-{cura_version.pre}" if cura_version.pre else "" pre_tag = f"-{cura_version.pre}" if cura_version.pre else ""
build_tag = f"+{cura_version.build}" if cura_version.build else "" build_tag = f"+{cura_version.build}" if cura_version.build else ""
internal_tag = f"+internal" if self._internal else "" internal_tag = f"+internal" if self.options.internal else ""
cura_version = f"{cura_version.major}.{cura_version.minor}.{cura_version.patch}{pre_tag}{build_tag}{internal_tag}" cura_version = f"{cura_version.major}.{cura_version.minor}.{cura_version.patch}{pre_tag}{build_tag}{internal_tag}"
self.output.info(f"Write CuraVersion.py to {self.recipe_folder}")
with open(os.path.join(location, "CuraVersion.py"), "w") as f: with open(os.path.join(location, "CuraVersion.py"), "w") as f:
f.write(cura_version_py.render( f.write(cura_version_py.render(
cura_app_name = self.name, cura_app_name = self.name,
cura_app_display_name = self._app_name, cura_app_display_name = self._app_name,
cura_version = cura_version, cura_version = cura_version,
cura_build_type = "Enterprise" if self._enterprise else "", cura_version_full = self.version,
cura_build_type = "Enterprise" if self.options.enterprise else "",
cura_debug_mode = self.options.cura_debug_mode, cura_debug_mode = self.options.cura_debug_mode,
cura_cloud_api_root = self.conan_data["urls"][self._urls]["cloud_api_root"], cura_cloud_api_root = self.conan_data["urls"][self._urls]["cloud_api_root"],
cura_cloud_api_version = self.options.cloud_api_version, cura_cloud_api_version = self.options.cloud_api_version,
@ -273,43 +224,51 @@ class CuraConan(ConanFile):
except Exception as ex: except Exception as ex:
print(f"WARNING: Attempt to delete folder {dir_} results in: {str(ex)}") print(f"WARNING: Attempt to delete folder {dir_} results in: {str(ex)}")
def _generate_pyinstaller_spec(self, location, entrypoint_location, icon_path, entitlements_file): def _generate_pyinstaller_spec(self, location, entrypoint_location, icon_path, entitlements_file, cura_source_folder):
pyinstaller_metadata = self.conan_data["pyinstaller"] pyinstaller_metadata = self.conan_data["pyinstaller"]
datas = [] datas = []
for data in pyinstaller_metadata["datas"].values(): for data in pyinstaller_metadata["datas"].values():
if not self._internal and data.get("internal", False): if (not self.options.internal and data.get("internal", False)) or (not self.options.enterprise and data.get("enterprise_only", False)):
continue
if "oses" in data and self.settings.os not in data["oses"]:
continue continue
if "package" in data: # get the paths from conan package if "package" in data: # get the paths from conan package
if data["package"] == self.name: if data["package"] == self.name:
if self.in_local_cache: src_path = str(Path(cura_source_folder, data["src"]))
src_path = os.path.join(self.package_folder, data["src"])
else: else:
src_path = os.path.join(self.source_folder, data["src"]) if data["package"] not in self.dependencies:
else: raise ConanException(f"Required package {data['package']} does not exist as a dependency")
if data["package"] not in self.deps_cpp_info.deps:
continue package_folder = self.dependencies[data['package']].package_folder
src_path = os.path.join(self.deps_cpp_info[data["package"]].rootpath, data["src"]) if package_folder is None:
raise ConanException(f"Unable to find package_folder for {data['package']}, check that it has not been skipped")
src_path = os.path.join(self.dependencies[data["package"]].package_folder, data["src"])
elif "root" in data: # get the paths relative from the install folder elif "root" in data: # get the paths relative from the install folder
src_path = os.path.join(self.install_folder, data["root"], data["src"]) src_path = os.path.join(self.install_folder, data["root"], data["src"])
else: else:
continue raise ConanException("Misformatted conan data for pyinstaller datas, expected either package or root option")
if Path(src_path).exists():
if not Path(src_path).exists():
raise ConanException(f"Missing folder {src_path} for pyinstaller data {data}")
datas.append((str(src_path), data["dst"])) datas.append((str(src_path), data["dst"]))
binaries = [] binaries = []
for binary in pyinstaller_metadata["binaries"].values(): for binary in pyinstaller_metadata["binaries"].values():
if "package" in binary: # get the paths from conan package if "package" in binary: # get the paths from conan package
src_path = os.path.join(self.deps_cpp_info[binary["package"]].rootpath, binary["src"]) src_path = os.path.join(self.dependencies[binary["package"]].package_folder, binary["src"])
elif "root" in binary: # get the paths relative from the sourcefolder elif "root" in binary: # get the paths relative from the sourcefolder
src_path = str(self.source_path.joinpath(binary["root"], binary["src"])) src_path = str(Path(self.source_folder, binary["root"], binary["src"]))
if self.settings.os == "Windows": if self.settings.os == "Windows":
src_path = src_path.replace("\\", "\\\\") src_path = src_path.replace("\\", "\\\\")
else: else:
continue raise ConanException("Misformatted conan data for pyinstaller binaries, expected either package or root option")
if not Path(src_path).exists(): if not Path(src_path).exists():
self.output.warning(f"Source path for binary {binary['binary']} does not exist") raise ConanException(f"Missing folder {src_path} for pyinstaller binary {binary}")
continue
for bin in Path(src_path).glob(binary["binary"] + "*[.exe|.dll|.so|.dylib|.so.]*"): for bin in Path(src_path).glob(binary["binary"] + "*[.exe|.dll|.so|.dylib|.so.]*"):
binaries.append((str(bin), binary["dst"])) binaries.append((str(bin), binary["dst"]))
@ -382,89 +341,50 @@ class CuraConan(ConanFile):
copy(self, "*", os.path.join(self.recipe_folder, "cura"), os.path.join(self.export_sources_folder, "cura"), excludes="CuraVersion.py") copy(self, "*", os.path.join(self.recipe_folder, "cura"), os.path.join(self.export_sources_folder, "cura"), excludes="CuraVersion.py")
copy(self, "*", os.path.join(self.recipe_folder, "packaging"), os.path.join(self.export_sources_folder, "packaging")) copy(self, "*", os.path.join(self.recipe_folder, "packaging"), os.path.join(self.export_sources_folder, "packaging"))
copy(self, "*", os.path.join(self.recipe_folder, ".run_templates"), os.path.join(self.export_sources_folder, ".run_templates")) copy(self, "*", os.path.join(self.recipe_folder, ".run_templates"), os.path.join(self.export_sources_folder, ".run_templates"))
copy(self, "requirements.txt", self.recipe_folder, self.export_sources_folder)
copy(self, "requirements-dev.txt", self.recipe_folder, self.export_sources_folder)
copy(self, "requirements-ultimaker.txt", self.recipe_folder, self.export_sources_folder)
copy(self, "cura_app.py", self.recipe_folder, self.export_sources_folder) copy(self, "cura_app.py", self.recipe_folder, self.export_sources_folder)
def config_options(self):
if self.settings.os == "Windows" and not self.conf.get("tools.microsoft.bash:path", check_type=str):
del self.options.enable_i18n
def configure(self):
self.options["pyarcus"].shared = True
self.options["pysavitar"].shared = True
self.options["pynest2d"].shared = True
self.options["dulcificum"].shared = self.settings.os != "Windows"
self.options["cpython"].shared = True
self.options["boost"].header_only = True
if self.settings.os == "Linux":
self.options["openssl"].shared = True
if self.conf.get("user.curaengine:sentry_url", "", check_type=str) != "":
self.options["curaengine"].enable_sentry = True
self.options["arcus"].enable_sentry = True
self.options["clipper"].enable_sentry = True
def validate(self): def validate(self):
version = self.conf.get("user.cura:version", default = self.version, check_type = str) if self.options.i18n_extract and self.settings.os == "Windows" and not self.conf.get("tools.microsoft.bash:path", check_type=str):
if version and Version(version) <= Version("4"): raise ConanInvalidConfiguration("Unable to extract translations on Windows without Bash installed")
raise ConanInvalidConfiguration("Only versions 5+ are support")
def requirements(self): def requirements(self):
for req in self.conan_data["requirements"]: for req in self.conan_data["requirements"]:
if self._internal and "fdm_materials" in req: if self.options.internal and "fdm_materials" in req:
continue
if not self._enterprise and "native_cad_plugin" in req:
continue continue
self.requires(req) self.requires(req)
if self._internal: if self.options.internal:
for req in self.conan_data["requirements_internal"]: for req in self.conan_data["requirements_internal"]:
self.requires(req) self.requires(req)
self.requires("cpython/3.10.4@ultimaker/stable") if self.options.enterprise:
self.requires("clipper/6.4.2@ultimaker/stable") for req in self.conan_data["requirements_enterprise"]:
self.requires("openssl/3.2.0") self.requires(req)
self.requires("protobuf/3.21.12") self.requires("cpython/3.12.2")
self.requires("boost/1.82.0")
self.requires("spdlog/1.12.0")
self.requires("fmt/10.1.1")
self.requires("zlib/1.2.13")
def build_requirements(self):
if self.options.get_safe("enable_i18n", False):
self.tool_requires("gettext/0.21", force_host_context = True)
def layout(self): def layout(self):
self.folders.source = "." self.folders.source = "."
self.folders.build = "venv" self.folders.build = "build"
self.folders.generators = os.path.join(self.folders.build, "conan") self.folders.generators = os.path.join(self.folders.build, "generators")
self.cpp.package.libdirs = [os.path.join("site-packages", "cura")] self.cpp.package.libdirs = [os.path.join("site-packages", "cura")]
self.cpp.package.bindirs = ["bin"] self.cpp.package.bindirs = ["bin"]
self.cpp.package.resdirs = ["resources", "plugins", "packaging", "pip_requirements"] # pip_requirements should be the last item in the list self.cpp.package.resdirs = ["resources", "plugins", "packaging"]
def generate(self): def generate(self):
copy(self, "cura_app.py", self.source_folder, str(self._script_dir)) copy(self, "cura_app.py", self.source_folder, str(self._script_dir))
cura_run_envvars = self._cura_run_env.vars(self, scope = "run")
ext = ".ps1" if self.settings.os == "Windows" else ".sh"
cura_run_envvars.save_script(os.path.join(self.folders.generators, f"cura_run_environment{ext}"))
vr = VirtualRunEnv(self) self._generate_cura_version(str(Path(self.source_folder, "cura")))
vr.generate()
self._generate_cura_version(os.path.join(self.source_folder, "cura"))
if not self.in_local_cache:
# Copy CuraEngine.exe to bindirs of Virtual Python Environment # Copy CuraEngine.exe to bindirs of Virtual Python Environment
curaengine = self.dependencies["curaengine"].cpp_info curaengine = self.dependencies["curaengine"].cpp_info
copy(self, "CuraEngine.exe", curaengine.bindirs[0], self.source_folder, keep_path = False) copy(self, "CuraEngine.exe", curaengine.bindirs[0], self.source_folder, keep_path = False)
copy(self, "CuraEngine", curaengine.bindirs[0], self.source_folder, keep_path = False) copy(self, "CuraEngine", curaengine.bindirs[0], self.source_folder, keep_path = False)
# Copy the external plugins that we want to bundle with Cura # Copy the external plugins that we want to bundle with Cura
if self._enterprise: if self.options.enterprise:
rmdir(self, str(self.source_path.joinpath("plugins", "NativeCADplugin"))) rmdir(self, str(Path(self.source_folder, "plugins", "NativeCADplugin")))
native_cad_plugin = self.dependencies["native_cad_plugin"].cpp_info native_cad_plugin = self.dependencies["native_cad_plugin"].cpp_info
copy(self, "*", native_cad_plugin.resdirs[0], str(self.source_path.joinpath("plugins", "NativeCADplugin")), keep_path = True) copy(self, "*", native_cad_plugin.resdirs[0], str(Path(self.source_folder, "plugins", "NativeCADplugin")), keep_path = True)
copy(self, "bundled_*.json", native_cad_plugin.resdirs[1], str(self.source_path.joinpath("resources", "bundled_packages")), keep_path = False) copy(self, "bundled_*.json", native_cad_plugin.resdirs[1], str(Path(self.source_folder, "resources", "bundled_packages")), keep_path = False)
# Copy resources of cura_binary_data # Copy resources of cura_binary_data
cura_binary_data = self.dependencies["cura_binary_data"].cpp_info cura_binary_data = self.dependencies["cura_binary_data"].cpp_info
@ -484,48 +404,38 @@ class CuraConan(ConanFile):
copy(self, "*.dylib", libdir, str(self._base_dir.joinpath("lib")), keep_path = False) copy(self, "*.dylib", libdir, str(self._base_dir.joinpath("lib")), keep_path = False)
# Copy materials (flat) # Copy materials (flat)
rmdir(self, os.path.join(self.source_folder, "resources", "materials")) rmdir(self, str(Path(self.source_folder, "resources", "materials")))
fdm_materials = self.dependencies["fdm_materials"].cpp_info fdm_materials = self.dependencies["fdm_materials"].cpp_info
copy(self, "*", fdm_materials.resdirs[0], self.source_folder) copy(self, "*", fdm_materials.resdirs[0], self.source_folder)
# Copy internal resources # Copy internal resources
if self._internal: if self.options.internal:
cura_private_data = self.dependencies["cura_private_data"].cpp_info cura_private_data = self.dependencies["cura_private_data"].cpp_info
copy(self, "*", cura_private_data.resdirs[0], str(self._share_dir.joinpath("cura"))) copy(self, "*", cura_private_data.resdirs[0], str(self._share_dir.joinpath("cura")))
if self.options.devtools: if self.options.i18n_extract:
entitlements_file = "'{}'".format(os.path.join(self.source_folder, "packaging", "MacOS", "cura.entitlements"))
self._generate_pyinstaller_spec(
location=self.generators_folder,
entrypoint_location="'{}'".format(
os.path.join(self.source_folder, self.conan_data["pyinstaller"]["runinfo"]["entrypoint"])).replace(
"\\", "\\\\"),
icon_path="'{}'".format(os.path.join(self.source_folder, "packaging",
self.conan_data["pyinstaller"]["icon"][
str(self.settings.os)])).replace("\\", "\\\\"),
entitlements_file=entitlements_file if self.settings.os == "Macos" else "None"
)
if self.options.get_safe("enable_i18n", False) and self._i18n_options["extract"]:
vb = VirtualBuildEnv(self) vb = VirtualBuildEnv(self)
vb.generate() vb.generate()
# # FIXME: once m4, autoconf, automake are Conan V2 ready use self.win_bash and add gettext as base tool_requirement pot = self.python_requires["translationextractor"].module.ExtractTranslations(self)
cpp_info = self.dependencies["gettext"].cpp_info
pot = self.python_requires["translationextractor"].module.ExtractTranslations(self, cpp_info.bindirs[0])
pot.generate() pot.generate()
def build(self): def build(self):
if self.options.get_safe("enable_i18n", False) and self._i18n_options["build"]: if self.settings.os == "Windows" and not self.conf.get("tools.microsoft.bash:path", check_type=str):
for po_file in self.source_path.joinpath("resources", "i18n").glob("**/*.po"): self.output.warning("Skipping generation of binary translation files because Bash could not be found and is required")
mo_file = Path(self.build_folder, po_file.with_suffix('.mo').relative_to(self.source_path)) return
for po_file in Path(self.source_folder, "resources", "i18n").glob("**/*.po"):
mo_file = Path(self.build_folder, po_file.with_suffix('.mo').relative_to(self.source_folder))
mo_file = mo_file.parent.joinpath("LC_MESSAGES", mo_file.name) mo_file = mo_file.parent.joinpath("LC_MESSAGES", mo_file.name)
mkdir(self, str(unix_path(self, Path(mo_file).parent))) mkdir(self, str(unix_path(self, Path(mo_file).parent)))
cpp_info = self.dependencies["gettext"].cpp_info self.run(f"msgfmt {po_file} -o {mo_file} -f", env="conanbuild")
self.run(f"{cpp_info.bindirs[0]}/msgfmt {po_file} -o {mo_file} -f", env="conanbuild", ignore_errors=True)
def deploy(self): def deploy(self):
copy(self, "*", os.path.join(self.package_folder, self.cpp.package.resdirs[2]), os.path.join(self.install_folder, "packaging"), keep_path = True) ''' Note: this deploy step is actually used to prepare for building a Cura distribution with pyinstaller, which is not
the original purpose in the Conan philosophy '''
copy(self, "*", os.path.join(self.package_folder, self.cpp.package.resdirs[2]), os.path.join(self.deploy_folder, "packaging"), keep_path = True)
# Copy resources of Cura (keep folder structure) needed by pyinstaller to determine the module structure # Copy resources of Cura (keep folder structure) needed by pyinstaller to determine the module structure
copy(self, "*", os.path.join(self.package_folder, self.cpp_info.bindirs[0]), str(self._base_dir), keep_path = False) copy(self, "*", os.path.join(self.package_folder, self.cpp_info.bindirs[0]), str(self._base_dir), keep_path = False)
@ -545,27 +455,6 @@ class CuraConan(ConanFile):
copy(self, "*", uranium.resdirs[1], str(self._share_dir.joinpath("uranium", "plugins")), keep_path = True) copy(self, "*", uranium.resdirs[1], str(self._share_dir.joinpath("uranium", "plugins")), keep_path = True)
copy(self, "*", uranium.libdirs[0], str(self._site_packages.joinpath("UM")), keep_path = True) copy(self, "*", uranium.libdirs[0], str(self._site_packages.joinpath("UM")), keep_path = True)
# Generate the GitHub Action version info Environment
version = self.conf.get("user.cura:version", default = self.version, check_type = str)
cura_version = Version(version)
env_prefix = "Env:" if self.settings.os == "Windows" else ""
activate_github_actions_version_env = Template(r"""echo "CURA_VERSION_MAJOR={{ cura_version_major }}" >> ${{ env_prefix }}GITHUB_ENV
echo "CURA_VERSION_MINOR={{ cura_version_minor }}" >> ${{ env_prefix }}GITHUB_ENV
echo "CURA_VERSION_PATCH={{ cura_version_patch }}" >> ${{ env_prefix }}GITHUB_ENV
echo "CURA_VERSION_BUILD={{ cura_version_build }}" >> ${{ env_prefix }}GITHUB_ENV
echo "CURA_VERSION_FULL={{ cura_version_full }}" >> ${{ env_prefix }}GITHUB_ENV
echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV
""").render(cura_version_major = cura_version.major,
cura_version_minor = cura_version.minor,
cura_version_patch = cura_version.patch,
cura_version_build = cura_version.build if cura_version.build != "" else "0",
cura_version_full = self.version,
cura_app_name = self._app_name,
env_prefix = env_prefix)
ext = ".sh" if self.settings.os != "Windows" else ".ps1"
save(self, os.path.join(self._script_dir, f"activate_github_actions_version_env{ext}"), activate_github_actions_version_env)
self._generate_cura_version(os.path.join(self._site_packages, "cura")) self._generate_cura_version(os.path.join(self._site_packages, "cura"))
self._delete_unwanted_binaries(self._site_packages) self._delete_unwanted_binaries(self._site_packages)
@ -573,11 +462,12 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV
self._delete_unwanted_binaries(self._base_dir) self._delete_unwanted_binaries(self._base_dir)
self._delete_unwanted_binaries(self._share_dir) self._delete_unwanted_binaries(self._share_dir)
entitlements_file = "'{}'".format(Path(self.cpp_info.res_paths[2], "MacOS", "cura.entitlements")) entitlements_file = "'{}'".format(Path(self.deploy_folder, "packaging", "MacOS", "cura.entitlements"))
self._generate_pyinstaller_spec(location = self._base_dir, self._generate_pyinstaller_spec(location = self.deploy_folder,
entrypoint_location = "'{}'".format(os.path.join(self.package_folder, self.cpp_info.bindirs[0], self.conan_data["pyinstaller"]["runinfo"]["entrypoint"])).replace("\\", "\\\\"), entrypoint_location = "'{}'".format(os.path.join(self.package_folder, self.cpp_info.bindirs[0], self.conan_data["pyinstaller"]["runinfo"]["entrypoint"])).replace("\\", "\\\\"),
icon_path = "'{}'".format(os.path.join(self.package_folder, self.cpp_info.resdirs[2], self.conan_data["pyinstaller"]["icon"][str(self.settings.os)])).replace("\\", "\\\\"), icon_path = "'{}'".format(os.path.join(self.package_folder, self.cpp_info.resdirs[2], self.conan_data["pyinstaller"]["icon"][str(self.settings.os)])).replace("\\", "\\\\"),
entitlements_file = entitlements_file if self.settings.os == "Macos" else "None") entitlements_file = entitlements_file if self.settings.os == "Macos" else "None",
cura_source_folder = self.package_folder)
def package(self): def package(self):
copy(self, "cura_app.py", src = self.source_folder, dst = os.path.join(self.package_folder, self.cpp.package.bindirs[0])) copy(self, "cura_app.py", src = self.source_folder, dst = os.path.join(self.package_folder, self.cpp.package.bindirs[0]))
@ -585,8 +475,8 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV
copy(self, "*", src = os.path.join(self.source_folder, "resources"), dst = os.path.join(self.package_folder, self.cpp.package.resdirs[0])) copy(self, "*", src = os.path.join(self.source_folder, "resources"), dst = os.path.join(self.package_folder, self.cpp.package.resdirs[0]))
copy(self, "*.mo", os.path.join(self.build_folder, "resources"), os.path.join(self.package_folder, "resources")) copy(self, "*.mo", os.path.join(self.build_folder, "resources"), os.path.join(self.package_folder, "resources"))
copy(self, "*", src = os.path.join(self.source_folder, "plugins"), dst = os.path.join(self.package_folder, self.cpp.package.resdirs[1])) copy(self, "*", src = os.path.join(self.source_folder, "plugins"), dst = os.path.join(self.package_folder, self.cpp.package.resdirs[1]))
copy(self, "requirement*.txt", src = self.source_folder, dst = os.path.join(self.package_folder, self.cpp.package.resdirs[-1]))
copy(self, "*", src = os.path.join(self.source_folder, "packaging"), dst = os.path.join(self.package_folder, self.cpp.package.resdirs[2])) copy(self, "*", src = os.path.join(self.source_folder, "packaging"), dst = os.path.join(self.package_folder, self.cpp.package.resdirs[2]))
copy(self, "pip_requirements_*.txt", src = self.generators_folder, dst = os.path.join(self.package_folder, self.cpp.package.resdirs[-1]))
# Remove the fdm_materials from the package # Remove the fdm_materials from the package
rmdir(self, os.path.join(self.package_folder, self.cpp.package.resdirs[0], "materials")) rmdir(self, os.path.join(self.package_folder, self.cpp.package.resdirs[0], "materials"))
@ -598,35 +488,8 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV
rmdir(self, os.path.join(self.package_folder, self.cpp.package.resdirs[0], Path(res_dir).name)) rmdir(self, os.path.join(self.package_folder, self.cpp.package.resdirs[0], Path(res_dir).name))
def package_info(self): def package_info(self):
self.user_info.pip_requirements = "requirements.txt"
self.user_info.pip_requirements_git = "requirements-ultimaker.txt"
self.user_info.pip_requirements_build = "requirements-dev.txt"
if self.in_local_cache:
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.package_folder, "site-packages")) self.runenv_info.append_path("PYTHONPATH", os.path.join(self.package_folder, "site-packages"))
self.env_info.PYTHONPATH.append(os.path.join(self.package_folder, "site-packages"))
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.package_folder, "plugins")) self.runenv_info.append_path("PYTHONPATH", os.path.join(self.package_folder, "plugins"))
self.env_info.PYTHONPATH.append(os.path.join(self.package_folder, "plugins"))
else:
self.runenv_info.append_path("PYTHONPATH", self.source_folder)
self.env_info.PYTHONPATH.append(self.source_folder)
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.source_folder, "plugins"))
self.env_info.PYTHONPATH.append(os.path.join(self.source_folder, "plugins"))
def package_id(self): def package_id(self):
self.info.clear() self.info.options.rm_safe("enable_i18n")
# The following options shouldn't be used to determine the hash, since these are only used to set the CuraVersion.py
# which will als be generated by the deploy method during the `conan install cura/5.1.0@_/_`
del self.info.options.enterprise
del self.info.options.staging
del self.info.options.devtools
del self.info.options.cloud_api_version
del self.info.options.display_name
del self.info.options.cura_debug_mode
if self.options.get_safe("enable_i18n", False):
del self.info.options.enable_i18n
# TODO: Use the hash of requirements.txt and requirements-ultimaker.txt, Because changing these will actually result in a different
# Cura. This is needed because the requirements.txt aren't managed by Conan and therefor not resolved in the package_id. This isn't
# ideal but an acceptable solution for now.

View File

@ -25,7 +25,8 @@ def build_dmg(source_path: str, dist_path: str, filename: str, app_name: str) ->
f"{dist_path}/{filename}", f"{dist_path}/{filename}",
f"{dist_path}/{app_name}"] f"{dist_path}/{app_name}"]
subprocess.run(arguments) print(f"Run create dmg command [{" ".join([str(arg) for arg in arguments])}]")
subprocess.run(arguments, check=True)
def build_pkg(dist_path: str, app_filename: str, component_filename: str, cura_version: str, installer_filename: str) -> None: def build_pkg(dist_path: str, app_filename: str, component_filename: str, cura_version: str, installer_filename: str) -> None:
@ -56,7 +57,8 @@ def build_pkg(dist_path: str, app_filename: str, component_filename: str, cura_v
else: else:
print("CODESIGN_IDENTITY missing. The installer is not being signed") print("CODESIGN_IDENTITY missing. The installer is not being signed")
subprocess.run(pkg_build_arguments) print(f"Run package build command [{" ".join([str(arg) for arg in pkg_build_arguments])}]")
subprocess.run(pkg_build_arguments, check=True)
# This automatically generates a distribution.xml file that is used to build the installer. # This automatically generates a distribution.xml file that is used to build the installer.
# If you want to make any changes to how the installer functions, this file should be changed to do that. # If you want to make any changes to how the installer functions, this file should be changed to do that.
@ -67,7 +69,8 @@ def build_pkg(dist_path: str, app_filename: str, component_filename: str, cura_v
"--package", Path(dist_path, component_filename), # Package that will be inside installer "--package", Path(dist_path, component_filename), # Package that will be inside installer
Path(dist_path, "distribution.xml"), # Output location for sythesized distributions file Path(dist_path, "distribution.xml"), # Output location for sythesized distributions file
] ]
subprocess.run(distribution_creation_arguments) print(f"Run distribution creation command [{" ".join([str(arg) for arg in distribution_creation_arguments])}]")
subprocess.run(distribution_creation_arguments, check=True)
# This creates the distributable package (Installer) # This creates the distributable package (Installer)
installer_creation_arguments = [ installer_creation_arguments = [
@ -80,7 +83,8 @@ def build_pkg(dist_path: str, app_filename: str, component_filename: str, cura_v
if codesign_identity: if codesign_identity:
installer_creation_arguments.extend(["--sign", codesign_identity]) installer_creation_arguments.extend(["--sign", codesign_identity])
subprocess.run(installer_creation_arguments) print(f"Run installer creation command [{" ".join([str(arg) for arg in installer_creation_arguments])}]")
subprocess.run(installer_creation_arguments, check=True)
def notarize_file(dist_path: str, filename: str) -> None: def notarize_file(dist_path: str, filename: str) -> None:
@ -99,7 +103,8 @@ def notarize_file(dist_path: str, filename: str) -> None:
Path(dist_path, filename) Path(dist_path, filename)
] ]
subprocess.run(notarize_arguments) print(f"Run notarize command [{" ".join([str(arg) for arg in notarize_arguments])}]")
subprocess.run(notarize_arguments, check=True)
def create_pkg_installer(filename: str, dist_path: str, cura_version: str, app_name: str) -> None: def create_pkg_installer(filename: str, dist_path: str, cura_version: str, app_name: str) -> None:

View File

@ -5,6 +5,7 @@
import os import os
import argparse # Command line arguments parsing and help. import argparse # Command line arguments parsing and help.
import subprocess import subprocess
import semver
import shutil import shutil
from datetime import datetime from datetime import datetime
@ -14,11 +15,12 @@ from pathlib import Path
from jinja2 import Template from jinja2 import Template
def generate_nsi(source_path: str, dist_path: str, filename: str): def generate_nsi(source_path: str, dist_path: str, filename: str, version: str):
dist_loc = Path(os.getcwd(), dist_path) dist_loc = Path(os.getcwd(), dist_path)
source_loc = Path(os.getcwd(), source_path) source_loc = Path(os.getcwd(), source_path)
instdir = Path("$INSTDIR") instdir = Path("$INSTDIR")
dist_paths = [p.relative_to(dist_loc.joinpath("UltiMaker-Cura")) for p in sorted(dist_loc.joinpath("UltiMaker-Cura").rglob("*")) if p.is_file()] dist_paths = [p.relative_to(dist_loc.joinpath("UltiMaker-Cura")) for p in sorted(dist_loc.joinpath("UltiMaker-Cura").rglob("*")) if p.is_file()]
parsed_version = semver.Version.parse(version)
mapped_out_paths = {} mapped_out_paths = {}
for dist_path in dist_paths: for dist_path in dist_paths:
if "__pycache__" not in dist_path.parts: if "__pycache__" not in dist_path.parts:
@ -42,12 +44,12 @@ def generate_nsi(source_path: str, dist_path: str, filename: str):
nsis_content = template.render( nsis_content = template.render(
app_name = f"UltiMaker Cura {os.getenv('CURA_VERSION_FULL')}", app_name = f"UltiMaker Cura {version}",
main_app = "UltiMaker-Cura.exe", main_app = "UltiMaker-Cura.exe",
version = os.getenv('CURA_VERSION_FULL'), version = version,
version_major = os.environ.get("CURA_VERSION_MAJOR"), version_major = str(parsed_version.major),
version_minor = os.environ.get("CURA_VERSION_MINOR"), version_minor = str(parsed_version.minor),
version_patch = os.environ.get("CURA_VERSION_PATCH"), version_patch = str(parsed_version.patch),
company = "UltiMaker", company = "UltiMaker",
web_site = "https://ultimaker.com", web_site = "https://ultimaker.com",
year = datetime.now().year, year = datetime.now().year,
@ -74,9 +76,10 @@ def build(dist_path: str):
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description = "Create Windows exe installer of Cura.") parser = argparse.ArgumentParser(description = "Create Windows exe installer of Cura.")
parser.add_argument("source_path", type=str, help="Path to Conan install Cura folder.") parser.add_argument("--source_path", type=str, help="Path to Conan install Cura folder.")
parser.add_argument("dist_path", type=str, help="Path to Pyinstaller dist folder") parser.add_argument("--dist_path", type=str, help="Path to Pyinstaller dist folder")
parser.add_argument("filename", type = str, help = "Filename of the exe (e.g. 'UltiMaker-Cura-5.1.0-beta-Windows-X64.exe')") parser.add_argument("--filename", type = str, help = "Filename of the exe (e.g. 'UltiMaker-Cura-5.1.0-beta-Windows-X64.exe')")
parser.add_argument("--version", type=str, help="The full cura version, e.g. 5.9.0-beta.1+24132")
args = parser.parse_args() args = parser.parse_args()
generate_nsi(args.source_path, args.dist_path, args.filename) generate_nsi(args.source_path, args.dist_path, args.filename, args.version)
build(args.dist_path) build(args.dist_path)

View File

@ -7,6 +7,7 @@ import os
import shutil import shutil
import subprocess import subprocess
import uuid import uuid
import semver
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
@ -20,11 +21,12 @@ def work_path(filename: Path) -> Path:
return filename.parent return filename.parent
def generate_wxs(source_path: Path, dist_path: Path, filename: Path, app_name: str): def generate_wxs(source_path: Path, dist_path: Path, filename: Path, app_name: str, version: str):
source_loc = Path(os.getcwd(), source_path) source_loc = Path(os.getcwd(), source_path)
dist_loc = Path(os.getcwd(), dist_path) dist_loc = Path(os.getcwd(), dist_path)
work_loc = work_path(filename) work_loc = work_path(filename)
work_loc.mkdir(parents=True, exist_ok=True) work_loc.mkdir(parents=True, exist_ok=True)
parsed_version = semver.Version.parse(version)
jinja_template_path = Path(source_loc.joinpath("packaging", "msi", "UltiMaker-Cura.wxs.jinja")) jinja_template_path = Path(source_loc.joinpath("packaging", "msi", "UltiMaker-Cura.wxs.jinja"))
with open(jinja_template_path, "r") as f: with open(jinja_template_path, "r") as f:
@ -33,10 +35,10 @@ def generate_wxs(source_path: Path, dist_path: Path, filename: Path, app_name: s
wxs_content = template.render( wxs_content = template.render(
app_name=f"{app_name}", app_name=f"{app_name}",
main_app="UltiMaker-Cura.exe", main_app="UltiMaker-Cura.exe",
version=os.getenv('CURA_VERSION_FULL'), version=version,
version_major=os.environ.get("CURA_VERSION_MAJOR"), version_major=str(parsed_version.major),
version_minor=os.environ.get("CURA_VERSION_MINOR"), version_minor=str(parsed_version.minor),
version_patch=os.environ.get("CURA_VERSION_PATCH"), version_patch=str(parsed_version.patch),
company="UltiMaker", company="UltiMaker",
web_site="https://ultimaker.com", web_site="https://ultimaker.com",
year=datetime.now().year, year=datetime.now().year,
@ -111,12 +113,13 @@ def build(dist_path: Path, filename: Path):
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Create Windows msi installer of Cura.") parser = argparse.ArgumentParser(description="Create Windows msi installer of Cura.")
parser.add_argument("source_path", type=Path, help="Path to Conan install Cura folder.") parser.add_argument("--source_path", type=Path, help="Path to Conan install Cura folder.")
parser.add_argument("dist_path", type=Path, help="Path to Pyinstaller dist folder") parser.add_argument("--dist_path", type=Path, help="Path to Pyinstaller dist folder")
parser.add_argument("filename", type=Path, parser.add_argument("--filename", type=Path,
help="Filename of the exe (e.g. 'UltiMaker-Cura-5.1.0-beta-Windows-X64.msi')") help="Filename of the exe (e.g. 'UltiMaker-Cura-5.1.0-beta-Windows-X64.msi')")
parser.add_argument("name", type=str, help="App name (e.g. 'UltiMaker Cura')") parser.add_argument("--name", type=str, help="App name (e.g. 'UltiMaker Cura')")
parser.add_argument("--version", type=str, help="The full cura version, e.g. 5.9.0-beta.1+24132")
args = parser.parse_args() args = parser.parse_args()
generate_wxs(args.source_path.resolve(), args.dist_path.resolve(), args.filename.resolve(), args.name) generate_wxs(args.source_path.resolve(), args.dist_path.resolve(), args.filename.resolve(), args.name, args.version)
cleanup_artifacts(args.dist_path.resolve()) cleanup_artifacts(args.dist_path.resolve())
build(args.dist_path.resolve(), args.filename) build(args.dist_path.resolve(), args.filename)

View File

@ -1,6 +0,0 @@
pytest
pyinstaller==6.3.0
pyinstaller-hooks-contrib
pyyaml
sip==6.5.1
jinja2

View File

@ -1 +0,0 @@
git+https://github.com/ultimaker/libcharon@master/s-line#egg=charon

View File

@ -1,398 +0,0 @@
### Direct requirements for Uranium and libCharon ###
PyQt6-sip==13.6.0 \
--hash=sha256:0dfd22cfedd87e96f9d51e0778ca2ba3dc0be83e424e9e0f98f6994d8d9c90f0 \
--hash=sha256:13885361ca2cb2f5085d50359ba61b3fabd41b139fb58f37332acbe631ef2357 \
--hash=sha256:24441032a29791e82beb7dfd76878339058def0e97fdb7c1cea517f3a0e6e96b \
--hash=sha256:2486e1588071943d4f6657ba09096dc9fffd2322ad2c30041e78ea3f037b5778 \
--hash=sha256:3075d8b325382750829e6cde6971c943352309d35768a4d4da0587459606d562 \
--hash=sha256:33ea771fe777eb0d1a2c3ef35bcc3f7a286eb3ff09cd5b2fdd3d87d1f392d7e8 \
--hash=sha256:39854dba35f8e5a4288da26ecb5f40b4c5ec1932efffb3f49d5ea435a7f37fb3 \
--hash=sha256:3bf03e130fbfd75c9c06e687b86ba375410c7a9e835e4e03285889e61dd4b0c4 \
--hash=sha256:43fb8551796030aae3d66d6e35e277494071ec6172cd182c9569ab7db268a2f5 \
--hash=sha256:58f68a48400e0b3d1ccb18090090299bad26e3aed7ccb7057c65887b79b8aeea \
--hash=sha256:5b9c6b6f9cfccb48cbb78a59603145a698fb4ffd176764d7083e5bf47631d8df \
--hash=sha256:747f6ca44af81777a2c696bd501bc4815a53ec6fc94d4e25830e10bc1391f8ab \
--hash=sha256:86a7b67c64436e32bffa9c28c9f21bf14a9faa54991520b12c3f6f435f24df7f \
--hash=sha256:8c282062125eea5baf830c6998587d98c50be7c3a817a057fb95fef647184012 \
--hash=sha256:8f9df9f7ccd8a9f0f1d36948c686f03ce1a1281543a3e636b7b7d5e086e1a436 \
--hash=sha256:98bf954103b087162fa63b3a78f30b0b63da22fd6450b610ec1b851dbb798228 \
--hash=sha256:9adf672f9114687533a74d5c2d4c03a9a929ad5ad9c3e88098a7da1a440ab916 \
--hash=sha256:a6ce80bc24618d8a41be8ca51ad9f10e8bc4296dd90ab2809573df30a23ae0e5 \
--hash=sha256:d6b5f699aaed0ac1fcd23e8fbca70d8a77965831b7c1ce474b81b1678817a49d \
--hash=sha256:fa759b6339ff7e25f9afe2a6b651b775f0a36bcb3f5fa85e81a90d3b033c83f4 \
--hash=sha256:fa7b10af7488efc5e53b41dd42c0f421bde6c2865a107af7ae259aff9d841da9
PyQt6==6.6.0 \
--hash=sha256:33655db05ac2de699320f035250c21434c77144a6a2943aca3f4c579dabc3f7b \
--hash=sha256:3ef68830a9b32050c30f7962c56a5927802c9193b68eaf405faecb8ce9ae10a8 \
--hash=sha256:d41512d66044c2df9c5f515a56a922170d68a37b3406ffddc8b4adc57181b576 \
--hash=sha256:fc7185d65755f26d7a6842492ec5398c92544dc4eafbbcbef1b1922aca585c96
PyQt6-Qt6==6.6.0 \
--hash=sha256:1b079a33088d32ff47872cdb37fd15aa42101f0be46c3340244483849b781438 \
--hash=sha256:8cb30d64a4d32465ea1686bc827cbe452225fb387c4873356b0fa7b9ae63534f \
--hash=sha256:a151f34712cd645111e89cb30b02e5fb69c9dcc3603ab3c03a561e874bd7cbcf \
--hash=sha256:e5483ae04bf107411c7469f1be9f9e2eb9840303e788b3ac524fe30af90d45f4
certifi==2023.5.7; \
--hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716
cryptography==41.0.1 \
--hash=sha256:059e348f9a3c1950937e1b5d7ba1f8e968508ab181e75fc32b879452f08356db \
--hash=sha256:1a5472d40c8f8e91ff7a3d8ac6dfa363d8e3138b961529c996f3e2df0c7a411a \
--hash=sha256:1a8e6c2de6fbbcc5e14fd27fb24414507cb3333198ea9ab1258d916f00bc3039 \
--hash=sha256:1fee5aacc7367487b4e22484d3c7e547992ed726d14864ee33c0176ae43b0d7c \
--hash=sha256:5d092fdfedaec4cbbffbf98cddc915ba145313a6fdaab83c6e67f4e6c218e6f3 \
--hash=sha256:5f0ff6e18d13a3de56f609dd1fd11470918f770c6bd5d00d632076c727d35485 \
--hash=sha256:7bfc55a5eae8b86a287747053140ba221afc65eb06207bedf6e019b8934b477c \
--hash=sha256:7fa01527046ca5facdf973eef2535a27fec4cb651e4daec4d043ef63f6ecd4ca \
--hash=sha256:8dde71c4169ec5ccc1087bb7521d54251c016f126f922ab2dfe6649170a3b8c5 \
--hash=sha256:8f4ab7021127a9b4323537300a2acfb450124b2def3756f64dc3a3d2160ee4b5 \
--hash=sha256:948224d76c4b6457349d47c0c98657557f429b4e93057cf5a2f71d603e2fc3a3 \
--hash=sha256:9a6c7a3c87d595608a39980ebaa04d5a37f94024c9f24eb7d10262b92f739ddb \
--hash=sha256:b46e37db3cc267b4dea1f56da7346c9727e1209aa98487179ee8ebed09d21e43 \
--hash=sha256:b4ceb5324b998ce2003bc17d519080b4ec8d5b7b70794cbd2836101406a9be31 \
--hash=sha256:cb33ccf15e89f7ed89b235cff9d49e2e62c6c981a6061c9c8bb47ed7951190bc \
--hash=sha256:d198820aba55660b4d74f7b5fd1f17db3aa5eb3e6893b0a41b75e84e4f9e0e4b \
--hash=sha256:d34579085401d3f49762d2f7d6634d6b6c2ae1242202e860f4d26b046e3a1006 \
--hash=sha256:eb8163f5e549a22888c18b0d53d6bb62a20510060a22fd5a995ec8a05268df8a \
--hash=sha256:f73bff05db2a3e5974a6fd248af2566134d8981fd7ab012e5dd4ddb1d9a70699
zeroconf==0.31.0 \
--hash=sha256:53a180248471c6f81bd1fffcbce03ed93d7d8eaf10905c9121ac1ea996d19844 \
--hash=sha256:5a468da018bc3f04bbce77ae247924d802df7aeb4c291bbbb5a9616d128800b0
importlib-metadata==4.10.0 \
--hash=sha256:b7cf7d3fef75f1e4c80a96ca660efbd51473d7e8f39b5ab9210febc7809012a4 \
--hash=sha256:92a8b58ce734b2a4494878e0ecf7d79ccd7a128b5fc6014c401e0b61f006f0f6
keyring==23.0.1 \
--hash=sha256:045703609dd3fccfcdb27da201684278823b72af515aedec1a8515719a038cb8 \
--hash=sha256:8f607d7d1cc502c43a932a275a56fe47db50271904513a379d39df1af277ac48
# Use Numpy wheel that is compiled with Intel optimizations (MKL). Obtained from https://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy
# We cache this at software.ultimaker.com since this website tends to remove older versions rather quickly.
https://software.ultimaker.com/cura-binary-dependencies/numpy-1.21.5+mkl-cp310-cp310-win_amd64.whl; \
sys_platform=="win32" \
--hash=sha256:fbd5d5126b730a151134d21994a951fe28df06464e0c9a2cba2a4132e542a5fc
numpy==1.21.5; \
sys_platform!="win32" \
--hash=sha256:00c9fa73a6989895b8815d98300a20ac993c49ac36c8277e8ffeaa3631c0dbbb \
--hash=sha256:025b497014bc33fc23897859350f284323f32a2fff7654697f5a5fc2a19e9939 \
--hash=sha256:08de8472d9f7571f9d51b27b75e827f5296295fa78817032e84464be8bb905bc \
--hash=sha256:1964db2d4a00348b7a60ee9d013c8cb0c566644a589eaa80995126eac3b99ced \
--hash=sha256:2a9add27d7fc0fdb572abc3b2486eb3b1395da71e0254c5552b2aad2a18b5441 \
--hash=sha256:2d8adfca843bc46ac199a4645233f13abf2011a0b2f4affc5c37cd552626f27b \
--hash=sha256:301e408a052fdcda5cdcf03021ebafc3c6ea093021bf9d1aa47c54d48bdad166 \
--hash=sha256:311283acf880cfcc20369201bd75da907909afc4666966c7895cbed6f9d2c640 \
--hash=sha256:341dddcfe3b7b6427a28a27baa59af5ad51baa59bfec3264f1ab287aa3b30b13 \
--hash=sha256:3a5098df115340fb17fc93867317a947e1dcd978c3888c5ddb118366095851f8 \
--hash=sha256:3c978544be9e04ed12016dd295a74283773149b48f507d69b36f91aa90a643e5 \
--hash=sha256:3d893b0871322eaa2f8c7072cdb552d8e2b27645b7875a70833c31e9274d4611 \
--hash=sha256:4fe6a006557b87b352c04596a6e3f12a57d6e5f401d804947bd3188e6b0e0e76 \
--hash=sha256:507c05c7a37b3683eb08a3ff993bd1ee1e6c752f77c2f275260533b265ecdb6c \
--hash=sha256:58ca1d7c8aef6e996112d0ce873ac9dfa1eaf4a1196b4ff7ff73880a09923ba7 \
--hash=sha256:61bada43d494515d5b122f4532af226fdb5ee08fe5b5918b111279843dc6836a \
--hash=sha256:69a5a8d71c308d7ef33ef72371c2388a90e3495dbb7993430e674006f94797d5 \
--hash=sha256:6a5928bc6241264dce5ed509e66f33676fc97f464e7a919edc672fb5532221ee \
--hash=sha256:7b9d6b14fc9a4864b08d1ba57d732b248f0e482c7b2ff55c313137e3ed4d8449 \
--hash=sha256:a7c4b701ca418cd39e28ec3b496e6388fe06de83f5f0cb74794fa31cfa384c02 \
--hash=sha256:a7e8f6216f180f3fd4efb73de5d1eaefb5f5a1ee5b645c67333033e39440e63a \
--hash=sha256:b545ebadaa2b878c8630e5bcdb97fc4096e779f335fc0f943547c1c91540c815 \
--hash=sha256:c293d3c0321996cd8ffe84215ffe5d269fd9d1d12c6f4ffe2b597a7c30d3e593 \
--hash=sha256:c5562bcc1a9b61960fc8950ade44d00e3de28f891af0acc96307c73613d18f6e \
--hash=sha256:ca9c23848292c6fe0a19d212790e62f398fd9609aaa838859be8459bfbe558aa \
--hash=sha256:cc1b30205d138d1005adb52087ff45708febbef0e420386f58664f984ef56954 \
--hash=sha256:dbce7adeb66b895c6aaa1fad796aaefc299ced597f6fbd9ceddb0dd735245354 \
--hash=sha256:dc4b2fb01f1b4ddbe2453468ea0719f4dbb1f5caa712c8b21bb3dd1480cd30d9 \
--hash=sha256:eed2afaa97ec33b4411995be12f8bdb95c87984eaa28d76cf628970c8a2d689a \
--hash=sha256:fc7a7d7b0ed72589fd8b8486b9b42a564f10b8762be8bd4d9df94b807af4a089
pyclipper==1.3.0.post3; \
--hash=sha256:1408461fba4985d58589fa74c59e273e8aa91d8b55c2e9a6abf966eed7562d90 \
--hash=sha256:1df7e4bce6ac68abfe926d319f52b749b7c9d5e0a6bd7112a0c7f2f908abecbc \
--hash=sha256:24b6b70114941805c14a33e9378e52d24b18791f1bfc365853d5adb33425f173 \
--hash=sha256:2b0950dada5b56a002dddccf131815a8f9b55c4df86ff6a43b7ef48a91b572aa \
--hash=sha256:2d51757df15f1721946f39016191c7d685306fc69d8a5f2933a1d22119150a1d \
--hash=sha256:341556b83ce2a5d4ee36e263e04751a9949e4161f60f0011f9500b845b25ce3c \
--hash=sha256:46b3996c8dcda562c408e653ccef8efd95a7d69400f9119df2c2cb8083d36bf8 \
--hash=sha256:5434e1e69425dc7958579b1f7bedfa8a7cce79400e1b708a42be769a165a3a2c \
--hash=sha256:5b4e0e360ebfc25d01c7e0873b27f912d1c02d99b84393d526bc01836a5fb9f4 \
--hash=sha256:60f20e96e9e055e9bb2e729fe6078969ce252c6b7b1b18d8d963e5343d99f99e \
--hash=sha256:615bece709d8c304d97089a83f8ff91ca0d2646e8fe42f2637d7cdfcf99a6e4e \
--hash=sha256:639fbc55569b94487f89261b1656e3e655d06888a582218c5432c426705d1f6f \
--hash=sha256:6748239b89a5edd00b3ce36cb5c7a177978ff3361de861fe2cc559bb2760625d \
--hash=sha256:679bfd1fd4595a3f58a706256dc6cc7179ee40fbeff4d134aa3163a9c87ca545 \
--hash=sha256:6ace0de72f252e48eda28981e24142a2b02ac17eacc3d8a2baf628671dd8cc8f \
--hash=sha256:771ba332790e88eb4aa9de2172131af25525ac23fdda789691e543962849f149 \
--hash=sha256:8fabba875314ebc751b66e571b8b0d5319c76e22051304880a552d70db2252af \
--hash=sha256:a050ec9df95e9611461adb7f86da4f066848c045d966c46e7b124593e6410e2a \
--hash=sha256:ab7e2f9b655333a37002b90bea47d77ff8d1f01293798911afa7f39217f1b71d \
--hash=sha256:b0097aef9ac8a5e10434059641fea338fb682c61993bfe65670e459ec14b4151 \
--hash=sha256:b509cfd696962683553cd6b9fc7f0baf05bff47c09fd68b085a8aea493436267 \
--hash=sha256:bad590e701eaef644899ce164631f83e39669796e552f17aef5a37238646b392 \
--hash=sha256:c586ca07c1418d4f010c6bc65215c4b193211e1b95dd8a1bd312d8207c5ccf6a \
--hash=sha256:cb5ad68b82c2aa408672444e567cea138db29790997d603525878632d61fd6ec \
--hash=sha256:cd9f0496daa9b505902848d401bfc3ffe80ee3a6863451fc6c05ceb2a45b9d8f \
--hash=sha256:da4d8f253dd8e152b3364902bed5e221165d3af4e71e2ae81eb9a9a9802089a2 \
--hash=sha256:e8d77755a00566e0f0cf48da2e42e76ff93423b55880621944f950058be3fc0e \
--hash=sha256:ebc13dbfaec1b489fc6ed92a642b8a2c7072fa2d4bc12514cc2bbeacd47c5baf \
--hash=sha256:ed5ea68bc6f3428fbf9d98f1e72e2020d763d88053cc9a9d31b2eeb49500b26f \
--hash=sha256:ee52b9d29512eb7b8b9faee6db3f8694eb6c8455785a5d2d561c40eca67b226f \
--hash=sha256:f428ecdd224ec30c1a4dbdbaac44e746cbe9a05c25627b05cc7bc2dcda235a26 \
--hash=sha256:f5f3ad171f21511813085ac549bb717bbdcc0f4da27abf6b0629438e1f23ca0b
scipy==1.9.1 \
--hash=sha256:c61b4a91a702e8e04aeb0bfc40460e1f17a640977c04dda8757efb0199c75332 \
--hash=sha256:d79da472015d0120ba9b357b28a99146cd6c17b9609403164b1a8ed149b4dfc8 \
--hash=sha256:825951b88f56765aeb6e5e38ac9d7d47407cfaaeb008d40aa1b45a2d7ea2731e \
--hash=sha256:f950a04b33e17b38ff561d5a0951caf3f5b47caa841edd772ffb7959f20a6af0 \
--hash=sha256:8cc81ac25659fec73599ccc52c989670e5ccd8974cf34bacd7b54a8d809aff1a \
--hash=sha256:8d3faa40ac16c6357aaf7ea50394ea6f1e8e99d75e927a51102b1943b311b4d9 \
--hash=sha256:7a412c476a91b080e456229e413792bbb5d6202865dae963d1e6e28c2bb58691 \
--hash=sha256:eb954f5aca4d26f468bbebcdc5448348eb287f7bea536c6306f62ea062f63d9a \
--hash=sha256:3c6f5d1d4b9a5e4fe5e14f26ffc9444fc59473bbf8d45dc4a9a15283b7063a72 \
--hash=sha256:bc4e2c77d4cd015d739e75e74ebbafed59ba8497a7ed0fd400231ed7683497c4 \
--hash=sha256:0419485dbcd0ed78c0d5bf234c5dd63e86065b39b4d669e45810d42199d49521 \
--hash=sha256:34441dfbee5b002f9e15285014fd56e5e3372493c3e64ae297bae2c4b9659f5a \
--hash=sha256:b97b479f39c7e4aaf807efd0424dec74bbb379108f7d22cf09323086afcd312c \
--hash=sha256:e8fe305d9d67a81255e06203454729405706907dccbdfcc330b7b3482a6c371d \
--hash=sha256:39ab9240cd215a9349c85ab908dda6d732f7d3b4b192fa05780812495536acc4 \
--hash=sha256:71487c503e036740635f18324f62a11f283a632ace9d35933b2b0a04fd898c98 \
--hash=sha256:3bc1ab68b9a096f368ba06c3a5e1d1d50957a86665fc929c4332d21355e7e8f4 \
--hash=sha256:f7c39f7dbb57cce00c108d06d731f3b0e2a4d3a95c66d96bce697684876ce4d4 \
--hash=sha256:47d1a95bd9d37302afcfe1b84c8011377c4f81e33649c5a5785db9ab827a6ade \
--hash=sha256:96d7cf7b25c9f23c59a766385f6370dab0659741699ecc7a451f9b94604938ce \
--hash=sha256:09412eb7fb60b8f00b328037fd814d25d261066ebc43a1e339cdce4f7502877e \
--hash=sha256:90c805f30c46cf60f1e76e947574f02954d25e3bb1e97aa8a07bc53aa31cf7d1 \
--hash=sha256:26d28c468900e6d5fdb37d2812ab46db0ccd22c63baa095057871faa3a498bc9
trimesh==3.9.36 \
--hash=sha256:f01e8edab14d1999700c980c21a1546f37417216ad915a53be649d263130181e \
--hash=sha256:8ac8bea693b3ee119f11b022fc9b9481c9f1af06cb38bc859bf5d16bbbe49b23
sentry-sdk==0.13.5 \
--hash=sha256:05285942901d38c7ce2498aba50d8e87b361fc603281a5902dda98f3f8c5e145 \
--hash=sha256:c6b919623e488134a728f16326c6f0bcdab7e3f59e7f4c472a90eea4d6d8fe82
mypy==0.931 \
--hash=sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce \
--hash=sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d \
--hash=sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069 \
--hash=sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c \
--hash=sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d \
--hash=sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714 \
--hash=sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a \
--hash=sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d \
--hash=sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05 \
--hash=sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266 \
--hash=sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697 \
--hash=sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc \
--hash=sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799 \
--hash=sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd \
--hash=sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00 \
--hash=sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7 \
--hash=sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a \
--hash=sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0 \
--hash=sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0 \
--hash=sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166
pyserial==3.4 \
--hash=sha256:6e2d401fdee0eab996cf734e67773a0143b932772ca8b42451440cfed942c627 \
--hash=sha256:e0770fadba80c31013896c7e6ef703f72e7834965954a78e71a3049488d4d7d8
### Indirect requirements ###
chardet==3.0.4 \
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae \
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
idna==2.8 \
--hash=sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407 \
--hash=sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c
attrs==21.3.0 \
--hash=sha256:8f7335278dedd26b58c38e006338242cc0977f06d51579b2b8b87b9b33bff66c \
--hash=sha256:50f3c9b216dc9021042f71b392859a773b904ce1a029077f58f6598272432045
requests==2.22.0 \
--hash=sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4 \
--hash=sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31
# twisted
Twisted==21.2.0 \
--hash=sha256:77544a8945cf69b98d2946689bbe0c75de7d145cdf11f391dd487eae8fc95a12 \
--hash=sha256:aab38085ea6cda5b378b519a0ec99986874921ee8881318626b0a3414bb2631e
constantly==15.1.0 \
--hash=sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35 \
--hash=sha256:dd2fa9d6b1a51a83f0d7dd76293d734046aa176e384bf6e33b7e44880eb37c5d
hyperlink==21.0.0 \
--hash=sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b \
--hash=sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4
incremental==22.10.0 \
--hash=sha256:b864a1f30885ee72c5ac2835a761b8fe8aa9c28b9395cacf27286602688d3e51 \
--hash=sha256:912feeb5e0f7e0188e6f42241d2f450002e11bbc0937c65865045854c24c0bd0
zope.interface==5.4.0 \
--hash=sha256:0f91b5b948686659a8e28b728ff5e74b1be6bf40cb04704453617e5f1e945ef3 \
--hash=sha256:3c02411a3b62668200910090a0dff17c0b25aaa36145082a5a6adf08fa281e54 \
--hash=sha256:5dba5f530fec3f0988d83b78cc591b58c0b6eb8431a85edd1569a0539a8a5a0e \
--hash=sha256:bf68f4b2b6683e52bec69273562df15af352e5ed25d1b6641e7efddc5951d1a7 \
--hash=sha256:db1fa631737dab9fa0b37f3979d8d2631e348c3b4e8325d6873c2541d0ae5a48 \
--hash=sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4
Automat==20.2.0 \
--hash=sha256:7979803c74610e11ef0c0d68a2942b152df52da55336e0c9d58daf1831cbdf33 \
--hash=sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111
twisted-iocpsupport==1.0.2; \
sys_platform=="win32" \
--hash=sha256:306becd6e22ab6e8e4f36b6bdafd9c92e867c98a5ce517b27fdd27760ee7ae41 \
--hash=sha256:3c61742cb0bc6c1ac117a7e5f422c129832f0c295af49e01d8a6066df8cfc04d \
--hash=sha256:72068b206ee809c9c596b57b5287259ea41ddb4774d86725b19f35bf56aa32a9 \
--hash=sha256:7d972cfa8439bdcb35a7be78b7ef86d73b34b808c74be56dfa785c8a93b851bf \
--hash=sha256:81b3abe3527b367da0220482820cb12a16c661672b7bcfcde328902890d63323 \
--hash=sha256:851b3735ca7e8102e661872390e3bce88f8901bece95c25a0c8bb9ecb8a23d32 \
--hash=sha256:985c06a33f5c0dae92c71a036d1ea63872ee86a21dd9b01e1f287486f15524b4 \
--hash=sha256:9dbb8823b49f06d4de52721b47de4d3b3026064ef4788ce62b1a21c57c3fff6f \
--hash=sha256:b435857b9efcbfc12f8c326ef0383f26416272260455bbca2cd8d8eca470c546 \
--hash=sha256:b76b4eed9b27fd63ddb0877efdd2d15835fdcb6baa745cb85b66e5d016ac2878 \
--hash=sha256:b9fed67cf0f951573f06d560ac2f10f2a4bbdc6697770113a2fc396ea2cb2565 \
--hash=sha256:bf4133139d77fc706d8f572e6b7d82871d82ec7ef25d685c2351bdacfb701415
numpy-stl==2.10.1 \
--hash=sha256:f6b529b8a8112dfe456d4f7697c7aee0aca62be5a873879306afe4b26fca963c
python-utils==2.3.0 \
--hash=sha256:34aaf26b39b0b86628008f2ae0ac001b30e7986a8d303b61e1357dfcdad4f6d3 \
--hash=sha256:e25f840564554eaded56eaa395bca507b0b9e9f0ae5ecb13a8cb785305c56d25
six==1.12.0 \
--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c \
--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73
shapely==2.0.1 \
--hash=sha256:01224899ff692a62929ef1a3f5fe389043e262698a708ab7569f43a99a48ae82 \
--hash=sha256:05c51a29336e604c084fb43ae5dbbfa2c0ef9bd6fedeae0a0d02c7b57a56ba46 \
--hash=sha256:09d6c7763b1bee0d0a2b84bb32a4c25c6359ad1ac582a62d8b211e89de986154 \
--hash=sha256:193a398d81c97a62fc3634a1a33798a58fd1dcf4aead254d080b273efbb7e3ff \
--hash=sha256:1a34a23d6266ca162499e4a22b79159dc0052f4973d16f16f990baa4d29e58b6 \
--hash=sha256:2569a4b91caeef54dd5ae9091ae6f63526d8ca0b376b5bb9fd1a3195d047d7d4 \
--hash=sha256:33403b8896e1d98aaa3a52110d828b18985d740cc9f34f198922018b1e0f8afe \
--hash=sha256:3ad81f292fffbd568ae71828e6c387da7eb5384a79db9b4fde14dd9fdeffca9a \
--hash=sha256:3cb256ae0c01b17f7bc68ee2ffdd45aebf42af8992484ea55c29a6151abe4386 \
--hash=sha256:45b4833235b90bc87ee26c6537438fa77559d994d2d3be5190dd2e54d31b2820 \
--hash=sha256:4641325e065fd3e07d55677849c9ddfd0cf3ee98f96475126942e746d55b17c8 \
--hash=sha256:502e0a607f1dcc6dee0125aeee886379be5242c854500ea5fd2e7ac076b9ce6d \
--hash=sha256:66a6b1a3e72ece97fc85536a281476f9b7794de2e646ca8a4517e2e3c1446893 \
--hash=sha256:70a18fc7d6418e5aea76ac55dce33f98e75bd413c6eb39cfed6a1ba36469d7d4 \
--hash=sha256:7d3bbeefd8a6a1a1017265d2d36f8ff2d79d0162d8c141aa0d37a87063525656 \
--hash=sha256:83a8ec0ee0192b6e3feee9f6a499d1377e9c295af74d7f81ecba5a42a6b195b7 \
--hash=sha256:865bc3d7cc0ea63189d11a0b1120d1307ed7a64720a8bfa5be2fde5fc6d0d33f \
--hash=sha256:90cfa4144ff189a3c3de62e2f3669283c98fb760cfa2e82ff70df40f11cadb39 \
--hash=sha256:91575d97fd67391b85686573d758896ed2fc7476321c9d2e2b0c398b628b961c \
--hash=sha256:9a6ac34c16f4d5d3c174c76c9d7614ec8fe735f8f82b6cc97a46b54f386a86bf \
--hash=sha256:a529218e72a3dbdc83676198e610485fdfa31178f4be5b519a8ae12ea688db14 \
--hash=sha256:a70a614791ff65f5e283feed747e1cc3d9e6c6ba91556e640636bbb0a1e32a71 \
--hash=sha256:ac1dfc397475d1de485e76de0c3c91cc9d79bd39012a84bb0f5e8a199fc17bef \
--hash=sha256:b06d031bc64149e340448fea25eee01360a58936c89985cf584134171e05863f \
--hash=sha256:b4f0711cc83734c6fad94fc8d4ec30f3d52c1787b17d9dca261dc841d4731c64 \
--hash=sha256:b50c401b64883e61556a90b89948297f1714dbac29243d17ed9284a47e6dd731 \
--hash=sha256:b519cf3726ddb6c67f6a951d1bb1d29691111eaa67ea19ddca4d454fbe35949c \
--hash=sha256:bca57b683e3d94d0919e2f31e4d70fdfbb7059650ef1b431d9f4e045690edcd5 \
--hash=sha256:c43755d2c46b75a7b74ac6226d2cc9fa2a76c3263c5ae70c195c6fb4e7b08e79 \
--hash=sha256:c7eed1fb3008a8a4a56425334b7eb82651a51f9e9a9c2f72844a2fb394f38a6c \
--hash=sha256:c8b0d834b11be97d5ab2b4dceada20ae8e07bcccbc0f55d71df6729965f406ad \
--hash=sha256:ce88ec79df55430e37178a191ad8df45cae90b0f6972d46d867bf6ebbb58cc4d \
--hash=sha256:d173d24e85e51510e658fb108513d5bc11e3fd2820db6b1bd0522266ddd11f51 \
--hash=sha256:d8f55f355be7821dade839df785a49dc9f16d1af363134d07eb11e9207e0b189 \
--hash=sha256:da71de5bf552d83dcc21b78cc0020e86f8d0feea43e202110973987ffa781c21 \
--hash=sha256:e55698e0ed95a70fe9ff9a23c763acfe0bf335b02df12142f74e4543095e9a9b \
--hash=sha256:f32a748703e7bf6e92dfa3d2936b2fbfe76f8ce5f756e24f49ef72d17d26ad02 \
--hash=sha256:f470a130d6ddb05b810fc1776d918659407f8d025b7f56d2742a596b6dffa6c7
cython==0.29.26 \
--hash=sha256:af377d543a762867da11fcf6e558f7a4a535ff8693f30cce123fab10c00fa312 \
--hash=sha256:f5e15ff892c8afad64931ee3dd723c4755c2c516606f9aae7613bebfac62b0f6 \
--hash=sha256:2b834ff6e4d10ba6d7a0d676dd71c1b427a181ddbbbbf79e91d1861557aab59f \
--hash=sha256:c813799d533194b7d85203d881d8b4f567a8c644a67f50d47f1ffbf316df412f \
--hash=sha256:6773cce9d4b3b6168d8feb2b6f06b658ef1e11cbfec075041745666d8e2a5e45 \
--hash=sha256:362fbb9cb4627c7786231429768b54aaba5459a2a0e46c25e59f202ca6155437
pybind11==2.6.2 \
--hash=sha256:2d8aebe1709bc367e34e3b23d8eccbf3f387ee9d5640548c6260d33b59f02405 \
--hash=sha256:d0e0aed9279656f21501243b707eb6e3b951e89e10c3271dedf3ae41c365e5ed
wheel==0.37.1 \
--hash=sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4 \
--hash=sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a
setuptools==62.0.0 \
--hash=sha256:7999cbd87f1b6e1f33bf47efa368b224bed5e27b5ef2c4d46580186cbcb1a86a \
--hash=sha256:a65e3802053e99fc64c6b3b29c11132943d5b8c8facbcc461157511546510967
ifaddr==0.1.7 \
--hash=sha256:1f9e8a6ca6f16db5a37d3356f07b6e52344f6f9f7e806d618537731669eb1a94 \
--hash=sha256:d1f603952f0a71c9ab4e705754511e4e03b02565bc4cec7188ad6415ff534cd3
pycparser==2.20 \
--hash=sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0 \
--hash=sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705
zipp==3.5.0 \
--hash=sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3 \
--hash=sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4
cffi==1.15.0 \
--hash=sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3 \
--hash=sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2 \
--hash=sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636 \
--hash=sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20 \
--hash=sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728 \
--hash=sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27 \
--hash=sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66 \
--hash=sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443 \
--hash=sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0 \
--hash=sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7 \
--hash=sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39 \
--hash=sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605 \
--hash=sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a \
--hash=sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37 \
--hash=sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029 \
--hash=sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139 \
--hash=sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc \
--hash=sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df \
--hash=sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14 \
--hash=sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880 \
--hash=sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2 \
--hash=sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a \
--hash=sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e \
--hash=sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474 \
--hash=sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024 \
--hash=sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8 \
--hash=sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0 \
--hash=sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e \
--hash=sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a \
--hash=sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e \
--hash=sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032 \
--hash=sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6 \
--hash=sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e \
--hash=sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b \
--hash=sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e \
--hash=sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954 \
--hash=sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962 \
--hash=sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c \
--hash=sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4 \
--hash=sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55 \
--hash=sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962 \
--hash=sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023 \
--hash=sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c \
--hash=sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6 \
--hash=sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8 \
--hash=sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382 \
--hash=sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7 \
--hash=sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc \
--hash=sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997 \
--hash=sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796
urllib3==1.25.9 \
--hash=sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527 \
--hash=sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115
mypy-extensions==0.4.3 \
--hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \
--hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8
tomli==2.0.1 \
--hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
--hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
typing-extensions==3.10.0.2 \
--hash=sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e \
--hash=sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34
jeepney==0.7.1; \
--hash=sha256:1b5a0ea5c0e7b166b2f5895b91a08c14de8915afda4407fb5022a195224958ac \
--hash=sha256:fa9e232dfa0c498bd0b8a3a73b8d8a31978304dcef0515adc859d4e096f96f4f
SecretStorage==3.3.3 \
--hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \
--hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99
keyring==23.0.1 \
--hash=sha256:045703609dd3fccfcdb27da201684278823b72af515aedec1a8515719a038cb8 \
--hash=sha256:8f607d7d1cc502c43a932a275a56fe47db50271904513a379d39df1af277ac48
networkx==2.6.2 \
--hash=sha256:2306f1950ce772c5a59a57f5486d59bb9cab98497c45fc49cbc45ac0dec119bb \
--hash=sha256:5fcb7004be69e8fbdf07dcb502efa5c77cadcaad6982164134eeb9721f826c2e
pywin32==303; \
sys_platform=="win32" \
--hash=sha256:51cb52c5ec6709f96c3f26e7795b0bf169ee0d8395b2c1d7eb2c029a5008ed51
pywin32-ctypes==0.2.0; \
sys_platform=="win32" \
--hash=sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942 \
--hash=sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98
charset-normalizer==2.1.0; \
--hash=sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5

View File

@ -5,7 +5,7 @@ from conan.tools.files import copy, update_conandata
from conan.tools.scm import Version from conan.tools.scm import Version
from conan.errors import ConanInvalidConfiguration from conan.errors import ConanInvalidConfiguration
required_conan_version = ">=1.58.0 <2.0.0" required_conan_version = ">=2.7.0"
class CuraResource(ConanFile): class CuraResource(ConanFile):
@ -15,9 +15,8 @@ class CuraResource(ConanFile):
url = "https://github.com/Ultimaker/cura" url = "https://github.com/Ultimaker/cura"
description = "Cura Resources" description = "Cura Resources"
topics = ("conan", "cura") topics = ("conan", "cura")
settings = "os", "compiler", "build_type", "arch"
no_copy_source = True no_copy_source = True
package_type = "shared-library"
@property @property
def _shared_resources(self): def _shared_resources(self):
@ -37,10 +36,6 @@ class CuraResource(ConanFile):
copy(self, pattern="*", src=os.path.join(self.recipe_folder, shared_resources), copy(self, pattern="*", src=os.path.join(self.recipe_folder, shared_resources),
dst=os.path.join(self.export_sources_folder, shared_resources)) dst=os.path.join(self.export_sources_folder, shared_resources))
def validate(self):
if Version(self.version) <= Version("4"):
raise ConanInvalidConfiguration("Only versions 5+ are support")
def layout(self): def layout(self):
self.cpp.source.resdirs = self._shared_resources self.cpp.source.resdirs = self._shared_resources
self.cpp.package.resdirs = [f"res/{res}" for res in self._shared_resources] self.cpp.package.resdirs = [f"res/{res}" for res in self._shared_resources]
@ -54,9 +49,6 @@ class CuraResource(ConanFile):
self.runenv_info.append_path("CURA_RESOURCES", os.path.join(self.package_folder, "res")) self.runenv_info.append_path("CURA_RESOURCES", os.path.join(self.package_folder, "res"))
self.runenv_info.append_path("CURA_ENGINE_SEARCH_PATH", os.path.join(self.package_folder, "res", "definitions")) self.runenv_info.append_path("CURA_ENGINE_SEARCH_PATH", os.path.join(self.package_folder, "res", "definitions"))
self.runenv_info.append_path("CURA_ENGINE_SEARCH_PATH", os.path.join(self.package_folder, "res", "extruders")) self.runenv_info.append_path("CURA_ENGINE_SEARCH_PATH", os.path.join(self.package_folder, "res", "extruders"))
self.env_info.CURA_RESOURCES.append(os.path.join(self.package_folder, "res"))
self.env_info.CURA_ENGINE_SEARCH_PATH.append(os.path.join(self.package_folder, "res", "definitions"))
self.env_info.CURA_ENGINE_SEARCH_PATH.append(os.path.join(self.package_folder, "res", "definitions"))
def package_id(self): def package_id(self):
self.info.clear() self.info.clear()

22
scripts/get_pypi_hashes.py Executable file
View File

@ -0,0 +1,22 @@
import requests
import argparse
from pathlib import Path
def get_package_wheel_hashes(package, version):
url = f"https://pypi.org/pypi/{package}/{version}/json"
data = requests.get(url).json()
print(f" {package}:")
print(f" version: \"{version}\"")
print(f" hashes:")
for url in data["urls"]:
print(f" - sha256:{url['digests']['sha256']}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Display the hashes of the wheel files to be inserted in pip_requirements")
parser.add_argument("package", type=Path, help="Name of the target package")
parser.add_argument("version", type=Path, help="Version of the target package")
args = parser.parse_args()
get_package_wheel_hashes(args.package, args.version)

View File

@ -80,12 +80,12 @@ def test_errorLoginState(application):
with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance"): # Don't want triggers for account information to actually make HTTP requests. with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance"): # Don't want triggers for account information to actually make HTTP requests.
account._onLoginStateChanged(True, "BLARG!") account._onLoginStateChanged(True, "BLARG!")
# Even though we said that the login worked, it had an error message, so the login failed. # Even though we said that the login worked, it had an error message, so the login failed.
account.loginStateChanged.emit.called_with(False) account.loginStateChanged.emit.assert_called_with(False)
with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance"): with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance"):
account._onLoginStateChanged(True) account._onLoginStateChanged(True)
account._onLoginStateChanged(False, "OMGZOMG!") account._onLoginStateChanged(False, "OMGZOMG!")
account.loginStateChanged.emit.called_with(False) account.loginStateChanged.emit.assert_called_with(False)
def test_sync_success(): def test_sync_success():
account = Account(MagicMock()) account = Account(MagicMock())

View File

@ -50,9 +50,10 @@ def quality_changes_container():
def test_createMachineWithUnknownDefinition(application, container_registry): def test_createMachineWithUnknownDefinition(application, container_registry):
application.getContainerRegistry = MagicMock(return_value=container_registry) application.getContainerRegistry = MagicMock(return_value=container_registry)
with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=application)): with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=application)):
with patch("UM.ConfigurationErrorMessage.ConfigurationErrorMessage.getInstance") as mocked_config_error: mocked_config_error = MagicMock()
with patch("UM.ConfigurationErrorMessage.ConfigurationErrorMessage.getInstance", MagicMock(return_value=mocked_config_error)):
assert CuraStackBuilder.createMachine("Whatever", "NOPE") is None assert CuraStackBuilder.createMachine("Whatever", "NOPE") is None
assert mocked_config_error.addFaultyContainers.called_with("NOPE") mocked_config_error.addFaultyContainers.assert_called_once_with("NOPE")
def test_createMachine(application, container_registry, definition_container, global_variant, material_instance_container, def test_createMachine(application, container_registry, definition_container, global_variant, material_instance_container,

View File

@ -3,6 +3,7 @@
from datetime import datetime from datetime import datetime
from unittest.mock import MagicMock, Mock, patch from unittest.mock import MagicMock, Mock, patch
from pytest import fixture
from PyQt6.QtGui import QDesktopServices from PyQt6.QtGui import QDesktopServices
from PyQt6.QtNetwork import QNetworkReply from PyQt6.QtNetwork import QNetworkReply
@ -59,6 +60,17 @@ NO_REFRESH_AUTH_RESPONSE = AuthenticationResponse(
MALFORMED_AUTH_RESPONSE = AuthenticationResponse(success=False) MALFORMED_AUTH_RESPONSE = AuthenticationResponse(success=False)
@fixture
def http_request_manager():
mock_reply = Mock() # The user profile that the service should respond with.
mock_reply.error = Mock(return_value=QNetworkReply.NetworkError.NoError)
http_mock = Mock()
http_mock.get = lambda url, headers_dict, callback, error_callback, timeout: callback(mock_reply)
http_mock.readJSON = Mock(return_value={"data": {"user_id": "id_ego_or_superego", "username": "Ghostkeeper"}})
http_mock.setDelayRequests = Mock()
return http_mock
def test_cleanAuthService() -> None: def test_cleanAuthService() -> None:
""" """
Ensure that when setting up an AuthorizationService, no data is set. Ensure that when setting up an AuthorizationService, no data is set.
@ -72,18 +84,20 @@ def test_cleanAuthService() -> None:
assert authorization_service.getAccessToken() is None assert authorization_service.getAccessToken() is None
def test_refreshAccessTokenSuccess(): def test_refreshAccessTokenSuccess(http_request_manager):
authorization_service = AuthorizationService(OAUTH_SETTINGS, Preferences()) authorization_service = AuthorizationService(OAUTH_SETTINGS, Preferences())
authorization_service.initialize() authorization_service.initialize()
with patch.object(AuthorizationService, "getUserProfile", return_value=UserProfile()): with patch.object(AuthorizationService, "getUserProfile", return_value=UserProfile()):
authorization_service._storeAuthData(SUCCESSFUL_AUTH_RESPONSE) authorization_service._storeAuthData(SUCCESSFUL_AUTH_RESPONSE)
authorization_service.onAuthStateChanged.emit = MagicMock() authorization_service.onAuthStateChanged.emit = MagicMock()
with patch.object(AuthorizationHelpers, "getAccessTokenUsingRefreshToken", return_value=SUCCESSFUL_AUTH_RESPONSE): with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance", MagicMock(return_value=http_request_manager)):
with patch.object(AuthorizationService, "getUserProfile", return_value=UserProfile()):
with patch.object(AuthorizationHelpers, "getAccessTokenUsingRefreshToken", side_effect=lambda refresh_token, callback: callback(SUCCESSFUL_AUTH_RESPONSE)):
authorization_service.refreshAccessToken() authorization_service.refreshAccessToken()
assert authorization_service.onAuthStateChanged.emit.called_with(True) authorization_service.onAuthStateChanged.emit.assert_called_once_with(logged_in = True)
def test__parseJWTNoRefreshToken(): def test__parseJWTNoRefreshToken(http_request_manager):
""" """
Tests parsing the user profile if there is no refresh token stored, but there is a normal authentication token. Tests parsing the user profile if there is no refresh token stored, but there is a normal authentication token.
@ -94,13 +108,8 @@ def test__parseJWTNoRefreshToken():
authorization_service._storeAuthData(NO_REFRESH_AUTH_RESPONSE) authorization_service._storeAuthData(NO_REFRESH_AUTH_RESPONSE)
mock_callback = Mock() # To log the final profile response. mock_callback = Mock() # To log the final profile response.
mock_reply = Mock() # The user profile that the service should respond with.
mock_reply.error = Mock(return_value = QNetworkReply.NetworkError.NoError)
http_mock = Mock()
http_mock.get = lambda url, headers_dict, callback, error_callback, timeout: callback(mock_reply)
http_mock.readJSON = Mock(return_value = {"data": {"user_id": "id_ego_or_superego", "username": "Ghostkeeper"}})
with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance", MagicMock(return_value = http_mock)): with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance", MagicMock(return_value = http_request_manager)):
authorization_service._parseJWT(mock_callback) authorization_service._parseJWT(mock_callback)
mock_callback.assert_called_once() mock_callback.assert_called_once()
profile_reply = mock_callback.call_args_list[0][0][0] profile_reply = mock_callback.call_args_list[0][0][0]
@ -175,9 +184,10 @@ def test_refreshAccessTokenFailed():
""" """
authorization_service = AuthorizationService(OAUTH_SETTINGS, Preferences()) authorization_service = AuthorizationService(OAUTH_SETTINGS, Preferences())
authorization_service.initialize() authorization_service.initialize()
with patch.object(AuthorizationService, "getUserProfile", return_value=UserProfile()):
authorization_service._storeAuthData(SUCCESSFUL_AUTH_RESPONSE)
authorization_service.onAuthStateChanged.emit = MagicMock()
def mock_refresh(self, refresh_token, callback): # Refreshing gives a valid token.
callback(FAILED_AUTH_RESPONSE)
mock_reply = Mock() # The response that the request should give, containing an error about it failing to authenticate. mock_reply = Mock() # The response that the request should give, containing an error about it failing to authenticate.
mock_reply.error = Mock(return_value = QNetworkReply.NetworkError.AuthenticationRequiredError) # The reply is 403: Authentication required, meaning the server responded with a "Can't do that, Dave". mock_reply.error = Mock(return_value = QNetworkReply.NetworkError.AuthenticationRequiredError) # The reply is 403: Authentication required, meaning the server responded with a "Can't do that, Dave".
http_mock = Mock() http_mock = Mock()
@ -187,10 +197,9 @@ def test_refreshAccessTokenFailed():
with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.readJSON", Mock(return_value = {"error_description": "Mock a failed request!"})): with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.readJSON", Mock(return_value = {"error_description": "Mock a failed request!"})):
with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance", MagicMock(return_value = http_mock)): with patch("UM.TaskManagement.HttpRequestManager.HttpRequestManager.getInstance", MagicMock(return_value = http_mock)):
authorization_service._storeAuthData(SUCCESSFUL_AUTH_RESPONSE) authorization_service._storeAuthData(SUCCESSFUL_AUTH_RESPONSE)
authorization_service.onAuthStateChanged.emit = MagicMock() with patch("cura.OAuth2.AuthorizationHelpers.AuthorizationHelpers.getAccessTokenUsingRefreshToken", side_effect=lambda refresh_token, callback: callback(FAILED_AUTH_RESPONSE)):
with patch("cura.OAuth2.AuthorizationHelpers.AuthorizationHelpers.getAccessTokenUsingRefreshToken", mock_refresh):
authorization_service.refreshAccessToken() authorization_service.refreshAccessToken()
assert authorization_service.onAuthStateChanged.emit.called_with(False) authorization_service.onAuthStateChanged.emit.assert_called_with(logged_in = False)
def test_refreshAccesTokenWithoutData(): def test_refreshAccesTokenWithoutData():
authorization_service = AuthorizationService(OAUTH_SETTINGS, Preferences()) authorization_service = AuthorizationService(OAUTH_SETTINGS, Preferences())