Compare commits

...

41 Commits

Author SHA1 Message Date
Jedd Morgan 8497d0c195 Merge pull request #144 from specklesystems/jrm/ifc/fix
fixed IFC commits with empty lists
2023-01-20 17:00:04 +00:00
Jedd Morgan 1ce394c08f fixed issue with IFC commits with empty lists 2023-01-20 15:31:44 +00:00
Jedd Morgan aabbf87dda fix(ci): signing cert for iss 2023-01-16 17:12:39 +00:00
Jedd Morgan 7e31787d37 Updated config.yml 2023-01-16 16:29:13 +00:00
Jedd Morgan f1259587fd Bumped speckle py to 2.11.4 2023-01-16 15:00:10 +00:00
Jedd Morgan 7f913e3af0 Merge pull request #141 from specklesystems/gergo/ciContextUpdate
clone ci tools with ssh, use circleci context for env vars
2023-01-16 13:42:24 +00:00
Jedd Morgan 5433c34a4d Merge pull request #140 from specklesystems/jrm/manual-installer
Manual Installer
2023-01-16 13:39:50 +00:00
Alan Rynne 2c52e93660 ci: Updated github actions to use new actions repo 2023-01-09 20:41:22 +01:00
Gergő Jedlicska 3c3b24cf98 use innosetup context in the windows build 2023-01-06 14:01:56 +01:00
Gergő Jedlicska 3012b0ebcb clone ci tools with ssh, use circleci context for env vars 2023-01-06 12:17:19 +01:00
Jedd Morgan e3eb29daa4 fiX(ci): fixed mistake in manual installer ci 2022-12-15 14:17:29 +00:00
Jedd Morgan 3359c8f275 feat(ci): Added manual instaler deploy 2022-12-14 17:01:45 +00:00
Gergő Jedlicska cfc5007d00 update tag fiter for numbered alpha and beta 2022-12-14 11:20:00 +01:00
Jedd Morgan 0a630457be Jrm/accounts reload (#138)
* add new installer mechanism

* ci(circleci): add new package connector step

* ci(circleci): install dependencies before packaging

* chore(deps): remove local specklepy dep

* chore(deps): relock again

* feat(connector): Added reload operation to user account selection

* Zero restart installation

Co-authored-by: Gergő Jedlicska <gergo@jedlicska.com>
2022-12-14 11:09:57 +01:00
Gergő Jedlicska fa124c2312 gergo/newInstaller (#136)
* add new installer mechanism

* ci(circleci): add new package connector step

* ci(circleci): install dependencies before packaging

* chore(deps): remove local specklepy dep

* chore(deps): relock again

* ci(circleci): rewrite full ci WIP

* fix(installer): ensure pip call was commented outy

* ci(circleci): updates

* ci(circleci): fix naming

* ci(circleci): update filters

* ci(circleci): update semver location

* ci(circleci): update dependency graph

* getting the specific installer branch

* get proper ci tools

* force remove new lines from installer tags

* fix installer patch pathing

* properly saving packaged zip

* add python to dotnet installer

* add zip again

* only zip the published isntaller

* publish only usefull stuff

* ci(circleci): update details in deploy

* ci(circleci): fix filters

* ci(cirleci): fix mac  build triggers

* make sure semver is set

* ci(circleci): fix env var restore in deploy

* ci(circleci): fix missing semver in files

* ci(circleci): wtf is microsoft doing with env vars in net6 containers?

* ci(circleci): fix persist to workspace pathing

* fix zipping dir

* mkdir for the zip folder

* mkdir -p

* force copy

* copy 101

* mkdir 101

* top level cp operation

* pipe the zip

* no CD

* only parameter

* build for osx 13 for arm

* moving back to a mac build machine

* fixc arm mac runtime

* remove old linux installer build

* allow alpha numbered version

* remove ci tools branch
2022-12-14 10:55:44 +01:00
Jedd Morgan b1481bd259 Merge pull request #135 from specklesystems/jrm/2.10-fixes
Jrm/2.10 fixes
2022-11-30 20:40:01 +00:00
Jedd Morgan e19fc9ef4e fix(deployment): potential fix for mac releases 2022-11-30 20:38:43 +00:00
Jedd Morgan 448eb856b2 Bumped dependencies 2022-11-30 20:36:07 +00:00
Jedd Morgan 06a7d416c7 Merge pull request #134 from specklesystems/jrm/2.10-fixes
fix(converter): fixed issue with meshes with very high number of vert…
2022-11-30 20:32:42 +00:00
Jedd Morgan 0753436899 fix(converter): fixed issue with meshes with very high number of verts taking an eternity to send
Changed from using sum to extend list functions
2022-11-29 23:54:28 +00:00
Jedd Morgan 40e0a49b11 Merge pull request #130 from specklesystems/jrm/clean-mesh-fix
fix(receive): Fixed issue with Clean Mesh creating duplicated collection
2022-11-17 16:05:56 +00:00
JR-Morgan b17b9c9de4 fix(receive): Fixed issue with Clean Mesh creating duplicated collection 2022-11-17 14:45:17 +00:00
Jedd Morgan f035111ffa Merge pull request #128 from specklesystems/fix-py39
Fixed issue with connector failing to load on Blender 2.93
2022-11-11 12:09:55 +00:00
JR-Morgan fa073f754f Merge remote-tracking branch 'origin' into fix-py39 2022-11-11 02:23:50 +00:00
Jedd Morgan 83919375f9 Merge pull request #129 from specklesystems/jrm/ci/macos
MacOS CI
2022-11-11 02:22:49 +00:00
JR-Morgan defb11bc89 fix: Fixed issue with connector on Blender 2.93 failing due to accidental use of unsupported python features 2022-11-11 02:13:19 +00:00
JR-Morgan 548b3ad352 CI fix for macos slugs 2022-10-24 21:48:25 +01:00
JR-Morgan d2deecf099 added deploy steps for macos 2022-10-24 21:27:38 +01:00
JR-Morgan fbda0110cd fix(connector): 2.9.0 update 2022-10-11 18:43:36 +01:00
Jedd Morgan ba9ad9ac07 Merge pull request #118 from specklesystems/gergo/workflowMetrics
add workflow tracking to receive operations
2022-10-11 17:56:40 +01:00
Jedd Morgan d13db2b44a Merge pull request #117 from specklesystems/jrm/receive-script-update
Jrm/receive script update
2022-10-11 17:54:33 +01:00
JR-Morgan 2c127c85f3 feat: Updated recieve scripts to use context rather than scene 2022-10-07 16:03:10 +01:00
Gergő Jedlicska cc099c0ff1 add workflow tracking to receive operations 2022-10-07 16:08:27 +02:00
JR-Morgan 448ab70c3b Merge remote-tracking branch 'origin/jrm/clean-mesh' into jrm/receive-script-update 2022-10-04 18:28:57 +01:00
JR-Morgan 020eba2727 Merge remote-tracking branch 'origin/main' into jrm/receive-script-update 2022-10-04 17:53:01 +01:00
JR-Morgan d8117e2c30 feat(converter): Updated Recieve Script callback functions to allow for access to Base object, and for callback on ToNative completion 2022-10-04 17:50:57 +01:00
Matteo Cominetti 57a6d88e6b ci 2022-09-27 10:27:50 +01:00
Matteo Cominetti 74cb3e5f85 ci: change shell 2022-09-27 10:15:58 +01:00
Matteo Cominetti d0aeecc863 Update README.md 2022-09-27 10:08:55 +01:00
Matteo Cominetti 2803308c5e Update README.md 2022-09-27 10:08:06 +01:00
Matteo Cominetti 326f04f67d ci: adds signtool param 2022-09-27 10:07:01 +01:00
19 changed files with 1279 additions and 1375 deletions
+219 -237
View File
@@ -1,98 +1,110 @@
version: 2.1
orbs:
python: circleci/python@1.3.2
# Using windows for builds
win: circleci/windows@2.4.0
# Upload artifacts to s3
aws-s3: circleci/aws-s3@2.0.0
commands:
install-specklepy-windows: # Reusable job for installing `specklepy` for windows machines
parameters:
python-version:
type: string
default: "" # leave blank for blender v2.93
steps:
- when:
condition: << parameters.python-version >>
steps:
- run:
name: Upgrade python version << parameters.python-version >>
shell: powershell.exe
command: |
choco upgrade python --version=<< parameters.python-version >>
refreshenv
python --version
- run:
name: Install specklepy into modules directory
shell: powershell.exe
command: |
$pyarr=(python --version).split(' ')[1].split('.')
$pyver=($pyarr[0..1] -join '.')
echo "using python version:" $pyver
$specklepy=(python patch_version.py)
python -m pip install --target=./modules-$pyver specklepy==$specklepy
win: circleci/windows@5.0.0
jobs:
build-connector-win: # Reusable job for basic connectors
executor:
name: win/default # comes with python 3.7.3
shell: cmd.exe
parameters:
slug:
type: string
default: "blender"
installer:
type: boolean
default: false
package-connector:
docker:
- image: cimg/python:3.11.0
steps:
- checkout
- run:
name: Setup SEMVER value
command: |
SEMVER=$(if [ "${CIRCLE_TAG}" ]; then echo $CIRCLE_TAG; else echo "0.0.0"; fi;)
echo $SEMVER > ./SEMVER
python3 patch_version.py $SEMVER
- run:
name: install dependencies
command: poetry install --only main
- run:
name: export package dependencies
command: ./export_dependencies.sh
- persist_to_workspace:
root: ./
paths:
- bpy_speckle
- patch_installer.py
- SEMVER
build-connector-zip:
docker:
- image: cimg/python:3.11.0
steps:
- attach_workspace:
at: ./
- install-specklepy-windows
- install-specklepy-windows:
python-version: "3.9.10"
- install-specklepy-windows:
python-version: "3.10.2"
- run: &restore_semver
name: Restore Semver
command: SEMVER=$(cat ./SEMVER) && echo $SEMVER
- run:
name: Patch
shell: powershell.exe
command:
| # If no tag, use 0.0.0.1 and don't make any YML (for testing only!)
$tag = if([string]::IsNullOrEmpty($env:CIRCLE_TAG)) { "0.0.0" } else { $env:CIRCLE_TAG }
$semver = if($tag.Contains('/')) {$tag.Split("/")[1] } else { $tag }
$ver = if($semver.Contains('-')) {$semver.Split("-")[0] } else { $semver }
$version = "$($ver).$($env:CIRCLE_BUILD_NUM)"
$channel = if($semver.Contains('-')) { "prerelease" } else { "latest" }
New-Item -Force "speckle-sharp-ci-tools/Installers/blender/$channel.yml" -ItemType File -Value "version: $semver"
echo $semver
python patch_version.py $semver
speckle-sharp-ci-tools\InnoSetup\ISCC.exe speckle-sharp-ci-tools\blender.iss
- when:
condition: << parameters.installer >>
steps:
- persist_to_workspace:
root: ./
paths:
- speckle-sharp-ci-tools/Installers
name: Package to Zip
command: zip -r bpy_speckle.zip bpy_speckle
- persist_to_workspace:
root: ./
paths:
- bpy_speckle.zip
get-ci-tools: # Clones our ci tools and persists them to the workspace
docker:
- image: cimg/base:2021.01
steps:
- add_ssh_keys:
fingerprints:
- "77:64:03:93:c5:f3:1d:a6:fd:bd:fb:d1:05:56:ca:e9"
- run:
name: I know Github as a host
command: |
mkdir ~/.ssh
touch ~/.ssh/known_hosts
ssh-keyscan github.com >> ~/.ssh/known_hosts
- run:
name: Clone
command: git clone git@github.com:specklesystems/speckle-sharp-ci-tools.git speckle-sharp-ci-tools
- run:
command: cd speckle-sharp-ci-tools
- persist_to_workspace:
root: ./
paths:
- speckle-sharp-ci-tools
build-connector-mac:
build-installer-win:
executor:
name: win/default
shell: cmd.exe
steps:
- attach_workspace:
at: ./
- run:
name: Patch installer
shell: powershell.exe
command: python patch_installer.py (Get-Content -Raw SEMVER)
- run:
name: Create Innosetup signing cert
shell: powershell.exe
command: |
echo $env:PFX_B64 > "speckle-sharp-ci-tools\SignTool\AEC Systems Ltd.txt"
certutil -decode "speckle-sharp-ci-tools\SignTool\AEC Systems Ltd.txt" "speckle-sharp-ci-tools\SignTool\AEC Systems Ltd.pfx"
- run:
name: Installer
shell: cmd.exe #does not work in powershell
command: speckle-sharp-ci-tools\InnoSetup\ISCC.exe speckle-sharp-ci-tools\blender.iss /Sbyparam=$p
- persist_to_workspace:
root: ./
paths:
- speckle-sharp-ci-tools/Installers/blender/blender-*.exe
build-installer-mac:
macos:
xcode: 12.5.1
parameters:
slug:
type: string
default: "blender-mac"
installername:
type: string
default: "SpeckleBlenderInstall"
runtime:
type: string
default: "osx-x64"
installer:
type: boolean
default: false
slug:
type: string
installer_path:
type: string
default: speckle-sharp-ci-tools/Mac/SpeckleBlenderInstall
steps:
- checkout
- attach_workspace:
@@ -105,110 +117,64 @@ jobs:
- run:
name: Install dotnet
command: curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin
- run:
name: Build & Patch Version
command: |
TAG=$(if [ "${CIRCLE_TAG}" ]; then echo $CIRCLE_TAG; else echo "0.0.0"; fi;)
SEMVER=$(echo "$TAG" | sed -e 's/[a-zA-Z-]*\///')
VER=$(echo "$SEMVER" | sed -e 's/-beta//')
VERSION=$(echo $VER.$CIRCLE_BUILD_NUM)
CHANNEL=$(if [[ "$VERSION" == *"-"* ]]; then echo $(cut -d "-" -f2 \<\<\< $VERSION); else echo latest; fi)
mkdir -p speckle-sharp-ci-tools/Installers/<< parameters.slug >>
if [ "${CIRCLE_TAG}" ]; then echo "version: $SEMVER" > "speckle-sharp-ci-tools/Installers/<< parameters.slug >>/$CHANNEL.yml"; fi
python3 patch_version.py $SEMVER
# update python and package dependencies
- when:
condition:
and:
# - << parameters.installer >>
- equal: [osx-x64, << parameters.runtime >>]
steps:
- run:
name: Install python 3.10
command: |
brew install python@3.10
brew link --overwrite python@3.10
- run:
name: Package specklepy dependencies for blender 3.1 & 3.2
command: |
python3 --version
python3 -m pip install --target=./modules-intel-3.10 specklepy==$(python3 -m patch_version)
zip -r modules-intel-3.10.zip modules-intel-3.10/
cp modules-intel-3.10.zip speckle-sharp-ci-tools/Mac/<<parameters.installername>>/.installationFiles
- run:
name: Zip Connector files
command: |
zip -r << parameters.slug >>.zip bpy_speckle/
- run: *restore_semver
- run:
name: Copy connector files to installer
command: |
mkdir -p speckle-sharp-ci-tools/Mac/<<parameters.installername>>/.installationFiles/
cp << parameters.slug >>.zip speckle-sharp-ci-tools/Mac/<<parameters.installername>>/.installationFiles
python3 patch_version.py > speckle-sharp-ci-tools/Mac/<<parameters.installername>>/.installationFiles/specklepy_ver.yml
mkdir -p <<parameters.installer_path >>/.installationFiles/
cp bpy_speckle.zip << parameters.installer_path >>/.installationFiles
- run:
name: Build Mac installer
command: ~/.dotnet/dotnet publish speckle-sharp-ci-tools/Mac/<<parameters.installername>>/<<parameters.installername>>.sln -r << parameters.runtime >> -c Release
command: ~/.dotnet/dotnet publish << parameters.installer_path >>/SpeckleBlenderInstall.sln -r << parameters.runtime >> -c Release
- run:
name: Zip installer
command: |
cd speckle-sharp-ci-tools/Mac/<<parameters.installername>>/bin/Release/net6.0/<< parameters.runtime >>/
zip -r << parameters.slug >>.zip ./
- store_artifacts:
path: speckle-sharp-ci-tools/Mac/<<parameters.installername>>/bin/Release/net6.0/<< parameters.runtime >>/<< parameters.slug >>.zip
- run:
name: Copy to installer location
command: |
TAG=$(if [ "${CIRCLE_TAG}" ]; then echo $CIRCLE_TAG; else echo "0.0.0"; fi;)
SEMVER=$(echo "$TAG" | sed -e 's/[a-zA-Z-]*\///')
cp speckle-sharp-ci-tools/Mac/<<parameters.installername>>/bin/Release/net6.0/<< parameters.runtime >>/<< parameters.slug >>.zip speckle-sharp-ci-tools/Installers/<< parameters.slug >>/<< parameters.slug >>-$SEMVER.zip
- when:
condition: << parameters.installer >>
steps:
- persist_to_workspace:
root: ./
paths:
- speckle-sharp-ci-tools/Installers
SEMVER=$(cat ./SEMVER)
echo $SEMVER
mkdir -p speckle-sharp-ci-tools/Installers/blender
(cd <<parameters.installer_path>>/bin/Release/net6.0/<< parameters.runtime >>/publish/ && zip -r - ./) > << parameters.slug >>-${SEMVER}.zip
cp << parameters.slug >>-${SEMVER}.zip speckle-sharp-ci-tools/Installers/blender/
get-ci-tools: # Clones our ci tools and persists them to the workspace
docker:
- image: cimg/base:2021.01
steps:
- run: # Could not get ssh to work, so using a personal token
name: Clone
command: git clone https://$GITHUB_TOKEN@github.com/specklesystems/speckle-sharp-ci-tools.git speckle-sharp-ci-tools
- persist_to_workspace:
root: ./
paths:
- speckle-sharp-ci-tools
- speckle-sharp-ci-tools/Installers/blender/<< parameters.slug >>*.zip
deploy: # Uploads all installers found to S3
build-installer-manual:
docker:
- image: cimg/base:2021.01
parameters:
slug:
type: string
default: bpy_speckle
steps:
- attach_workspace:
at: ./
- run: *restore_semver
- run:
name: List contents
command: ls -R speckle-sharp-ci-tools/Installers
- aws-s3/copy:
arguments: "--recursive --endpoint=https://$SPACES_REGION.digitaloceanspaces.com --acl public-read"
aws-access-key-id: SPACES_KEY
aws-region: SPACES_REGION
aws-secret-access-key: SPACES_SECRET
from: '"speckle-sharp-ci-tools/Installers/"'
to: s3://speckle-releases/installers/
name: Copy zip with semver
command: |
SEMVER=$(cat ./SEMVER)
mkdir -p speckle-sharp-ci-tools/Installers/blender
cp bpy_speckle.zip speckle-sharp-ci-tools/Installers/blender/<< parameters.slug >>-${SEMVER}.zip
- persist_to_workspace:
root: ./
paths:
- speckle-sharp-ci-tools/Installers/blender/<< parameters.slug >>*.zip
deploy-manager2:
deploy-connector:
docker:
- image: mcr.microsoft.com/dotnet/sdk:6.0
parameters:
slug:
file_slug:
type: string
os:
type: string
extension:
type: string
arch:
type: string
default: Any
steps:
- checkout
- attach_workspace:
@@ -216,110 +182,126 @@ jobs:
- run:
name: Install Manager Feed CLI
command: dotnet tool install --global Speckle.Manager.Feed
- run: *restore_semver
- run:
name: Upload new version
# this is where the installer gets the semver baked into the file name
command: |
TAG=$(if [ "${CIRCLE_TAG}" ]; then echo $CIRCLE_TAG; else echo "0.0.0"; fi;)
SEMVER=$(echo "$TAG" | sed -e 's/\/[a-zA-Z-]*//')
/root/.dotnet/tools/Speckle.Manager.Feed deploy -s << parameters.slug >> -v ${SEMVER} -u https://releases.speckle.dev/installers/<< parameters.slug >>/<< parameters.slug >>-${SEMVER}.<< parameters.extension >> -o << parameters.os >> -f speckle-sharp-ci-tools/Installers/<< parameters.slug >>/<< parameters.slug >>-${SEMVER}.<< parameters.extension >>
SEMVER=$(cat ./SEMVER)
echo $SEMVER
/root/.dotnet/tools/Speckle.Manager.Feed deploy \
-s blender \
-v ${SEMVER} \
-u https://releases.speckle.dev/installers/blender/<< parameters.file_slug >>-${SEMVER}.<< parameters.extension >> \
-o << parameters.os >> \
-a << parameters.arch >> \
-f speckle-sharp-ci-tools/Installers/blender/<< parameters.file_slug >>-${SEMVER}.<< parameters.extension >>
workflows:
build: # build the installers, but don't persist to workspace for deployment
jobs:
- get-ci-tools:
filters:
branches:
only:
- main
- /ci\/.*/
- build-connector-win:
name: Windows Build
- package-connector:
filters: &build_filters
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?(?:\.[0-9]+)?/
- build-connector-zip:
requires:
- package-connector
filters: *build_filters
- get-ci-tools:
filters: *build_filters
- build-installer-win:
context: innosetup
name: Windows Installer Build
requires:
- package-connector
- get-ci-tools
filters:
filters: *build_filters
- deploy-connector:
context: do-spaces-speckle-releases
name: deploy-windows
file_slug: blender
os: WIN
arch: Any
extension: exe
requires:
- Manual Installer Build
- Windows Installer Build
- Mac Intel Build
- Mac ARM Build
filters: &deploy_filters
branches:
only:
- main
- /ci\/.*/
- build-connector-mac:
ignore: /.*/
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?(?:\.[0-9]+)?/
- build-installer-mac:
name: Mac ARM Build
slug: blender-mac-arm
runtime: osx-arm64
requires:
- get-ci-tools
- build-connector-mac:
- build-connector-zip
filters: *build_filters
- deploy-connector:
context: do-spaces-speckle-releases
name: deploy-mac-arm
file_slug: blender-mac-arm
os: OSX
arch: Arm
extension: zip
requires:
- Manual Installer Build
- Windows Installer Build
- Mac Intel Build
- Mac ARM Build
filters: *deploy_filters
- build-installer-mac:
name: Mac Intel Build
slug: blender-mac-intel
runtime: osx-x64
requires:
- get-ci-tools
deploy: # build installers and deploy
jobs:
- get-ci-tools:
filters:
tags:
only: /.*/
branches:
ignore: /.*/
- build-connector-zip
filters: *build_filters
- build-connector-win:
name: Windows Build&Deploy
slug: blender
installer: true
- deploy-connector:
context: do-spaces-speckle-releases
name: deploy-mac-intel
file_slug: blender-mac-intel
os: OSX
arch: Intel
extension: zip
requires:
- Manual Installer Build
- Windows Installer Build
- Mac Intel Build
- Mac ARM Build
filters: *deploy_filters
- build-installer-manual:
name: Manual Installer Build
requires:
- get-ci-tools
filters:
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
branches:
ignore: /.*/
- build-connector-zip
filters: *build_filters
- build-connector-mac:
name: Mac ARM Build&Deploy
slug: blender-mac-arm
runtime: osx-arm64
installer: true
- deploy-connector:
context: do-spaces-speckle-releases
name: deploy-manual
file_slug: bpy_speckle
os: Any
arch: Any
extension: zip
requires:
- get-ci-tools
filters:
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
branches:
ignore: /.*/
- build-connector-mac:
name: Mac Intel Build&Deploy
slug: blender-mac-intel
runtime: osx-x64
installer: true
requires:
- get-ci-tools
filters:
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
branches:
ignore: /.*/
- deploy:
requires:
- get-ci-tools
- Windows Build&Deploy
- Mac ARM Build&Deploy
- Mac Intel Build&Deploy
filters:
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
branches:
ignore: /.*/
- deploy-manager2:
slug: blender
os: Win
extension: exe
requires:
- deploy
filters:
tags:
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?$/
branches:
ignore: /.*/ # For testing only! /ci\/.*/
- Manual Installer Build
- Windows Installer Build
- Mac Intel Build
- Mac ARM Build
filters: *deploy_filters
+4 -70
View File
@@ -6,73 +6,7 @@ on:
jobs:
update_issue:
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ORGANIZATION: specklesystems
PROJECT_NUMBER: 9
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectNext(number: $number) {
id
fields(first:20) {
nodes {
id
name
settings
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo "$PROJECT_ID"
echo "$STATUS_FIELD_ID"
echo 'DONE_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .settings | fromjson | .options[] | select(.name== "Done") | .id' project_data.json) >> $GITHUB_ENV
echo "$DONE_ID"
- name: Add Issue to project #it's already in the project, but we do this to get its node id!
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $id:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
- name: Update Status
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $status:ID!, $id:ID!, $value:String!) {
set_status: updateProjectNextItemField(
input: {
projectId: $project
itemId: $id
fieldId: $status
value: $value
}
) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f status=$STATUS_FIELD_ID -f id=$ITEM_ID -f value=${{ env.DONE_ID }}
uses: specklesystems/github-actions/.github/workflows/project-add-issue.yml@main
secrets: inherit
with:
issue-id: ${{ github.event.issue.node_id }}
+4 -42
View File
@@ -6,45 +6,7 @@ on:
jobs:
track_issue:
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ORGANIZATION: specklesystems
PROJECT_NUMBER: 9
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectNext(number: $number) {
id
fields(first:20) {
nodes {
id
name
settings
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
- name: Add Issue to project
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $id:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
uses: specklesystems/github-actions/.github/workflows/project-add-issue.yml@main
secrets: inherit
with:
issue-id: ${{ github.event.issue.node_id }}
+4 -1
View File
@@ -10,4 +10,7 @@ __pycache__/
# dev
.venv
Installers/
modules/
modules/
.tool-versions
requirements.txt
SEMVER
+2 -2
View File
@@ -3,7 +3,7 @@
Speckle | Blender
</h1>
<h3 align="center">
Connector for Blender 2.92 & 2.93
Connector for Blender
</h3>
<p align="center"><b>Speckle</b> is the data infrastructure for the AEC industry.</p><br/>
@@ -91,4 +91,4 @@ The Speckle Community hangs out on [the forum](https://discourse.speckle.works),
Unless otherwise described, the code in this repository is licensed under the Apache-2.0 License. Please note that some modules, extensions or code herein might be otherwise licensed. This is indicated either in the root of the containing folder under a different license file, or in the respective file's header. If you have any questions, don't hesitate to get in touch with us via [email](mailto:hello@speckle.systems).
## Notes
SpeckleBlender is written and maintained by [Tom Svilans](http://tomsvilans.com) ([Github](https://github.com/tsvilans)).
Thanks to [Tom Svilans](http://tomsvilans.com) ([Github](https://github.com/tsvilans)) for the original v1 contribution!
+11 -9
View File
@@ -1,4 +1,15 @@
import bpy
from bpy_speckle.installer import ensure_dependencies
ensure_dependencies()
from specklepy.logging import metrics
from bpy_speckle.ui import *
from bpy_speckle.properties import *
from bpy_speckle.operators import *
from bpy_speckle.callbacks import *
from bpy.app.handlers import persistent
bl_info = {
"name": "SpeckleBlender 2.0",
@@ -18,15 +29,6 @@ bl_info = {
Import SpeckleBlender classes
"""
from specklepy.api.client import SpeckleClient # , SpeckleCache
from specklepy.logging import metrics
from bpy_speckle.ui import *
from bpy_speckle.properties import *
from bpy_speckle.operators import *
from bpy_speckle.callbacks import *
from bpy.app.handlers import persistent
"""
Add load handler to initialize Speckle when
loading a Blender file
+2 -1
View File
@@ -1,7 +1,8 @@
from typing import Union
from bpy_speckle.convert.to_native import convert_to_native
from specklepy.objects.base import Base
def get_speckle_subobjects(attr: dict | Base, scale: float, name: str) -> list:
def get_speckle_subobjects(attr: Union[dict, Base], scale: float, name: str) -> list:
subobjects = []
keys = attr.keys() if isinstance(attr, dict) else attr.get_dynamic_member_names()
for key in keys:
+17 -13
View File
@@ -1,4 +1,5 @@
import math
from typing import Union
from bpy_speckle.functions import get_scale_length, _report
import mathutils
import bpy, bmesh, bpy_types
@@ -38,7 +39,7 @@ def can_convert_to_native(speckle_object: Base) -> bool:
return False
def convert_to_native(speckle_object: Base, name: str = None) -> list | Object:
def convert_to_native(speckle_object: Base, name: Optional[str] = None) -> Optional[Union[list, Object]]:
speckle_type = type(speckle_object)
speckle_name = (
name
@@ -47,9 +48,9 @@ def convert_to_native(speckle_object: Base, name: str = None) -> list | Object:
)
# convert unsupported types with display values
if speckle_type not in CAN_CONVERT_TO_NATIVE:
elements = getattr(speckle_object, "elements", []) or []
elements = getattr(speckle_object, "elements", getattr(speckle_object, "@elements", []))
display = getattr(
speckle_object, "displayValue", getattr(speckle_object, "displayMesh", None)
speckle_object, "displayValue", getattr(speckle_object, "@displayValue", None)
)
if not elements and not display:
_report(f"Could not convert unsupported Speckle object: {speckle_object}")
@@ -63,6 +64,8 @@ def convert_to_native(speckle_object: Base, name: str = None) -> list | Object:
# not making it hidden, so it will get added on send as i think it might be helpful? can reconsider
converted = []
for item in elements:
if not isinstance(item, Base):
continue
item.parent_speckle_type = speckle_object.speckle_type
blender_object = convert_to_native(item)
if isinstance(blender_object, list):
@@ -76,7 +79,7 @@ def convert_to_native(speckle_object: Base, name: str = None) -> list | Object:
# convert breps
if speckle_type is Brep:
meshes = getattr(
speckle_object, "displayValue", getattr(speckle_object, "displayMesh", None)
speckle_object, "displayValue", getattr(speckle_object, "displayMesh", iter([]))
)
if material := getattr(speckle_object, "renderMaterial", getattr(speckle_object, "@renderMaterial", None),):
for mesh in meshes:
@@ -84,18 +87,19 @@ def convert_to_native(speckle_object: Base, name: str = None) -> list | Object:
return [convert_to_native(mesh) for mesh in meshes]
scale = 1.0
if units := getattr(speckle_object, "units", None):
scale = get_scale_length(units) / bpy.context.scene.unit_settings.scale_length
# convert supported geometry
if speckle_type is Mesh:
if isinstance(speckle_object, Mesh):
obj_data = mesh_to_native(speckle_object, name=speckle_name, scale=scale)
elif speckle_type in SUPPORTED_CURVES:
obj_data = icurve_to_native(speckle_object, name=speckle_name, scale=scale)
elif speckle_type is Transform:
elif isinstance(speckle_object, Transform):
obj_data = transform_to_native(speckle_object, scale=scale)
elif speckle_type is BlockDefinition:
elif isinstance(speckle_object, BlockDefinition):
obj_data = block_def_to_native(speckle_object, scale=scale)
elif speckle_type is BlockInstance:
elif isinstance(speckle_object, BlockInstance): # speckle_type is BlockInstance:
obj_data = block_instance_to_native(speckle_object, scale=scale)
else:
_report(f"Unsupported type {speckle_type}")
@@ -151,7 +155,7 @@ def mesh_to_native(speckle_mesh: Mesh, name: str, scale=1.0) -> bpy.types.Mesh:
return blender_mesh
def line_to_native(speckle_curve: Line, blender_curve: bpy.types.Curve, scale: float) -> bpy.types.Spline | None:
def line_to_native(speckle_curve: Line, blender_curve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
line = blender_curve.splines.new("POLY")
line.points.add(1)
@@ -174,7 +178,7 @@ def line_to_native(speckle_curve: Line, blender_curve: bpy.types.Curve, scale: f
return line
def polyline_to_native(scurve: Polyline, bcurve: bpy.types.Curve, scale: float) -> bpy.types.Spline | None:
def polyline_to_native(scurve: Polyline, bcurve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
if value := scurve.value:
N = len(value) // 3
@@ -198,7 +202,7 @@ def polyline_to_native(scurve: Polyline, bcurve: bpy.types.Curve, scale: float)
return polyline
def nurbs_to_native(scurve: Curve, bcurve: bpy.types.Curve, scale: float) -> bpy.types.Spline | None:
def nurbs_to_native(scurve: Curve, bcurve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
if points := scurve.points:
N = len(points) // 3
@@ -227,7 +231,7 @@ def nurbs_to_native(scurve: Curve, bcurve: bpy.types.Curve, scale: float) -> bpy
return nurbs
def arc_to_native(rcurve: Arc, bcurve: bpy.types.Curve, scale: float) -> bpy.types.Spline | None:
def arc_to_native(rcurve: Arc, bcurve: bpy.types.Curve, scale: float) -> Optional[bpy.types.Spline]:
# TODO: improve Blender representation of arc
plane = rcurve.plane
@@ -322,7 +326,7 @@ def icurve_to_native_spline(speckle_curve: Base, blender_curve: bpy.types.Curve,
return arc_to_native(speckle_curve, blender_curve, scale)
def icurve_to_native(speckle_curve: Base, name=None, scale=1.0) -> Curve | None:
def icurve_to_native(speckle_curve: Base, name=None, scale=1.0) -> Optional[Curve]:
curve_type = type(speckle_curve)
if curve_type not in SUPPORTED_CURVES:
_report(f"Unsupported curve type: {curve_type}")
+29 -16
View File
@@ -1,5 +1,6 @@
from typing import Optional
import bpy
from bpy.types import MeshVertColor, MeshVertex, Object
from bpy.types import Depsgraph, MeshVertColor, MeshVertex, Object
from specklepy.objects.geometry import Mesh, Curve, Interval, Box, Point, Polyline
from specklepy.objects.other import *
from bpy_speckle.functions import _report
@@ -14,7 +15,7 @@ UNITS = "m"
CAN_CONVERT_TO_SPECKLE = ("MESH", "CURVE", "EMPTY")
def convert_to_speckle(blender_object: Object, scale: float, units: str, desgraph=None) -> list | None:
def convert_to_speckle(blender_object: Object, scale: float, units: str, desgraph: Optional[Depsgraph]) -> Optional[list]:
global UNITS
UNITS = units
blender_type = blender_object.type
@@ -64,12 +65,15 @@ def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh, scale=1.0) ->
verts = [tuple(mat @ x.co * scale) for x in data.vertices]
flattend_verts = []
for row in verts: flattend_verts.extend(row)
faces = [p.vertices for p in data.polygons]
unit_system = bpy.context.scene.unit_settings.system
sm = Mesh(
name=blender_object.name,
vertices=list(sum(verts, ())),
vertices=flattend_verts,
faces=[],
colors=[],
textureCoordinates=[],
@@ -100,7 +104,7 @@ def mesh_to_speckle(blender_object: Object, data: bpy.types.Mesh, scale=1.0) ->
return [sm]
def bezier_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float, name:str = None) -> Curve:
def bezier_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float, name: Optional[str] = None) -> Curve:
degree = 3
closed = spline.use_cyclic_u
@@ -120,9 +124,12 @@ def bezier_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: floa
tuple(matrix @ spline.bezier_points[0].co * scale),
)
)
num_points = len(points)
flattend_points = []
for row in points: flattend_points.extend(row)
knot_count = num_points + degree - 1
knots = [0] * knot_count
@@ -136,7 +143,7 @@ def bezier_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: floa
degree=degree,
closed=spline.use_cyclic_u,
periodic=spline.use_cyclic_u,
points=list(sum(points, ())), # magic (flatten list of tuples)
points=flattend_points,
weights=[1] * num_points,
knots=knots,
rational=False,
@@ -149,7 +156,7 @@ def bezier_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: floa
)
def nurbs_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float, name:str = None) -> Curve:
def nurbs_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float, name: Optional[str] = None) -> Curve:
knots = make_knots(spline)
points = [tuple(matrix @ pt.co.xyz * scale) for pt in spline.points]
degree = spline.order_u - 1
@@ -157,12 +164,15 @@ def nurbs_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float
length = spline.calc_length()
domain = Interval(start=0, end=length, totalChildrenCount=0)
flattend_points = []
for row in points: flattend_points.extend(row)
return Curve(
name=name,
degree=degree,
closed=spline.use_cyclic_u,
periodic=spline.use_cyclic_u,
points=list(sum(points, ())), # magic (flatten list of tuples)
points=flattend_points,
weights=[pt.weight for pt in spline.points],
knots=knots,
rational=False,
@@ -175,15 +185,18 @@ def nurbs_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float
)
def poly_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float, name: str = None) -> Polyline:
def poly_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float, name: Optional[str] = None) -> Polyline:
points = [tuple(matrix @ pt.co.xyz * scale) for pt in spline.points]
flattend_points = []
for row in points: flattend_points.extend(row)
length = spline.calc_length()
domain = Interval(start=0, end=length, totalChildrenCount=0)
return Polyline(
name=name,
closed=bool(spline.use_cyclic_u),
value=list(sum(points, ())), # magic (flatten list of tuples)
value=list(flattend_points),
length=length,
domain=domain,
bbox=Box(area=0.0, volume=0.0),
@@ -192,7 +205,7 @@ def poly_to_speckle(matrix: List[float], spline: bpy.types.Spline, scale: float,
)
def icurve_to_speckle(blender_object: Object, data: bpy.types.Curve, scale=1.0) -> List[Base] | None:
def icurve_to_speckle(blender_object: Object, data: bpy.types.Curve, scale=1.0) -> Optional[List[Base]]:
UNITS = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
if blender_object.type != "CURVE":
@@ -221,7 +234,7 @@ def icurve_to_speckle(blender_object: Object, data: bpy.types.Curve, scale=1.0)
return curves
def ngons_to_speckle_polylines(blender_object: Object, data: bpy.types.Mesh, scale=1.0) -> List[Polyline] | None:
def ngons_to_speckle_polylines(blender_object: Object, data: bpy.types.Mesh, scale=1.0) -> Optional[List[Polyline]]:
UNITS = "m" if bpy.context.scene.unit_settings.system == "METRIC" else "ft"
if blender_object.type != "MESH":
@@ -253,7 +266,7 @@ def ngons_to_speckle_polylines(blender_object: Object, data: bpy.types.Mesh, sca
return polylines
def material_to_speckle(blender_object: Object) -> RenderMaterial | None:
def material_to_speckle(blender_object: Object) -> Optional[RenderMaterial]:
"""Create and return a render material from a blender object"""
if not getattr(blender_object.data, "materials", None):
return None
@@ -295,7 +308,7 @@ def transform_to_speckle(blender_transform: List[float], scale=1.0) -> Transform
def block_def_to_speckle(blender_definition: bpy.types.Collection, scale=1.0) -> BlockDefinition:
geometry = []
for geo in blender_definition.objects:
geometry.extend(convert_to_speckle(geo, scale, UNITS))
geometry.extend(convert_to_speckle(geo, scale, UNITS, None))
block_def = BlockDefinition(
units=UNITS,
name=blender_definition.name,
@@ -307,7 +320,7 @@ def block_def_to_speckle(blender_definition: bpy.types.Collection, scale=1.0) ->
return block_def
def block_instance_to_speckle(blender_instance: Object, scale=1.0):
def block_instance_to_speckle(blender_instance: Object, scale=1.0) -> BlockInstance:
return BlockInstance(
blockDefinition=block_def_to_speckle(
blender_instance.instance_collection, scale
@@ -318,7 +331,7 @@ def block_instance_to_speckle(blender_instance: Object, scale=1.0):
)
def empty_to_speckle(blender_object: Object, scale=1.0) -> BlockInstance | None:
def empty_to_speckle(blender_object: Object, scale=1.0) -> Optional[BlockInstance]:
# probably an instance collection (block) so let's try it
try:
geo = blender_object.instance_collection.objects.items()
+128
View File
@@ -0,0 +1,128 @@
from pathlib import Path
from importlib import import_module, invalidate_caches
import bpy
import sys
print("Starting Speckle Blender installation")
print(sys.executable)
PYTHON_PATH = sys.executable
def modules_path() -> Path:
modules_path = Path(bpy.utils.script_path_user(), "addons", "modules")
modules_path.mkdir(exist_ok=True, parents=True)
# set user modules path at beginning of paths for earlier hit
if sys.path[1] != modules_path:
sys.path.insert(1, modules_path)
return modules_path
print(f"Found blender modules path {modules_path()}")
def is_pip_available() -> bool:
try:
import_module("pip") # noqa F401
return True
except ImportError:
return False
def ensure_pip() -> None:
print("Installing pip... "),
from subprocess import run
completed_process = run([PYTHON_PATH, "-m", "ensurepip"])
if completed_process.returncode == 0:
print("Successfully installed pip")
else:
raise Exception("Failed to install pip.")
def get_requirements_path() -> Path:
# we assume that a requirements.txt exists next to the __init__.py file
path = Path(Path(__file__).parent, "requirements.txt")
assert path.exists()
return path
def install_requirements() -> None:
# set up addons/modules under the user
# script path. Here we'll install the
# dependencies
path = modules_path()
print(f"Installing Speckle dependencies to {path}")
from subprocess import run
completed_process = run(
[
PYTHON_PATH,
"-m",
"pip",
"install",
"-t",
str(path),
"-r",
str(get_requirements_path()),
],
capture_output=True,
text=True,
)
if completed_process.returncode != 0:
print("Please try manually installing speckle-blender")
raise Exception(
"""
Failed to install speckle-blender.
See console for manual install instruction.
"""
)
def install_dependencies() -> None:
if not is_pip_available():
ensure_pip()
install_requirements()
def _import_dependencies() -> None:
import_module("specklepy")
# the code above doesn't work for now, it fails on importing graphql-core
# despite that, the connector seams to be working as expected
# But it would be nice to make this solution work
# it would ensure that all dependencies are fully loaded
# requirements = get_requirements_path().read_text()
# reqs = [
# req.split(" ; ")[0].split("==")[0].split("[")[0].replace("-", "_")
# for req in requirements.split("\n")
# if req and not req.startswith(" ")
# ]
# for req in reqs:
# print(req)
# import_module("specklepy")
def ensure_dependencies() -> None:
try:
_import_dependencies()
print("Found all dependencies, proceed with loading")
except ImportError:
print("Failed to load all dependencies, trying to install them...")
install_dependencies()
invalidate_caches()
_import_dependencies()
if __name__ == "__main__":
ensure_dependencies()
+78 -41
View File
@@ -11,11 +11,10 @@ from bpy.props import (
StringProperty,
BoolProperty,
)
from bpy.types import Object
from bpy.types import Context, Object
from bpy_speckle.convert.to_native import can_convert_to_native, convert_to_native
from bpy_speckle.convert.to_speckle import (
convert_to_speckle,
ngons_to_speckle_polylines,
)
from bpy_speckle.functions import (
_check_speckle_client_user_stream,
@@ -26,12 +25,13 @@ from bpy_speckle.convert import get_speckle_subobjects
from bpy_speckle.clients import speckle_clients
from bpy_speckle.operators.users import add_user_stream
from specklepy.api import operations
from specklepy.api import operations, host_applications
from specklepy.api.wrapper import StreamWrapper
from specklepy.api.resources.stream import Stream
from specklepy.transports.server import ServerTransport
from specklepy.objects.geometry import *
from specklepy.logging.exceptions import SpeckleException
from specklepy.logging import metrics
def get_objects_collections(base: Base) -> Dict[str, list]:
@@ -49,9 +49,11 @@ def get_objects_collections(base: Base) -> Dict[str, list]:
return collections
def get_objects_nested_lists(items: list, parent_col: bpy.types.Collection = None) -> List:
def get_objects_nested_lists(items: list, parent_col: Optional[bpy.types.Collection] = None) -> List:
"""For handling the weird nested lists that come from Grasshopper"""
objects = []
if not items:
return objects
if isinstance(items[0], list):
items = list(chain.from_iterable(items))
@@ -66,7 +68,7 @@ def get_objects_nested_lists(items: list, parent_col: bpy.types.Collection = Non
return objects
def get_objects_collections_recursive(base: Base, parent_col: bpy.types.Collection = None) -> List:
def get_objects_collections_recursive(base: Base, parent_col: Optional[bpy.types.Collection] = None) -> List:
"""Recursively create collections based on the dynamic members on nested `Base` objects within the root commit object"""
# if it's a convertable (registered) class and not just a plain `Base`, return the object itself
if can_convert_to_native(base):
@@ -96,7 +98,47 @@ def get_objects_collections_recursive(base: Base, parent_col: bpy.types.Collecti
return objects
def bases_to_native(context: bpy.types.Context, collections: Dict[str, list], scale: float, stream_id: str, func: Callable = None):
ObjectCallback = Optional[Callable[[bpy.types.Context, Object, Base], Object]]
ReceiveCompleteCallback = Optional[Callable[[bpy.types.Context, Dict[str, Object]], None]]
def get_receive_funcs(context: Context, created_objects: Dict[str, Object]) -> tuple[ObjectCallback, ReceiveCompleteCallback]:
"""
Fetches the injected callback functions from user specified "Receive Script"
"""
objectCallback: ObjectCallback = None
receiveCompleteCallback: ReceiveCompleteCallback = None
if context.scene.speckle.receive_script in bpy.data.texts:
mod = bpy.data.texts[context.scene.speckle.receive_script].as_module()
if hasattr(mod, "execute_for_each"):
objectCallback = mod.execute_for_each
elif hasattr(mod, "execute"):
objectCallback = lambda c, o, _ : mod.execute(c.scene, o)
if hasattr(mod, "execute_for_all"):
receiveCompleteCallback = mod.execute_for_all
progress = 0
def for_each_object(context: bpy.types.Context, obj: Object, base: Base) -> Object:
nonlocal progress
nonlocal created_objects
nonlocal objectCallback
progress += 1 #TODO: Progress bar never reaches 100 because func is only called for convertible objects
context.window_manager.progress_update(progress)
created_objects[obj.name] = obj
if objectCallback:
return objectCallback(context, obj, base)
else:
return obj
return (for_each_object, receiveCompleteCallback)
def bases_to_native(context: bpy.types.Context, collections: Dict[str, list], scale: float, stream_id: str, func: ObjectCallback = None):
for col_name, objects in collections.items():
col = bpy.data.collections[col_name]
existing = get_existing_collection_objs(col)
@@ -129,7 +171,14 @@ def bases_to_native(context: bpy.types.Context, collections: Dict[str, list], sc
def base_to_native(context: bpy.types.Context, base: Base, scale: float, stream_id: str, col: bpy.types.Collection, existing: Dict[str, Object], func: Callable = None):
def base_to_native(context: bpy.types.Context,
base: Base,
scale: float,
stream_id: str,
col: bpy.types.Collection,
existing: Dict[str, Object],
func: ObjectCallback = None
):
new_objects = convert_to_native(base)
if not isinstance(new_objects, list):
new_objects = [new_objects]
@@ -152,7 +201,7 @@ def base_to_native(context: bpy.types.Context, base: Base, scale: float, stream_
Run injected function
"""
if func:
new_object = func(context.scene, new_object)
new_object = func(context, new_object, base) #this base object isn't the right one for hosted elements!
if (
new_object is None
@@ -232,7 +281,6 @@ def create_nested_hierarchy(base, hierarchy, objects):
return base
class ReceiveStreamObjects(bpy.types.Operator):
"""
Receive stream objects
@@ -264,10 +312,6 @@ class ReceiveStreamObjects(bpy.types.Operator):
if obj.type != 'MESH':
continue
# This seems to be required inorder to select the object here
if obj.name not in context.scene.collection.objects:
context.scene.collection.objects.link(obj)
obj.select_set(True, view_layer=context.scene.view_layers[0])
active = obj
@@ -312,10 +356,19 @@ class ReceiveStreamObjects(bpy.types.Operator):
_report("No commits found. Probably an empty stream.")
return {"CANCELLED"}
commit = branch.commits.items[int(bbranch.commit)]
commit: Commit = branch.commits.items[int(bbranch.commit)]
transport = ServerTransport(stream.id, client)
stream_data = operations.receive(commit.referencedObject, transport)
metrics.track(
metrics.RECEIVE,
getattr(transport, "account", None),
custom_props={
"sourceHostApp": host_applications.get_host_app_from_string(commit.sourceApplication).slug,
"sourceHostAppVersion": commit.sourceApplication
},
)
stream_data = operations._untracked_receive(commit.referencedObject, transport)
client.commit.received(
bstream.id,
commit.id,
@@ -337,8 +390,8 @@ class ReceiveStreamObjects(bpy.types.Operator):
name = "{} [ {} @ {} ]".format(stream.name, branch.name, commit.id)
col = create_collection(name)
col.speckle.stream_id = stream.id
col.speckle.name = stream.name
col.speckle.units = stream_data.units
col.speckle.units = stream_data.units or "m"
if col.name not in bpy.context.scene.collection.children:
bpy.context.scene.collection.children.link(col)
@@ -351,35 +404,15 @@ class ReceiveStreamObjects(bpy.types.Operator):
Set conversion scale from stream units
"""
scale = (
get_scale_length(stream_data.units)
get_scale_length(col.speckle.units)
/ context.scene.unit_settings.scale_length
)
"""
Get script from text editor for injection
"""
userFunc = None
if context.scene.speckle.receive_script in bpy.data.texts:
mod = bpy.data.texts[context.scene.speckle.receive_script].as_module()
if hasattr(mod, "execute"):
userFunc = mod.execute
createdObjects:Dict[str, Object] = {}
progress = 0
def func(scene, obj: Object):
nonlocal progress
nonlocal context
nonlocal createdObjects
progress += 1 #TODO: Progress bar neverreaches 100 because func is only called for convertable objects
context.window_manager.progress_update(progress)
createdObjects[obj.name] = obj
if userFunc:
return userFunc(scene, obj)
else:
return obj
created_objects = {}
(func, on_complete) = get_receive_funcs(context, created_objects)
"""
@@ -390,10 +423,14 @@ class ReceiveStreamObjects(bpy.types.Operator):
if self.clean_meshes:
self.clean_converted_meshes(context, createdObjects)
self.clean_converted_meshes(context, created_objects)
if on_complete:
on_complete(context, created_objects)
return {"FINISHED"}
+8 -5
View File
@@ -4,6 +4,7 @@ User account operators
import bpy
from bpy_speckle.functions import _report
from bpy_speckle.clients import speckle_clients
from bpy_speckle.properties.scene import SpeckleSceneSettings
from specklepy.api.client import SpeckleClient
from specklepy.api.models import Stream, User
from specklepy.api.credentials import get_local_accounts
@@ -23,12 +24,14 @@ class LoadUsers(bpy.types.Operator):
_report("Loading users...")
users = context.scene.speckle.users
speckle : SpeckleSceneSettings = context.scene.speckle
users = speckle.users
context.scene.speckle.users.clear()
speckle.users.clear()
speckle_clients.clear()
profiles = get_local_accounts()
active_user_index = 0
for profile in profiles:
user = users.add()
@@ -49,10 +52,10 @@ class LoadUsers(bpy.types.Operator):
_report(ex)
users.remove(len(users) - 1)
if profile.isDefault:
context.scene.speckle.active_user = str(len(users) - 1)
active_user_index = len(users) - 1
context.scene.speckle.active_user_index = int(context.scene.speckle.active_user)
bpy.ops.speckle.load_user_streams()
speckle.active_user_index = int(speckle.active_user) #TODO: what is this?
speckle.active_user = str(active_user_index)
bpy.context.view_layer.update()
if context.area:
+1 -1
View File
@@ -73,7 +73,7 @@ class SpeckleUserObject(bpy.types.PropertyGroup):
name: StringProperty(default="Speckle User")
email: StringProperty(default="user@speckle.xyz")
company: StringProperty(default="SpeckleSystems")
authToken: StringProperty(default="")
authToken: StringProperty(default="", subtype='PASSWORD')
streams: CollectionProperty(type=SpeckleStreamObject)
active_stream: IntProperty(default=0)
+2 -1
View File
@@ -121,7 +121,8 @@ class VIEW3D_PT_SpeckleUser(bpy.types.Panel):
user = speckle.users[int(speckle.active_user)]
col.label(text="{} ({})".format(user.server_name, user.server_url))
col.label(text="{} ({})".format(user.name, user.email))
col.operator("speckle.users_load", text="", icon="FILE_REFRESH")
class VIEW3D_PT_SpeckleStreams(bpy.types.Panel):
"""
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e -o pipefail
poetry export --only main -o bpy_speckle/requirements.txt
+20
View File
@@ -0,0 +1,20 @@
import sys
from pathlib import Path
def patch_installer(tag: str):
"""Patches the installer with the correct connector version and specklepy version"""
tag = tag.replace("\n", "")
iss_file = "speckle-sharp-ci-tools/blender.iss"
iss_path = Path(iss_file)
lines = iss_path.read_text().split("\n")
lines.insert(12, f'#define AppVersion "{tag.split("-")[0]}"')
lines.insert(13, f'#define AppInfoVersion "{tag}"')
iss_path.write_text("\n".join(lines))
print(f"Patched installer with connector v{tag}")
if __name__ == "__main__":
tag = sys.argv[1]
patch_installer(tag)
-36
View File
@@ -1,7 +1,6 @@
import re
import sys
def patch_connector(tag):
"""Patches the connector version within the connector init file"""
bpy_file = "bpy_speckle/__init__.py"
@@ -19,48 +18,13 @@ def patch_connector(tag):
with open(bpy_file, "w") as file:
file.writelines(lines)
def patch_installer(tag):
"""Patches the installer with the correct connector version and specklepy version"""
iss_file = "speckle-sharp-ci-tools/blender.iss"
py_tag = get_specklepy_version()
with open(iss_file, "r") as file:
lines = file.readlines()
lines.insert(11, f'#define SpecklepyVersion "{py_tag}"\n')
lines.insert(12, f'#define AppVersion "{tag.split("-")[0]}"\n')
lines.insert(13, f'#define AppInfoVersion "{tag}"\n')
with open(iss_file, "w") as file:
file.writelines(lines)
print(f"Patched installer with connector v{tag} and specklepy v{py_tag}")
def get_specklepy_version():
"""Get version of specklepy to install from the pyproject.toml"""
version = "2.3.3"
with open("pyproject.toml", "r") as f:
lines = [line for line in f if line.startswith("specklepy = ")]
if not lines:
raise Exception("Could not find specklepy in pyproject.toml")
match = re.search(r"[0-9]+(\.[0-9]+)*", lines[0])
if match:
version = match[0]
return version
def main():
if len(sys.argv) < 2:
print(get_specklepy_version())
return
tag = sys.argv[1]
if not re.match(r"([0-9]+)\.([0-9]+)\.([0-9]+)", tag):
raise ValueError(f"Invalid tag provided: {tag}")
print(f"Patching version: {tag}")
patch_connector(tag.split("-")[0])
patch_installer(tag)
if __name__ == "__main__":
Generated
+735 -892
View File
File diff suppressed because it is too large Load Diff
+11 -8
View File
@@ -2,19 +2,22 @@
name = "speckle-blender"
version = "2.0.0"
description = "the Speckle 2.0 connector for Blender!"
authors = ["izzy lyseggen <izzy.lyseggen@gmail.com>"]
authors = ["izzy lyseggen <izzy.lyseggen@gmail.com>", "Gergő Jedlicska <gergo@jedlicska.com>"]
license = "Apache-2.0"
[tool.poetry.dependencies]
python = ">=3.8, <4.0.0"
specklepy = "^2.6.6"
specklepy = "^2.11.4"
[tool.poetry.dev-dependencies]
devtools = "^0.6.1"
numpy = "^1.20.2"
fake-bpy-module-latest = "^20220401"
black = "^21.12b0"
pylint = "^2.12.2"
# [tool.poetry.group.local_specklepy.dependencies]
# specklepy = {path = "../specklepy", develop = true}
[tool.poetry.group.dev.dependencies]
numpy = "^1.23.5"
fake-bpy-module-latest = "^20221006"
black = "^22.10.0"
pylint = "^2.15.7"
ruff = "^0.0.166"
[build-system]
requires = ["poetry-core>=1.0.0"]