Release under the SolidCraft name: binaries, assets and installers (#383)

* Release under the SolidCraft name: binaries, assets and installers

The desktop binary is now `solidcraft` and the CLI `solidcraft-cli` (the two app packages
are renamed; their folders move with the rest of the rename later). Every release asset is
named solidcraft-<ver>-… / SolidCraft-<ver>-windows-x64.exe, and the installers show the
SolidCraft product name.

Kept so existing installs keep updating (docs/compatibility.md):
- `solvecraft-cli` alias binary in every package, forwarding to solidcraft-cli with a
  deprecation note on stderr (tests/legacy_alias.rs).
- Linux app ID ai.storyteller.solvecraft (Flatpak ID, desktop entry, Wayland app_id).
- MSI UpgradeCode, so the MSI upgrades in place.
- deb Replaces/Conflicts/Provides and rpm Obsoletes/Provides solvecraft.
- An old-named .zsync copy so earlier AppImages find updates; a legacy .flatpakrepo copy.
- .solvecraft file associations; SOLVECRAFT_* fallbacks in the packaging scripts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

* MSI: register the legacy .solvecraft extension without a duplicate open verb

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-12 16:05:35 -04:00
1 parent f06b76e14f
commit 6090e89b3f
50 files changed
+478 -317

No files matched your search

+19 -14
View File
@@ -3,37 +3,42 @@ parameter to watch the timeline rebuild. [Documentation](https://bherbruck.githu
· [try it in the browser](https://bherbruck.github.io/solidcraft/app/) · · [try it in the browser](https://bherbruck.github.io/solidcraft/app/) ·
[contributing](https://github.com/bherbruck/solidcraft/blob/main/CONTRIBUTING.md) · [contributing](https://github.com/bherbruck/solidcraft/blob/main/CONTRIBUTING.md) ·
[issues](https://github.com/bherbruck/solidcraft/issues). AI agents can model with it over MCP: [issues](https://github.com/bherbruck/solidcraft/issues). AI agents can model with it over MCP:
`solvecraft-cli mcp` ([how](https://bherbruck.github.io/solidcraft/guide/mcp.html)). `solidcraft-cli mcp` ([how](https://bherbruck.github.io/solidcraft/guide/mcp.html)).
Compatibility names are unchanged: existing `.solvecraft` designs, `solvecraft-cli`, package **Renamed to SolidCraft.** Downloads, installers and programs now carry the SolidCraft name:
IDs and archive filenames still work. Published 0.2.0 and 0.2.1 releases keep their original the desktop app is `solidcraft`, the command line `solidcraft-cli`. `solvecraft-cli` is still
SolveCraft branding. Documentation, the browser app and the Flatpak feed use the new installed as a deprecated alias that forwards to `solidcraft-cli` (it prints a one-line note on
SolidCraft project Pages URLs; old-name Pages addresses are not permanent aliases. stderr), so scripts and MCP setups such as `claude mcp add solvecraft -- solvecraft-cli mcp`
keep working; new setups use `claude mcp add solidcraft -- solidcraft-cli mcp`. Existing designs
open as before. Upgrades: the `.msi` upgrades an earlier install in place (it now installs to
`Program Files\SolidCraft`); the `solidcraft` `.deb`/`.rpm` replaces the old `solvecraft`
package; the Flatpak app ID `ai.storyteller.solvecraft` is unchanged, so Flatpak updates
continue; earlier AppImages still find updates.
**Which file?** **Which file?**
- **Windows:** `SolveCraft-{version}-windows-x64.exe` runs as is. Or install the `.msi`, or unzip the - **Windows:** `SolidCraft-{version}-windows-x64.exe` runs as is. Or install the `.msi`, or unzip the
`-portable.zip` (x64, x86 and arm64). `-portable.zip` (x64, x86 and arm64).
- **macOS 11+** (Apple silicon and Intel): open the `.dmg` and drag `SolidCraft.app` onto Applications. - **macOS 11+** (Apple silicon and Intel): open the `.dmg` and drag `SolidCraft.app` onto Applications.
The CLI is in `solvecraft-cli-{version}-macos-universal.zip`. The CLI is in `solidcraft-cli-{version}-macos-universal.zip`.
- **Linux** (x86_64 and aarch64, glibc 2.35+): the `.AppImage` (`chmod +x`, then run it), the - **Linux** (x86_64 and aarch64, glibc 2.35+): the `.AppImage` (`chmod +x`, then run it), the
`.deb` or `.rpm`, the `.flatpak` (`flatpak install --user <file>`), or the `.tar.gz`. `.deb` or `.rpm`, the `.flatpak` (`flatpak install --user <file>`), or the `.tar.gz`.
- **FreeBSD:** `tar -xzf solvecraft-{version}-freebsd-x86_64.tar.gz --strip-components 1 -C /usr/local`. - **FreeBSD:** `tar -xzf solidcraft-{version}-freebsd-x86_64.tar.gz --strip-components 1 -C /usr/local`.
- **Web:** `solvecraft-web-{version}.zip` is a static site to host yourself. - **Web:** `solidcraft-web-{version}.zip` is a static site to host yourself.
- `SHA256SUMS.txt`: `sha256sum -c SHA256SUMS.txt --ignore-missing`. - `SHA256SUMS.txt`: `sha256sum -c SHA256SUMS.txt --ignore-missing`.
**Updating macOS from SolveCraft.app:** quit the app, rename the existing app in **Updating macOS from SolveCraft.app:** quit the app, rename the existing app in
Applications to `SolidCraft.app`, then drag the new app from the DMG onto Applications Applications to `SolidCraft.app`, then drag the new app from the DMG onto Applications
and choose **Replace**. If both names are already installed, move the old `SolveCraft.app` and choose **Replace**. If both names are already installed, move the old `SolveCraft.app`
to the Trash. Remove any Dock shortcut with the old name and pin the new app. Designs, to the Trash. Remove any Dock shortcut with the old name and pin the new app. Designs
settings and the bundle identifier are unchanged. The DMG includes these instructions. and settings are unchanged. The DMG includes these instructions.
For Flatpak feed installation and updates, add Flathub for the required runtime before For Flatpak feed installation and updates, add Flathub for the required runtime before
installing SolidCraft; keep both remotes in the same user installation: installing SolidCraft; keep both remotes in the same user installation:
```sh ```sh
flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak remote-add --user --if-not-exists solvecraft https://bherbruck.github.io/solidcraft/flatpak/solvecraft.flatpakrepo flatpak remote-add --user --if-not-exists solidcraft https://bherbruck.github.io/solidcraft/flatpak/solidcraft.flatpakrepo
flatpak install --user solvecraft ai.storyteller.solvecraft flatpak install --user solidcraft ai.storyteller.solvecraft
flatpak run ai.storyteller.solvecraft flatpak run ai.storyteller.solvecraft
``` ```
@@ -43,7 +48,7 @@ still need an internet connection. [Linux installation details](https://bherbruc
The builds aren't signed yet. On macOS, right-click `SolidCraft.app` in Applications and choose The builds aren't signed yet. On macOS, right-click `SolidCraft.app` in Applications and choose
**Open** the first time (or run `xattr -dr com.apple.quarantine /Applications/SolidCraft.app`). **Open** the first time (or run `xattr -dr com.apple.quarantine /Applications/SolidCraft.app`).
On Windows, SmartScreen may say "Windows protected your PC": **More info**, then **Run anyway**. On Windows, SmartScreen may say "Windows protected your PC": **More info**, then **Run anyway**.
Licences are built in (Help ▸ About ▸ Licences, `solvecraft-cli licences`); the packages also Licences are built in (Help ▸ About ▸ Licences, `solidcraft-cli licences`); the packages also
install `THIRD-PARTY-LICENSES.txt`. Known limitations: install `THIRD-PARTY-LICENSES.txt`. Known limitations:
[ROADMAP.md](https://github.com/bherbruck/solidcraft/blob/main/ROADMAP.md#known-limitations). [ROADMAP.md](https://github.com/bherbruck/solidcraft/blob/main/ROADMAP.md#known-limitations).
+2 -2
View File
@@ -218,9 +218,9 @@ jobs:
with: with:
version: v0.16.0 version: v0.16.0
- name: Build the command line - name: Build the command line
run: cargo build -p solvecraft-cli --profile ci --locked run: cargo build -p solidcraft-cli --profile ci --locked
- name: Replay tests/oracle and compare with expected.json - name: Replay tests/oracle and compare with expected.json
run: cargo xtask oracle --cli target/ci/solvecraft-cli run: cargo xtask oracle --cli target/ci/solidcraft-cli
- name: Upload the report - name: Upload the report
if: always() if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
+2 -2
View File
@@ -52,8 +52,8 @@ jobs:
} }
- name: XML, desktop entry, AppStream, Flatpak manifest - name: XML, desktop entry, AppStream, Flatpak manifest
run: | run: |
xmllint --noout packaging/windows/solvecraft.wxs packaging/windows/solvecraft.en-us.wxl packaging/macos/*.plist* packaging/linux/*.xml* xmllint --noout packaging/windows/solidcraft.wxs packaging/windows/solidcraft.en-us.wxl packaging/macos/*.plist* packaging/linux/*.xml*
desktop-file-validate packaging/linux/ai.storyteller.solvecraft.desktop desktop-file-validate packaging/linux/ai.storyteller.solvecraft.desktop
sed -e 's/@VERSION@/0.0.0/' -e 's/@DATE@/2026-01-01/' packaging/linux/ai.storyteller.solvecraft.metainfo.xml.in >"$RUNNER_TEMP/ai.storyteller.solvecraft.metainfo.xml" sed -e 's/@VERSION@/0.0.0/' -e 's/@DATE@/2026-01-01/' packaging/linux/ai.storyteller.solvecraft.metainfo.xml.in >"$RUNNER_TEMP/ai.storyteller.solvecraft.metainfo.xml"
appstreamcli validate --no-net --explain "$RUNNER_TEMP/ai.storyteller.solvecraft.metainfo.xml" appstreamcli validate --no-net --explain "$RUNNER_TEMP/ai.storyteller.solvecraft.metainfo.xml"
python3 -c "import yaml; m = yaml.safe_load(open('packaging/linux/flatpak/ai.storyteller.solvecraft.bundle.yml')); assert m['id'] == 'ai.storyteller.solvecraft' and m['command'] == 'solvecraft'" python3 -c "import yaml; m = yaml.safe_load(open('packaging/linux/flatpak/ai.storyteller.solvecraft.bundle.yml')); assert m['id'] == 'ai.storyteller.solvecraft' and m['command'] == 'solidcraft'"
+28 -23
View File
@@ -79,7 +79,7 @@ jobs:
{ echo "version=$VERSION"; echo "date=$(date -u +%Y-%m-%d)"; echo "prerelease=$pre"; } >>"$GITHUB_OUTPUT" { echo "version=$VERSION"; echo "date=$(date -u +%Y-%m-%d)"; echo "prerelease=$pre"; } >>"$GITHUB_OUTPUT"
echo "### SolidCraft v$VERSION (\`${GITHUB_SHA::9}\`)" >>"$GITHUB_STEP_SUMMARY" echo "### SolidCraft v$VERSION (\`${GITHUB_SHA::9}\`)" >>"$GITHUB_STEP_SUMMARY"
# The app icon in every size, drawn by solvecraft-cli (no image files are committed), for the # The app icon in every size, drawn by solidcraft-cli (no image files are committed), for the
# Windows jobs: the ARM64 build is cross-compiled and can't run there to draw its own. # Windows jobs: the ARM64 build is cross-compiled and can't run there to draw its own.
icons: icons:
needs: version needs: version
@@ -91,10 +91,10 @@ jobs:
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with: with:
key: release-icons key: release-icons
- run: cargo build --release --locked -p solvecraft-cli - run: cargo build --release --locked -p solidcraft-cli
- run: | - run: |
. packaging/env.sh . packaging/env.sh
make_icons target/release/solvecraft-cli icons make_icons target/release/solidcraft-cli icons
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: icons name: icons
@@ -114,8 +114,8 @@ jobs:
- { arch: x86_64, runner: ubuntu-22.04, deb: amd64 } - { arch: x86_64, runner: ubuntu-22.04, deb: amd64 }
- { arch: aarch64, runner: ubuntu-22.04-arm, deb: arm64 } - { arch: aarch64, runner: ubuntu-22.04-arm, deb: arm64 }
env: env:
SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
SOLVECRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
NFPM_VERSION: 2.47.0 NFPM_VERSION: 2.47.0
steps: steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -135,17 +135,22 @@ jobs:
- name: Check the packages - name: Check the packages
run: | run: |
dpkg-deb --info dist/release/*.deb dpkg-deb --info dist/release/*.deb
dpkg-deb --contents dist/release/*.deb | grep -E 'usr/bin/solvecraft$|usr/bin/solvecraft-cli$|metainfo|applications|THIRD-PARTY-LICENSES.txt' dpkg-deb --contents dist/release/*.deb | grep -E 'usr/bin/solidcraft$|usr/bin/solidcraft-cli$|metainfo|applications|THIRD-PARTY-LICENSES.txt'
# Compatibility shims (docs/compatibility.md): the old CLI name and the package rename.
dpkg-deb --contents dist/release/*.deb | grep -E 'usr/bin/solvecraft-cli$'
dpkg-deb --field dist/release/*.deb Replaces Conflicts Provides | grep -F solvecraft
rpm -qip dist/release/*.rpm rpm -qip dist/release/*.rpm
rpm -qlp dist/release/*.rpm | grep -E '/usr/bin/solvecraft$|THIRD-PARTY-LICENSES.txt' rpm -qlp dist/release/*.rpm | grep -E '/usr/bin/solidcraft$|THIRD-PARTY-LICENSES.txt'
tar -tzf dist/release/*.tar.gz | grep -E '/bin/solvecraft$|THIRD-PARTY-LICENSES.txt' tar -tzf dist/release/*.tar.gz | grep -E '/bin/solidcraft$|THIRD-PARTY-LICENSES.txt'
ldd target/release/solvecraft ldd target/release/solidcraft
for appimage in dist/release/*.AppImage; do for appimage in dist/release/*.AppImage; do
chmod +x "$appimage" chmod +x "$appimage"
APPIMAGE_EXTRACT_AND_RUN=1 "$appimage" --version APPIMAGE_EXTRACT_AND_RUN=1 "$appimage" --version
"$appimage" --appimage-updateinformation | grep -F 'gh-releases-zsync|' "$appimage" --appimage-updateinformation | grep -F 'gh-releases-zsync|'
test -s "$appimage.zsync" test -s "$appimage.zsync"
done done
# Legacy AppImage update alias (docs/compatibility.md).
ls dist/release/solvecraft-*-linux-*.AppImage.zsync
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: release-linux-${{ matrix.arch }} name: release-linux-${{ matrix.arch }}
@@ -166,8 +171,8 @@ jobs:
- { arch: x86_64, runner: ubuntu-24.04 } - { arch: x86_64, runner: ubuntu-24.04 }
- { arch: aarch64, runner: ubuntu-24.04-arm } - { arch: aarch64, runner: ubuntu-24.04-arm }
env: env:
SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
SOLVECRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
steps: steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
@@ -181,7 +186,7 @@ jobs:
# Ubuntu 24.04's AppArmor blocks the unprivileged user namespaces bubblewrap needs. # Ubuntu 24.04's AppArmor blocks the unprivileged user namespaces bubblewrap needs.
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
- name: Build the Flatpak bundle - name: Build the Flatpak bundle
run: packaging/linux/flatpak-bundle.sh "dist/linux/solvecraft-$SOLVECRAFT_VERSION-linux-${{ matrix.arch }}.tar.gz" run: packaging/linux/flatpak-bundle.sh "dist/linux/solidcraft-$SOLIDCRAFT_VERSION-linux-${{ matrix.arch }}.tar.gz"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: release-flatpak-${{ matrix.arch }} name: release-flatpak-${{ matrix.arch }}
@@ -198,8 +203,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 180 timeout-minutes: 180
env: env:
SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
SOLVECRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
steps: steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build and package in a FreeBSD VM (tar.gz) - name: Build and package in a FreeBSD VM (tar.gz)
@@ -211,7 +216,7 @@ jobs:
cpu: 4 cpu: 4
mem: 12288 mem: 12288
# Passed into the VM by name; never templated into the script below. # Passed into the VM by name; never templated into the script below.
envs: "SOLVECRAFT_VERSION SOLVECRAFT_BUILD_DATE" envs: "SOLIDCRAFT_VERSION SOLIDCRAFT_BUILD_DATE"
prepare: | prepare: |
pkg install -y bash git curl pkgconf libxkbcommon wayland libX11 libXcursor libXrandr libXi libxcb mesa-libs vulkan-loader pkg install -y bash git curl pkgconf libxkbcommon wayland libX11 libXcursor libXrandr libXi libxcb mesa-libs vulkan-loader
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
@@ -221,10 +226,10 @@ jobs:
git config --global --add safe.directory "$PWD" git config --global --add safe.directory "$PWD"
# Build outside the checkout so only dist/ is copied back out of the VM. 4 jobs: more # Build outside the checkout so only dist/ is copied back out of the VM. 4 jobs: more
# runs the VM out of memory. # runs the VM out of memory.
export CARGO_TARGET_DIR=/var/tmp/solvecraft-target CARGO_BUILD_JOBS=4 export CARGO_TARGET_DIR=/var/tmp/solidcraft-target CARGO_BUILD_JOBS=4
bash packaging/freebsd/package.sh bash packaging/freebsd/package.sh
tar -tzf dist/release/solvecraft-*-freebsd-x86_64.tar.gz \ tar -tzf dist/release/solidcraft-*-freebsd-x86_64.tar.gz \
| grep -E '/bin/solvecraft$|/bin/solvecraft-cli$|/share/applications/ai\.storyteller\.solvecraft\.desktop$|/share/doc/solvecraft/THIRD-PARTY-LICENSES\.txt$' | grep -E '/bin/solidcraft$|/bin/solidcraft-cli$|/share/applications/ai\.storyteller\.solvecraft\.desktop$|/share/doc/solidcraft/THIRD-PARTY-LICENSES\.txt$'
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
name: release-freebsd-x86_64 name: release-freebsd-x86_64
@@ -237,8 +242,8 @@ jobs:
if: needs.version.outputs.build == 'true' if: needs.version.outputs.build == 'true'
runs-on: macos-14 runs-on: macos-14
env: env:
SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
SOLVECRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
steps: steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
@@ -269,7 +274,7 @@ jobs:
# Windows on ARM: cross-compiled on the x64 runner. # Windows on ARM: cross-compiled on the x64 runner.
- { arch: arm64, target: aarch64-pc-windows-msvc } - { arch: arm64, target: aarch64-pc-windows-msvc }
env: env:
SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
steps: steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
@@ -290,7 +295,7 @@ jobs:
- name: Build and package (msi, portable zip) - name: Build and package (msi, portable zip)
shell: pwsh shell: pwsh
env: env:
SOLVECRAFT_ICONS: ${{ github.workspace }}/icons SOLIDCRAFT_ICONS: ${{ github.workspace }}/icons
run: ./packaging/windows/package.ps1 -Arch ${{ matrix.arch }} run: ./packaging/windows/package.ps1 -Arch ${{ matrix.arch }}
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with: with:
@@ -304,7 +309,7 @@ jobs:
if: needs.version.outputs.build == 'true' if: needs.version.outputs.build == 'true'
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
TRUNK_VERSION: 0.21.14 TRUNK_VERSION: 0.21.14
steps: steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+2 -2
View File
@@ -115,7 +115,7 @@ version bumps solely from commit prefixes, overwrite published versions, or push
before the draft is verified. before the draft is verified.
## Running and looking at the app ## Running and looking at the app
- `cargo run --release -p solvecraft -- --sample --control PORT` (sample design + control channel). - `cargo run --release -p solidcraft -- --sample --control PORT` (sample design + control channel).
Pick a free port. Without a display, run it under `Xvfb :99` with `DISPLAY=:99`. Pick a free port. Without a display, run it under `Xvfb :99` with `DISPLAY=:99`.
- Drive it with JSON lines on `127.0.0.1:PORT` (see `docs/control-protocol.md`): - Drive it with JSON lines on `127.0.0.1:PORT` (see `docs/control-protocol.md`):
- `{"id":1,"method":"engine.execute","params":{"command":"solid.extrude","params":{"distance":20}}}` - `{"id":1,"method":"engine.execute","params":{"command":"solid.extrude","params":{"distance":20}}}`
@@ -128,7 +128,7 @@ before the draft is verified.
- Reference tests: `cargo xtask oracle` replays `tests/oracle/*/recipe.json` and compares with - Reference tests: `cargo xtask oracle` replays `tests/oracle/*/recipe.json` and compares with
each case's `expected.json` (analytic or FreeCAD values; writes `docs/oracle.md`). Expected each case's `expected.json` (analytic or FreeCAD values; writes `docs/oracle.md`). Expected
values never come from a commercial CAD product. values never come from a commercial CAD product.
- Build with `CARGO_TARGET_DIR=<repo>/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. - Build with `CARGO_TARGET_DIR=<repo>/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solidcraft`.
## Roadmap ## Roadmap
`ROADMAP.md` (committed) tracks status, milestones and estimates. Update it whenever a `ROADMAP.md` (committed) tracks status, milestones and estimates. Update it whenever a
+2 -2
View File
@@ -92,7 +92,7 @@ version bumps solely from commit prefixes, overwrite published versions, or push
before the draft is verified. before the draft is verified.
## Running and looking at the app ## Running and looking at the app
- `cargo run --release -p solvecraft -- --sample --control PORT` (sample design + control channel). - `cargo run --release -p solidcraft -- --sample --control PORT` (sample design + control channel).
Pick a free port. Without a display, run it under `Xvfb :99` with `DISPLAY=:99`. Pick a free port. Without a display, run it under `Xvfb :99` with `DISPLAY=:99`.
- Drive it with JSON lines on `127.0.0.1:PORT` (see `docs/control-protocol.md`): - Drive it with JSON lines on `127.0.0.1:PORT` (see `docs/control-protocol.md`):
- `{"id":1,"method":"engine.execute","params":{"command":"solid.extrude","params":{"distance":20}}}` - `{"id":1,"method":"engine.execute","params":{"command":"solid.extrude","params":{"distance":20}}}`
@@ -105,7 +105,7 @@ before the draft is verified.
- Reference tests: `cargo xtask oracle` replays `tests/oracle/*/recipe.json` and compares with - Reference tests: `cargo xtask oracle` replays `tests/oracle/*/recipe.json` and compares with
each case's `expected.json` (analytic or FreeCAD values; writes `docs/oracle.md`). Expected each case's `expected.json` (analytic or FreeCAD values; writes `docs/oracle.md`). Expected
values never come from a commercial CAD product. values never come from a commercial CAD product.
- Build with `CARGO_TARGET_DIR=<repo>/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. - Build with `CARGO_TARGET_DIR=<repo>/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solidcraft`.
## Roadmap ## Roadmap
`ROADMAP.md` (committed) tracks status, milestones and estimates. Update it whenever a `ROADMAP.md` (committed) tracks status, milestones and estimates. Update it whenever a
+5 -5
View File
@@ -17,23 +17,23 @@ build you also need `rustup target add wasm32-unknown-unknown` and [`trunk`](htt
```sh ```sh
git clone https://github.com/bherbruck/solidcraft && cd solidcraft git clone https://github.com/bherbruck/solidcraft && cd solidcraft
cargo run --release -p solvecraft -- --sample # desktop app with a sample part cargo run --release -p solidcraft -- --sample # desktop app with a sample part
cargo xtask test # unit, engine and UI-scenario tests cargo xtask test # unit, engine and UI-scenario tests
cargo xtask ci # everything a PR must pass (see below) cargo xtask ci # everything a PR must pass (see below)
``` ```
SolidCraft is the product and repository name. Cargo packages and executables retain SolidCraft is the product and repository name. Cargo packages and executables retain
their `solvecraft` names for compatibility with existing scripts and MCP clients. their `solvecraft` names for compatibility with existing scripts and MCP clients.
Build the desktop app with `cargo build --release -p solvecraft`, or the CLI with Build the desktop app with `cargo build --release -p solidcraft`, or the CLI with
`cargo build --release -p solvecraft-cli`. Run the CLI with `cargo build --release -p solidcraft-cli`. Run the CLI with
`cargo run --release -p solvecraft-cli -- commands` (or `target/release/solvecraft-cli commands` `cargo run --release -p solidcraft-cli -- commands` (or `target/release/solidcraft-cli commands`
after building). There is no Cargo package named `solidcraft`. after building). There is no Cargo package named `solidcraft`.
Web: `cd apps/solvecraft-web && trunk serve --release`, then open the printed URL (`?sample` Web: `cd apps/solvecraft-web && trunk serve --release`, then open the printed URL (`?sample`
opens the sample part, `?webgl` forces WebGL2). Saving and opening files in the browser needs opens the sample part, `?webgl` forces WebGL2). Saving and opening files in the browser needs
HTTPS or localhost, because it uses the Origin Private File System. HTTPS or localhost, because it uses the Origin Private File System.
Windows from Linux: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. Windows from Linux: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solidcraft`.
### NixOS: `nix develop` ### NixOS: `nix develop`
Generated
+2 -2
View File
@@ -3289,7 +3289,7 @@ dependencies = [
] ]
[[package]] [[package]]
name = "solvecraft" name = "solidcraft"
version = "0.5.0" version = "0.5.0"
dependencies = [ dependencies = [
"eframe", "eframe",
@@ -3306,7 +3306,7 @@ dependencies = [
] ]
[[package]] [[package]]
name = "solvecraft-cli" name = "solidcraft-cli"
version = "0.5.0" version = "0.5.0"
dependencies = [ dependencies = [
"serde_json", "serde_json",
+7 -7
View File
@@ -100,16 +100,16 @@ renamed repository; old-name Pages and Flatpak URLs are not maintained as perman
## Build and run ## Build and run
```sh ```sh
cargo run --release -p solvecraft -- --sample # desktop app with a sample part cargo run --release -p solidcraft -- --sample # desktop app with a sample part
cargo run --release -p solvecraft-cli -- commands # the command registry cargo run --release -p solidcraft-cli -- commands # the command registry
cargo run --release -p solvecraft-cli -- run examples/bracket.json --out bracket.step cargo run --release -p solidcraft-cli -- run examples/bracket.json --out bracket.step
cargo run --release -p solvecraft-cli -- snapshot examples/bracket.json --out bracket.png cargo run --release -p solidcraft-cli -- snapshot examples/bracket.json --out bracket.png
cargo run --release -p solvecraft -- part.step # open a STEP file as a new design cargo run --release -p solidcraft -- part.step # open a STEP file as a new design
cargo run --release -p solvecraft-cli -- eval part.step # measure an imported STEP file cargo run --release -p solidcraft-cli -- eval part.step # measure an imported STEP file
cargo xtask ci # fmt, clippy, tests, assets, layers, wasm cargo xtask ci # fmt, clippy, tests, assets, layers, wasm
``` ```
Windows builds: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. Windows builds: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solidcraft`.
On Windows and Linux, SolidCraft detects a connected 3Dconnexion SpaceNavigator or SpaceMouse through its On Windows and Linux, SolidCraft detects a connected 3Dconnexion SpaceNavigator or SpaceMouse through its
multi-axis HID interface. Move the cap to pan and zoom, and tilt or twist it to rotate the 3D view. multi-axis HID interface. Move the cap to pan and zoom, and tilt or twist it to rotate the 3D view.
+9 -2
View File
@@ -1,17 +1,24 @@
[package] [package]
name = "solvecraft-cli" name = "solidcraft-cli"
description = "SolidCraft headless CLI: run command scripts, measure, export, render snapshots, replay oracle recipes" description = "SolidCraft headless CLI: run command scripts, measure, export, render snapshots, replay oracle recipes"
version.workspace = true version.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
default-run = "solidcraft-cli"
[lints] [lints]
workspace = true workspace = true
[[bin]] [[bin]]
name = "solvecraft-cli" name = "solidcraft-cli"
path = "src/main.rs" path = "src/main.rs"
# Compatibility alias for the CLI's former name: forwards to solidcraft-cli with a deprecation
# note on stderr. Shipped in every package for at least one release.
[[bin]]
name = "solvecraft-cli"
path = "src/alias.rs"
[dependencies] [dependencies]
solvecraft-engine = { workspace = true } solvecraft-engine = { workspace = true }
solvecraft-mcp = { workspace = true } solvecraft-mcp = { workspace = true }
+30
View File
@@ -0,0 +1,30 @@
//! `solvecraft-cli`: the CLI's former name, kept for at least one release so existing scripts
//! and MCP client setups (`claude mcp add solvecraft -- solvecraft-cli mcp`) keep working.
//! Compatibility shim: it runs `solidcraft-cli` (next to this executable, else on PATH) with the
//! same arguments and standard streams, after a one-line deprecation note on stderr (stdout
//! stays clean for MCP's JSON-RPC), and exits with its status.
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
#![forbid(unsafe_code)]
use std::process::{Command, ExitCode};
const TARGET: &str = "solidcraft-cli";
fn main() -> ExitCode {
eprintln!("solvecraft-cli is deprecated and will be removed in a later release: use solidcraft-cli");
let sibling = std::env::current_exe()
.ok()
.and_then(|exe| exe.parent().map(|dir| dir.join(format!("{TARGET}{}", std::env::consts::EXE_SUFFIX))))
.filter(|p| p.is_file());
let program = sibling.map(|p| p.into_os_string()).unwrap_or_else(|| TARGET.into());
match Command::new(&program).args(std::env::args_os().skip(1)).status() {
Ok(status) => match status.code() {
Some(code) => ExitCode::from(u8::try_from(code).unwrap_or(1)),
None => ExitCode::FAILURE,
},
Err(e) => {
eprintln!("solvecraft-cli: could not run {}: {e}", program.to_string_lossy());
ExitCode::FAILURE
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
//! `solvecraft-cli fuzz`: random modelling sessions and boolean checks (docs/robustness.md). //! `solidcraft-cli fuzz`: random modelling sessions and boolean checks (docs/robustness.md).
//! //!
//! Each seed runs in its own process (`fuzz-one`) with a time limit, so a hang or a hard crash //! Each seed runs in its own process (`fuzz-one`) with a time limit, so a hang or a hard crash
//! is recorded like any other failure. //! is recorded like any other failure.
+28 -28
View File
@@ -1,17 +1,17 @@
//! SolveCraft headless command line. //! SolveCraft headless command line.
//! //!
//! ```text //! ```text
//! solvecraft-cli run <script.json|design.solvecraft|part.step|mesh.3mf> [--in design|part.step|mesh.3mf] [--out FILE]... [--save FILE] [--quiet] //! solidcraft-cli run <script.json|design.solvecraft|part.step|mesh.3mf> [--in design|part.step|mesh.3mf] [--out FILE]... [--save FILE] [--quiet]
//! solvecraft-cli eval <script.json|design.solvecraft|part.step> (alias: inspect) measurements as JSON //! solidcraft-cli eval <script.json|design.solvecraft|part.step> (alias: inspect) measurements as JSON
//! solvecraft-cli bench-open <design.solvecraft | part.step> [--parse-only] loading timings as JSON lines //! solidcraft-cli bench-open <design.solvecraft | part.step> [--parse-only] loading timings as JSON lines
//! solvecraft-cli snapshot <script|design> --out shot.png [--width W] [--height H] [--view iso|front|top|…] //! solidcraft-cli snapshot <script|design> --out shot.png [--width W] [--height H] [--view iso|front|top|…]
//! solvecraft-cli exec <command> [json-params] run one command on an empty design //! solidcraft-cli exec <command> [json-params] run one command on an empty design
//! solvecraft-cli commands the command registry as JSON //! solidcraft-cli commands the command registry as JSON
//! solvecraft-cli recipe <recipe.json> translate an oracle recipe to a script //! solidcraft-cli recipe <recipe.json> translate an oracle recipe to a script
//! solvecraft-cli oracle <case-dir>... replay recipes and compare with expected.json //! solidcraft-cli oracle <case-dir>... replay recipes and compare with expected.json
//! solvecraft-cli mcp [--in design|script] [--connect HOST:PORT] MCP server on stdio (docs/mcp.md) //! solidcraft-cli mcp [--in design|script] [--connect HOST:PORT] MCP server on stdio (docs/mcp.md)
//! solvecraft-cli licences SolveCraft's licence and the third-party licences //! solidcraft-cli licences SolveCraft's licence and the third-party licences
//! solvecraft-cli icon --out F.png|F.ico [--size N] the app icon (packaging; drawn, not a file) //! solidcraft-cli icon --out F.png|F.ico [--size N] the app icon (packaging; drawn, not a file)
//! ``` //! ```
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
@@ -31,19 +31,19 @@ use solvecraft_engine::Session;
use solvecraft_engine::render::{StandardView, render_png}; use solvecraft_engine::render::{StandardView, render_png};
const USAGE: &str = "usage: const USAGE: &str = "usage:
solvecraft-cli run <script.json|design.solvecraft|part.step> [--in design.solvecraft|part.step] [--out FILE]... [--save FILE] [--quiet] [--results] solidcraft-cli run <script.json|design.solvecraft|part.step> [--in design.solvecraft|part.step] [--out FILE]... [--save FILE] [--quiet] [--results]
solvecraft-cli run --in <design.solvecraft|part.step> [--out FILE]... solidcraft-cli run --in <design.solvecraft|part.step> [--out FILE]...
solvecraft-cli eval <script.json|design.solvecraft|part.step> (alias: inspect; or --in FILE) solidcraft-cli eval <script.json|design.solvecraft|part.step> (alias: inspect; or --in FILE)
solvecraft-cli bench-open <design.solvecraft | part.step> [--parse-only] solidcraft-cli bench-open <design.solvecraft | part.step> [--parse-only]
solvecraft-cli snapshot <script|design> --out shot.png [--width W] [--height H] [--view iso|front|back|top|bottom|left|right] solidcraft-cli snapshot <script|design> --out shot.png [--width W] [--height H] [--view iso|front|back|top|bottom|left|right]
solvecraft-cli exec <command> [json-params] solidcraft-cli exec <command> [json-params]
solvecraft-cli commands solidcraft-cli commands
solvecraft-cli recipe <recipe.json> solidcraft-cli recipe <recipe.json>
solvecraft-cli oracle <case-dir>... [--json] solidcraft-cli oracle <case-dir>... [--json]
solvecraft-cli fuzz [--from N] [--count N] [--jobs J] [--timeout S] [--steps N] [--minimise] [--out DIR] [--report FILE] solidcraft-cli fuzz [--from N] [--count N] [--jobs J] [--timeout S] [--steps N] [--minimise] [--out DIR] [--report FILE]
solvecraft-cli mcp [--in design.solvecraft|script.json] [--connect 127.0.0.1:PORT] solidcraft-cli mcp [--in design.solvecraft|script.json] [--connect 127.0.0.1:PORT]
solvecraft-cli licences solidcraft-cli licences
solvecraft-cli icon --out icon.png [--size 256] | --out icon.ico solidcraft-cli icon --out icon.png [--size 256] | --out icon.ico
"; ";
fn main() -> ExitCode { fn main() -> ExitCode {
@@ -87,7 +87,7 @@ fn main() -> ExitCode {
Some("bench-edit") => cmd_bench_edit(&args[1..]), Some("bench-edit") => cmd_bench_edit(&args[1..]),
Some("bench-open") => cmd_bench_open(&args[1..]), Some("bench-open") => cmd_bench_open(&args[1..]),
Some("--version" | "-V") => { Some("--version" | "-V") => {
println!("solvecraft-cli {}", env!("CARGO_PKG_VERSION")); println!("solidcraft-cli {}", env!("CARGO_PKG_VERSION"));
Ok(()) Ok(())
} }
_ => Err(USAGE.to_string()), _ => Err(USAGE.to_string()),
@@ -305,7 +305,7 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
/// parameter `save_round` set to the round number each time. /// parameter `save_round` set to the round number each time.
fn cmd_save_stress(args: &[String]) -> Result<(), String> { fn cmd_save_stress(args: &[String]) -> Result<(), String> {
let (Some(path), Some(rounds)) = (args.first(), args.get(1).and_then(|n| n.parse::<u64>().ok())) else { let (Some(path), Some(rounds)) = (args.first(), args.get(1).and_then(|n| n.parse::<u64>().ok())) else {
return Err("usage: solvecraft-cli save-stress <path> <rounds>".into()); return Err("usage: solidcraft-cli save-stress <path> <rounds>".into());
}; };
let mut s = Session::default(); let mut s = Session::default();
let filler = (0..3000).map(|i| solvecraft_engine::doc::Param { let filler = (0..3000).map(|i| solvecraft_engine::doc::Param {
@@ -327,7 +327,7 @@ fn cmd_save_stress(args: &[String]) -> Result<(), String> {
/// parameter edit, setting it back, undo and redo (ms and features recomputed each). /// parameter edit, setting it back, undo and redo (ms and features recomputed each).
fn cmd_bench_edit(args: &[String]) -> Result<(), String> { fn cmd_bench_edit(args: &[String]) -> Result<(), String> {
let (Some(path), Some(param), Some(expr)) = (args.first(), args.get(1), args.get(2)) else { let (Some(path), Some(param), Some(expr)) = (args.first(), args.get(1), args.get(2)) else {
return Err("usage: solvecraft-cli bench-edit <script.json|recipe.json> <param> <expr>".into()); return Err("usage: solidcraft-cli bench-edit <script.json|recipe.json> <param> <expr>".into());
}; };
let v = read_json(path)?; let v = read_json(path)?;
let script = if v.get("features").is_some() { recipe::to_script(&v)? } else { v }; let script = if v.get("features").is_some() { recipe::to_script(&v)? } else { v };
@@ -355,7 +355,7 @@ fn cmd_bench_edit(args: &[String]) -> Result<(), String> {
/// Separate file reading, JSON decoding/repair, timeline evaluation and display meshing. /// Separate file reading, JSON decoding/repair, timeline evaluation and display meshing.
fn cmd_bench_open(args: &[String]) -> Result<(), String> { fn cmd_bench_open(args: &[String]) -> Result<(), String> {
let path = args.first().ok_or("usage: solvecraft-cli bench-open <design.solvecraft | part.step> [--parse-only]")?; let path = args.first().ok_or("usage: solidcraft-cli bench-open <design.solvecraft | part.step> [--parse-only]")?;
let t = std::time::Instant::now(); let t = std::time::Instant::now();
let step = solvecraft_engine::io::is_step_path(path); let step = solvecraft_engine::io::is_step_path(path);
let limit = if step { solvecraft_engine::io::MAX_STEP_BYTES } else { solvecraft_engine::io::MAX_DESIGN_BYTES }; let limit = if step { solvecraft_engine::io::MAX_STEP_BYTES } else { solvecraft_engine::io::MAX_DESIGN_BYTES };
+2 -2
View File
@@ -4,7 +4,7 @@ use std::process::{Command, Stdio};
#[test] #[test]
fn registry_output_is_complete_json() { fn registry_output_is_complete_json() {
let output = Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")).arg("commands").output().unwrap(); let output = Command::new(env!("CARGO_BIN_EXE_solidcraft-cli")).arg("commands").output().unwrap();
assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr)); assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr));
let registry: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); let registry: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
let commands = registry.as_array().unwrap(); let commands = registry.as_array().unwrap();
@@ -16,7 +16,7 @@ fn registry_output_is_complete_json() {
#[test] #[test]
fn closed_registry_pipe_exits_without_panicking() { fn closed_registry_pipe_exits_without_panicking() {
let mut child = Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")).arg("commands").stdout(Stdio::piped()).stderr(Stdio::piped()).spawn().unwrap(); let mut child = Command::new(env!("CARGO_BIN_EXE_solidcraft-cli")).arg("commands").stdout(Stdio::piped()).stderr(Stdio::piped()).spawn().unwrap();
// Close our read end before waiting. No sleeps or timing threshold are needed: // Close our read end before waiting. No sleeps or timing threshold are needed:
// the registry is larger than the pipe buffer, so it cannot all be written first. // the registry is larger than the pipe buffer, so it cannot all be written first.
drop(child.stdout.take()); drop(child.stdout.take());
+3 -3
View File
@@ -5,7 +5,7 @@ use std::process::Command;
#[test] #[test]
fn overflowing_seed_range_is_an_error_not_a_panic() { fn overflowing_seed_range_is_an_error_not_a_panic() {
let output = let output =
Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")).args(["fuzz", "--from", "18446744073709551615", "--count", "2"]).output().unwrap(); Command::new(env!("CARGO_BIN_EXE_solidcraft-cli")).args(["fuzz", "--from", "18446744073709551615", "--count", "2"]).output().unwrap();
assert_eq!(output.status.code(), Some(1)); assert_eq!(output.status.code(), Some(1));
let stderr = String::from_utf8_lossy(&output.stderr); let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("seed range exceeds u64::MAX"), "{stderr}"); assert!(stderr.contains("seed range exceeds u64::MAX"), "{stderr}");
@@ -15,14 +15,14 @@ fn overflowing_seed_range_is_an_error_not_a_panic() {
#[test] #[test]
fn empty_seed_range_at_maximum_is_valid() { fn empty_seed_range_at_maximum_is_valid() {
let output = let output =
Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")).args(["fuzz", "--from", "18446744073709551615", "--count", "0"]).output().unwrap(); Command::new(env!("CARGO_BIN_EXE_solidcraft-cli")).args(["fuzz", "--from", "18446744073709551615", "--count", "0"]).output().unwrap();
assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr)); assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr));
assert!(String::from_utf8_lossy(&output.stdout).starts_with("0 seeds, 0 design steps,")); assert!(String::from_utf8_lossy(&output.stdout).starts_with("0 seeds, 0 design steps,"));
} }
#[test] #[test]
fn maximum_seed_runs_once_without_wrapping() { fn maximum_seed_runs_once_without_wrapping() {
let output = Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")) let output = Command::new(env!("CARGO_BIN_EXE_solidcraft-cli"))
.args(["fuzz", "--from", "18446744073709551615", "--count", "1", "--steps", "0", "--timeout", "0"]) .args(["fuzz", "--from", "18446744073709551615", "--count", "1", "--steps", "0", "--timeout", "0"])
.output() .output()
.unwrap(); .unwrap();
+1 -1
View File
@@ -12,7 +12,7 @@ fn round_of(path: &std::path::Path) -> Option<String> {
#[test] #[test]
fn killed_mid_save_the_old_file_survives() { fn killed_mid_save_the_old_file_survives() {
let exe = env!("CARGO_BIN_EXE_solvecraft-cli"); let exe = env!("CARGO_BIN_EXE_solidcraft-cli");
let dir = std::env::temp_dir().join(format!("solvecraft-kill-mid-save-{}", std::process::id())); let dir = std::env::temp_dir().join(format!("solvecraft-kill-mid-save-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir); let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap(); std::fs::create_dir_all(&dir).unwrap();
+20
View File
@@ -0,0 +1,20 @@
//! The `solvecraft-cli` compatibility alias forwards to `solidcraft-cli`.
use std::process::Command;
#[test]
fn legacy_alias_forwards_with_a_deprecation_note() {
let out = Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")).arg("--version").output().unwrap();
assert!(out.status.success(), "{out:?}");
let stdout = String::from_utf8_lossy(&out.stdout);
assert_eq!(stdout.trim(), format!("solidcraft-cli {}", env!("CARGO_PKG_VERSION")));
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(stderr.contains("deprecated") && stderr.contains("solidcraft-cli"), "{stderr}");
}
#[test]
fn legacy_alias_passes_the_exit_status_through() {
let alias = Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")).arg("no-such-command").output().unwrap();
let real = Command::new(env!("CARGO_BIN_EXE_solidcraft-cli")).arg("no-such-command").output().unwrap();
assert_eq!(alias.status.code(), real.status.code());
assert_eq!(alias.stdout, real.stdout);
}
+1 -1
View File
@@ -7,7 +7,7 @@ use std::process::{Command, Stdio};
fn mcp_connect_without_a_listening_app_names_the_control_flag() { fn mcp_connect_without_a_listening_app_names_the_control_flag() {
// A port that was free a moment ago: nothing listens on it. // A port that was free a moment ago: nothing listens on it.
let port = TcpListener::bind("127.0.0.1:0").unwrap().local_addr().unwrap().port(); let port = TcpListener::bind("127.0.0.1:0").unwrap().local_addr().unwrap().port();
let output = Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")) let output = Command::new(env!("CARGO_BIN_EXE_solidcraft-cli"))
.args(["mcp", "--connect", &format!("127.0.0.1:{port}")]) .args(["mcp", "--connect", &format!("127.0.0.1:{port}")])
.stdin(Stdio::null()) .stdin(Stdio::null())
.output() .output()
+1 -1
View File
@@ -31,7 +31,7 @@ impl Drop for Scratch {
} }
fn cli() -> Command { fn cli() -> Command {
Command::new(env!("CARGO_BIN_EXE_solvecraft-cli")) Command::new(env!("CARGO_BIN_EXE_solidcraft-cli"))
} }
fn json_output(output: Output) -> Value { fn json_output(output: Output) -> Value {
+2 -2
View File
@@ -1,11 +1,11 @@
[package] [package]
name = "solvecraft" name = "solidcraft"
description = "SolidCraft desktop app" description = "SolidCraft desktop app"
version.workspace = true version.workspace = true
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true
publish = false publish = false
default-run = "solvecraft" default-run = "solidcraft"
[lints] [lints]
workspace = true workspace = true
+1 -1
View File
@@ -56,6 +56,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let rc = out.join("solidcraft.rc"); let rc = out.join("solidcraft.rc");
std::fs::write(&rc, format!("1 ICON \"{}\"\n", icon.display().to_string().replace('\\', "/")))?; std::fs::write(&rc, format!("1 ICON \"{}\"\n", icon.display().to_string().replace('\\', "/")))?;
// Missing resource tools are a build error, rather than silently shipping a generic icon. // Missing resource tools are a build error, rather than silently shipping a generic icon.
embed_resource::compile_for(&rc, ["solvecraft"], embed_resource::NONE).manifest_required()?; embed_resource::compile_for(&rc, ["solidcraft"], embed_resource::NONE).manifest_required()?;
Ok(()) Ok(())
} }
+2 -2
View File
@@ -155,11 +155,11 @@ fn main() -> eframe::Result {
"--control" => control_port = args.next().and_then(|p| p.parse().ok()), "--control" => control_port = args.next().and_then(|p| p.parse().ok()),
"--sample" => sample = true, "--sample" => sample = true,
"--version" | "-V" => { "--version" | "-V" => {
println!("solvecraft {}", env!("CARGO_PKG_VERSION")); println!("solidcraft {}", env!("CARGO_PKG_VERSION"));
return Ok(()); return Ok(());
} }
"--help" | "-h" => { "--help" | "-h" => {
println!("usage: solvecraft [--control PORT] [--sample] [design.solvecraft | part.step]"); println!("usage: solidcraft [--control PORT] [--sample] [design.solvecraft | part.step]");
return Ok(()); return Ok(());
} }
_ => files.push(a), _ => files.push(a),
+7 -7
View File
@@ -12,12 +12,12 @@ stable Rust (1.95 or newer):
```sh ```sh
git clone https://github.com/bherbruck/solidcraft && cd solidcraft git clone https://github.com/bherbruck/solidcraft && cd solidcraft
cargo run --release -p solvecraft -- --sample # opens with a sample part cargo run --release -p solidcraft -- --sample # opens with a sample part
``` ```
`solvecraft part.step` opens a STEP, IGES, 3MF, STL or OBJ file as a new design, and `solvecraft part.step` opens a STEP, IGES, 3MF, STL or OBJ file as a new design, and
`solvecraft design.solvecraft` opens a saved design. Windows builds cross-compile from Linux with `solvecraft design.solvecraft` opens a saved design. Windows builds cross-compile from Linux with
`cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. `cargo xwin build --release --target x86_64-pc-windows-msvc -p solidcraft`.
### macOS ### macOS
@@ -71,11 +71,11 @@ cd apps/solvecraft-web && trunk serve --release
`solvecraft-cli` runs the same commands without a window: `solvecraft-cli` runs the same commands without a window:
```sh ```sh
cargo run --release -p solvecraft-cli -- commands # every command, as JSON cargo run --release -p solidcraft-cli -- commands # every command, as JSON
cargo run --release -p solvecraft-cli -- run examples/bracket.json --out bracket.step cargo run --release -p solidcraft-cli -- run examples/bracket.json --out bracket.step
cargo run --release -p solvecraft-cli -- eval examples/bracket.json # volume, area, faces… cargo run --release -p solidcraft-cli -- eval examples/bracket.json # volume, area, faces…
cargo run --release -p solvecraft-cli -- snapshot examples/bracket.json --out bracket.png cargo run --release -p solidcraft-cli -- snapshot examples/bracket.json --out bracket.png
cargo run --release -p solvecraft-cli -- exec solid.box '{"length": 20, "width": 10, "height": 5}' cargo run --release -p solidcraft-cli -- exec solid.box '{"length": 20, "width": 10, "height": 5}'
``` ```
A script is a list of commands: A script is a list of commands:
+26
View File
@@ -0,0 +1,26 @@
# Compatibility shims for the SolveCraft → SolidCraft rename
The product is SolidCraft everywhere. The old name survives only in the shims listed here,
each kept so that existing installs, scripts and files keep working. Remove a shim only in a
release whose notes say so.
## Programs and packages (since 0.5.0)
| Shim | Where | Why | Test |
|---|---|---|---|
| `solvecraft-cli` alias binary: forwards every argument and stream to `solidcraft-cli`, prints a one-line deprecation note on stderr, exits with its status | `apps/solvecraft-cli/src/alias.rs`; shipped by every package (deb, rpm, tar.gz, AppImage, Flatpak, FreeBSD, MSI, portable zip, macOS CLI zip, Nix) | scripts and MCP client setups (`claude mcp add solvecraft -- solvecraft-cli mcp`) keep working for at least one release | `apps/solvecraft-cli/tests/legacy_alias.rs`; release workflow checks the deb contents |
| Linux app ID `ai.storyteller.solvecraft` (Flatpak ID, desktop entry, metainfo, MIME and icon file names, Wayland app_id) | `packaging/env.sh` (`APP_ID`), `packaging/linux/*`, the app's `with_app_id` | a new Flatpak ID would be a different app: installed Flatpaks would never update. The desktop entry, metainfo and Wayland app_id must equal the Flatpak ID | packaging-lint workflow; Flatpak smoke test |
| MSI `UpgradeCode` `6A145FD6-D285-428D-AE84-A69570CDF4DB` (a GUID, no name in it) | `packaging/windows/solidcraft.wxs` | the new MSI upgrades an existing install in place. The install folder moves to `Program Files\SolidCraft` (registry `Software\SolidCraft`); a custom folder chosen for an earlier version is not carried over this once | release workflow (MSI build) |
| deb `Replaces`/`Conflicts`/`Provides: solvecraft`, rpm `Obsoletes`/`Provides: solvecraft` | `packaging/linux/nfpm.yaml` | installing the `solidcraft` package replaces the old `solvecraft` one instead of clashing with its files | release workflow checks the deb fields |
| A copy of each AppImage's `.zsync` under the old name `solvecraft-<ver>-linux-<arch>.AppImage.zsync` | `packaging/linux/package.sh` | earlier AppImages carry update information that looks for that name; the copy points at the new AppImage | release workflow |
| `solvecraft.flatpakrepo` next to `solidcraft.flatpakrepo` | `packaging/flatpak-site.sh` | links in earlier instructions keep working (existing remotes use the repository URL, which is unchanged) | Pages workflow |
| `.solvecraft` file associations (Windows ProgId extension, macOS document type, freedesktop MIME glob and `application/x-solvecraft` alias) | `packaging/windows/solidcraft.wxs`, `packaging/macos/Info.plist.in`, `packaging/linux/ai.storyteller.solvecraft.mime.xml` | existing design files keep opening in SolidCraft from the file manager | packaging-lint workflow |
| `SOLVECRAFT_VERSION`, `SOLVECRAFT_BUILD_DATE`, `SOLVECRAFT_MAINTAINER`, `SOLVECRAFT_NO_DESKTOP_INTEGRATION` read when the `SOLIDCRAFT_*` name is unset | `packaging/env.sh`, `packaging/linux/package.sh`, `packaging/linux/AppRun` | build scripts and AppImage users' environments keep working | packaging tests |
## Not kept
- The macOS bundle identifier is now `ai.storyteller.solidcraft`: apps are installed by dragging
from the DMG and there is no updater keyed on it. The first launch may ask again for Gatekeeper
approval.
- The GUI binary has no alias: every package's launcher, shortcut and file association runs
`solidcraft`.
+10 -12
View File
@@ -63,8 +63,8 @@
echo "SolidCraft: ${driverLibDir pkgs} is missing — on NixOS enable hardware.graphics; on other distributions use a matching nixGL driver wrapper." >&2 echo "SolidCraft: ${driverLibDir pkgs} is missing — on NixOS enable hardware.graphics; on other distributions use a matching nixGL driver wrapper." >&2
fi fi
''} ''}
command -v cc >/dev/null || echo "solvecraft: no C linker on PATH, cargo cannot link — use nix develop .#rust" >&2 command -v cc >/dev/null || echo "solidcraft: no C linker on PATH, cargo cannot link — use nix develop .#rust" >&2
echo "solvecraft: cargo run --release -p solvecraft -- --sample" echo "solidcraft: cargo run --release -p solidcraft -- --sample"
${pkgs.lib.optionalString pkgs.stdenv.isLinux '' ${pkgs.lib.optionalString pkgs.stdenv.isLinux ''
export XDG_DATA_DIRS="${driverShareDir pkgs}:''${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" export XDG_DATA_DIRS="${driverShareDir pkgs}:''${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
''} ''}
@@ -97,7 +97,7 @@
CARGO_TARGET_DIR = "target/nix"; CARGO_TARGET_DIR = "target/nix";
shellHook = '' shellHook = ''
${shellHook pkgs} ${shellHook pkgs}
echo "solvecraft: $(rustc --version), building into target/nix" echo "solidcraft: $(rustc --version), building into target/nix"
''; '';
}; };
}); });
@@ -116,15 +116,15 @@
# The CLI draws the same packaging icons as the other Linux distributions. # The CLI draws the same packaging icons as the other Linux distributions.
cargoBuildFlags = [ cargoBuildFlags = [
"-p" "-p"
"solvecraft" "solidcraft"
"-p" "-p"
"solvecraft-cli" "solidcraft-cli"
]; ];
cargoInstallFlags = [ cargoInstallFlags = [
"-p" "-p"
"solvecraft" "solidcraft"
"-p" "-p"
"solvecraft-cli" "solidcraft-cli"
]; ];
# `cargo xtask ci` is the test gate (it wants a wasm target and a GPU); the sandbox has # `cargo xtask ci` is the test gate (it wants a wasm target and a GPU); the sandbox has
# neither. # neither.
@@ -134,7 +134,6 @@
buildInputs = runtimeLibs pkgs; buildInputs = runtimeLibs pkgs;
postInstall = '' postInstall = ''
ln -s solvecraft $out/bin/solidcraft
${pkgs.lib.optionalString pkgs.stdenv.isLinux '' ${pkgs.lib.optionalString pkgs.stdenv.isLinux ''
install -Dm644 packaging/linux/ai.storyteller.solvecraft.desktop \ install -Dm644 packaging/linux/ai.storyteller.solvecraft.desktop \
$out/share/applications/ai.storyteller.solvecraft.desktop $out/share/applications/ai.storyteller.solvecraft.desktop
@@ -143,7 +142,7 @@
for size in 16 24 32 48 64 128 256 512; do for size in 16 24 32 48 64 128 256 512; do
icon=$out/share/icons/hicolor/''${size}x''${size}/apps/ai.storyteller.solvecraft.png icon=$out/share/icons/hicolor/''${size}x''${size}/apps/ai.storyteller.solvecraft.png
mkdir -p "$(dirname "$icon")" mkdir -p "$(dirname "$icon")"
$out/bin/solvecraft-cli icon --size "$size" --out "$icon" >/dev/null $out/bin/solidcraft-cli icon --size "$size" --out "$icon" >/dev/null
done done
''} ''}
''; '';
@@ -151,7 +150,7 @@
# Linux only: the app reaches the window through dlopen'd libraries, so the packaged # Linux only: the app reaches the window through dlopen'd libraries, so the packaged
# binary needs the same LD_LIBRARY_PATH the shell exports. macOS needs no wrapper. # binary needs the same LD_LIBRARY_PATH the shell exports. macOS needs no wrapper.
postFixup = pkgs.lib.optionalString pkgs.stdenv.isLinux '' postFixup = pkgs.lib.optionalString pkgs.stdenv.isLinux ''
wrapProgram $out/bin/solvecraft \ wrapProgram $out/bin/solidcraft \
--prefix LD_LIBRARY_PATH : "${libraryPath pkgs}" \ --prefix LD_LIBRARY_PATH : "${libraryPath pkgs}" \
--set-default XDG_DATA_DIRS /usr/local/share:/usr/share \ --set-default XDG_DATA_DIRS /usr/local/share:/usr/share \
--prefix XDG_DATA_DIRS : "$out/share:${driverShareDir pkgs}" --prefix XDG_DATA_DIRS : "$out/share:${driverShareDir pkgs}"
@@ -175,8 +174,7 @@
in { in {
default = desktop; default = desktop;
solidcraft = desktop; solidcraft = desktop;
solvecraft = { type = "app"; program = "${package}/bin/solvecraft"; }; cli = { type = "app"; program = "${package}/bin/solidcraft-cli"; };
cli = { type = "app"; program = "${package}/bin/solvecraft-cli"; };
}); });
}; };
} }
+15 -9
View File
@@ -4,9 +4,12 @@
# #
# Exports: # Exports:
# ROOT workspace root # ROOT workspace root
# VERSION [workspace.package] version from Cargo.toml (override: SOLVECRAFT_VERSION) # VERSION [workspace.package] version from Cargo.toml (override: SOLIDCRAFT_VERSION)
#
# Every SOLIDCRAFT_* override also accepts the pre-rename SOLVECRAFT_* name when the new one is
# unset (compatibility shim, see docs/compatibility.md).
# DIST output directory for release artifacts (default: $ROOT/dist/release) # DIST output directory for release artifacts (default: $ROOT/dist/release)
# SOLVECRAFT_BUILD_DATE UTC build date, YYYY-MM-DD # SOLIDCRAFT_BUILD_DATE UTC build date, YYYY-MM-DD
# CARGO_TARGET_DIR cargo's target dir (default: $ROOT/target) # CARGO_TARGET_DIR cargo's target dir (default: $ROOT/target)
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
@@ -20,7 +23,7 @@ workspace_version() {
' "$ROOT/Cargo.toml" ' "$ROOT/Cargo.toml"
} }
VERSION="${SOLVECRAFT_VERSION:-$(workspace_version)}" VERSION="${SOLIDCRAFT_VERSION:-${SOLVECRAFT_VERSION:-$(workspace_version)}}"
if [ -z "$VERSION" ]; then if [ -z "$VERSION" ]; then
echo "error: could not read [workspace.package] version from $ROOT/Cargo.toml" >&2 echo "error: could not read [workspace.package] version from $ROOT/Cargo.toml" >&2
exit 1 exit 1
@@ -32,8 +35,11 @@ mkdir -p "$DIST"
DIST="$(cd "$DIST" && pwd)" DIST="$(cd "$DIST" && pwd)"
export DIST export DIST
export SOLVECRAFT_BUILD_DATE="${SOLVECRAFT_BUILD_DATE:-$(date -u +%Y-%m-%d)}" export SOLIDCRAFT_BUILD_DATE="${SOLIDCRAFT_BUILD_DATE:-${SOLVECRAFT_BUILD_DATE:-$(date -u +%Y-%m-%d)}}"
export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target}" export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target}"
# Compatibility shim, see docs/compatibility.md: the reverse-DNS id (Flatpak app id, desktop,
# metainfo and MIME file names, icon name, Wayland app_id) keeps its pre-rename value so Flatpak
# installs keep updating and desktop integration keeps working.
APP_ID=ai.storyteller.solvecraft APP_ID=ai.storyteller.solvecraft
export APP_ID export APP_ID
@@ -43,7 +49,7 @@ warn() {
} }
# Copy the licence, notice and readme files into a package directory. The programs also carry # Copy the licence, notice and readme files into a package directory. The programs also carry
# them (Help > About > Licences, `solvecraft-cli licences`). # them (Help > About > Licences, `solidcraft-cli licences`).
copy_docs() { copy_docs() {
local dest="$1" f local dest="$1" f
for f in README.md LICENSE-MIT LICENSE-APACHE NOTICE THIRD-PARTY-LICENSES.txt; do for f in README.md LICENSE-MIT LICENSE-APACHE NOTICE THIRD-PARTY-LICENSES.txt; do
@@ -52,14 +58,14 @@ copy_docs() {
} }
# The app icon in every size a package needs, drawn by the CLI (no image files are committed): # The app icon in every size a package needs, drawn by the CLI (no image files are committed):
# $1 = the solvecraft-cli to run, $2 = output dir. Writes hicolor/<n>x<n>/apps/$APP_ID.png, # $1 = the solidcraft-cli to run, $2 = output dir. Writes hicolor/<n>x<n>/apps/$APP_ID.png,
# solvecraft.ico and solvecraft-1024.png. # solidcraft.ico and solidcraft-1024.png.
make_icons() { make_icons() {
local cli="$1" out="$2" s local cli="$1" out="$2" s
for s in 16 24 32 48 64 128 256 512; do for s in 16 24 32 48 64 128 256 512; do
mkdir -p "$out/hicolor/${s}x${s}/apps" mkdir -p "$out/hicolor/${s}x${s}/apps"
"$cli" icon --size "$s" --out "$out/hicolor/${s}x${s}/apps/$APP_ID.png" >/dev/null "$cli" icon --size "$s" --out "$out/hicolor/${s}x${s}/apps/$APP_ID.png" >/dev/null
done done
"$cli" icon --out "$out/solvecraft.ico" >/dev/null "$cli" icon --out "$out/solidcraft.ico" >/dev/null
"$cli" icon --size 1024 --out "$out/solvecraft-1024.png" >/dev/null "$cli" icon --size 1024 --out "$out/solidcraft-1024.png" >/dev/null
} }
+9 -5
View File
@@ -5,6 +5,7 @@ set -euo pipefail
site="${1:?site directory required}" site="${1:?site directory required}"
tag="${RELEASE_TAG:-}" tag="${RELEASE_TAG:-}"
# Compatibility shim (docs/compatibility.md): the Flatpak app id keeps its pre-rename value.
app_id=ai.storyteller.solvecraft app_id=ai.storyteller.solvecraft
if [ -z "$tag" ]; then if [ -z "$tag" ]; then
tag="$(gh api "repos/$GITHUB_REPOSITORY/releases?per_page=100" \ tag="$(gh api "repos/$GITHUB_REPOSITORY/releases?per_page=100" \
@@ -36,7 +37,7 @@ if curl --fail --silent --location --output /dev/null "$previous_url/summary"; t
ostree --repo="$repo_dir" remote delete previous ostree --repo="$repo_dir" remote delete previous
fi fi
for arch in x86_64 aarch64; do for arch in x86_64 aarch64; do
asset="solvecraft-$version-linux-$arch.flatpak" asset="solidcraft-$version-linux-$arch.flatpak"
gh release download "$tag" --repo "$GITHUB_REPOSITORY" --pattern "$asset" --dir "$bundles" gh release download "$tag" --repo "$GITHUB_REPOSITORY" --pattern "$asset" --dir "$bundles"
( (
cd "$bundles" cd "$bundles"
@@ -53,7 +54,7 @@ flatpak build-update-repo --title="SolidCraft" --comment='Official SolidCraft re
--description='Official Flatpak repository for SolidCraft' \ --description='Official Flatpak repository for SolidCraft' \
--homepage="https://github.com/$GITHUB_REPOSITORY" --default-branch=stable "$repo_dir" --homepage="https://github.com/$GITHUB_REPOSITORY" --default-branch=stable "$repo_dir"
test -s "$repo_dir/summary" test -s "$repo_dir/summary"
cat >"$site/flatpak/solvecraft.flatpakrepo" <<META cat >"$site/flatpak/solidcraft.flatpakrepo" <<META
[Flatpak Repo] [Flatpak Repo]
Title=SolidCraft Title=SolidCraft
Comment=Official SolidCraft releases Comment=Official SolidCraft releases
@@ -62,9 +63,12 @@ Url=$base_url/flatpak/repo/
Homepage=https://github.com/$GITHUB_REPOSITORY Homepage=https://github.com/$GITHUB_REPOSITORY
META META
cat >"$site/flatpak/index.html" <<HTML cat >"$site/flatpak/index.html" <<HTML
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>SolidCraft Flatpak repository</title></head><body><main><h1>SolidCraft Flatpak repository</h1><p>Latest published release: <strong>$tag</strong></p><p><a href="solvecraft.flatpakrepo">Add the SolidCraft repository</a></p><p>Flathub provides the required Freedesktop runtime. Add both remotes to the same user installation:</p><pre>flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>SolidCraft Flatpak repository</title></head><body><main><h1>SolidCraft Flatpak repository</h1><p>Latest published release: <strong>$tag</strong></p><p><a href="solidcraft.flatpakrepo">Add the SolidCraft repository</a></p><p>Flathub provides the required Freedesktop runtime. Add both remotes to the same user installation:</p><pre>flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak remote-add --user --if-not-exists solvecraft $base_url/flatpak/solvecraft.flatpakrepo flatpak remote-add --user --if-not-exists solidcraft $base_url/flatpak/solidcraft.flatpakrepo
flatpak install --user solvecraft $app_id flatpak install --user solidcraft $app_id
flatpak run $app_id</pre></main></body></html> flatpak run $app_id</pre></main></body></html>
HTML HTML
# Compatibility shim (docs/compatibility.md): links and instructions from before the rename point
# at solvecraft.flatpakrepo. Existing remotes keep working either way: they store the repo URL.
cp "$site/flatpak/solidcraft.flatpakrepo" "$site/flatpak/solvecraft.flatpakrepo"
touch "$site/.nojekyll" touch "$site/.nojekyll"
+18 -16
View File
@@ -1,12 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Build and package SolidCraft for FreeBSD: # Build and package SolidCraft for FreeBSD:
# #
# $DIST/solvecraft-<version>-freebsd-x86_64.tar.gz a /usr/local-style tree: # $DIST/solidcraft-<version>-freebsd-x86_64.tar.gz a /usr/local-style tree:
# solvecraft-<version>-freebsd-x86_64/{bin, share/applications, share/icons, share/mime, # solidcraft-<version>-freebsd-x86_64/{bin, share/applications, share/icons, share/mime,
# share/metainfo, share/doc/solvecraft} # share/metainfo, share/doc/solidcraft}
# #
# Install by copying the tree's contents into /usr/local: # Install by copying the tree's contents into /usr/local:
# tar -xzf solvecraft-<version>-freebsd-x86_64.tar.gz --strip-components 1 -C /usr/local # tar -xzf solidcraft-<version>-freebsd-x86_64.tar.gz --strip-components 1 -C /usr/local
# #
# Usage: packaging/freebsd/package.sh [--skip-build] # Usage: packaging/freebsd/package.sh [--skip-build]
# Needs: bash, cargo, and the packages installed by release.yml's FreeBSD job. # Needs: bash, cargo, and the packages installed by release.yml's FreeBSD job.
@@ -31,13 +31,13 @@ case "$(uname -m)" in
arm64 | aarch64) ARCH=aarch64 ;; arm64 | aarch64) ARCH=aarch64 ;;
*) echo "unsupported architecture $(uname -m)" >&2; exit 2 ;; *) echo "unsupported architecture $(uname -m)" >&2; exit 2 ;;
esac esac
BASENAME="solvecraft-$VERSION-freebsd-$ARCH" BASENAME="solidcraft-$VERSION-freebsd-$ARCH"
echo "==> SolidCraft $VERSION for FreeBSD $ARCH" echo "==> SolidCraft $VERSION for FreeBSD $ARCH"
# The release VM has 12 GB; full parallelism on the biggest crates runs it out of memory. # The release VM has 12 GB; full parallelism on the biggest crates runs it out of memory.
export CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-4}" export CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-4}"
if [ "$SKIP_BUILD" = 0 ]; then if [ "$SKIP_BUILD" = 0 ]; then
(cd "$ROOT" && cargo build --release --locked -p solvecraft -p solvecraft-cli) (cd "$ROOT" && cargo build --release --locked -p solidcraft -p solidcraft-cli)
fi fi
WORK="$CARGO_TARGET_DIR/freebsd-package" WORK="$CARGO_TARGET_DIR/freebsd-package"
STAGE="$WORK/$BASENAME" STAGE="$WORK/$BASENAME"
@@ -46,25 +46,27 @@ rm -rf "$WORK"
# FreeBSD's install(1) has no -D: create the directories first. # FreeBSD's install(1) has no -D: create the directories first.
mkdir -p "$STAGE/bin" "$STAGE/share/applications" "$STAGE/share/mime/packages" \ mkdir -p "$STAGE/bin" "$STAGE/share/applications" "$STAGE/share/mime/packages" \
"$STAGE/share/metainfo" "$STAGE/share/icons" "$STAGE/share/doc/solvecraft" "$STAGE/share/metainfo" "$STAGE/share/icons" "$STAGE/share/doc/solidcraft"
install -m 755 "$BIN/solvecraft" "$BIN/solvecraft-cli" "$STAGE/bin/" # solvecraft-cli: the old CLI name, forwarding to solidcraft-cli (compatibility shim,
strip "$STAGE/bin/solvecraft" "$STAGE/bin/solvecraft-cli" 2>/dev/null || true # docs/compatibility.md).
install -m 755 "$BIN/solidcraft" "$BIN/solidcraft-cli" "$BIN/solvecraft-cli" "$STAGE/bin/"
strip "$STAGE/bin/solidcraft" "$STAGE/bin/solidcraft-cli" "$STAGE/bin/solvecraft-cli" 2>/dev/null || true
# The desktop entry, MIME type, metainfo and icons are the freedesktop files Linux ships. # The desktop entry, MIME type, metainfo and icons are the freedesktop files Linux ships.
install -m 644 "$LINUX/$APP_ID.desktop" "$STAGE/share/applications/$APP_ID.desktop" install -m 644 "$LINUX/$APP_ID.desktop" "$STAGE/share/applications/$APP_ID.desktop"
install -m 644 "$LINUX/$APP_ID.mime.xml" "$STAGE/share/mime/packages/$APP_ID.xml" install -m 644 "$LINUX/$APP_ID.mime.xml" "$STAGE/share/mime/packages/$APP_ID.xml"
sed -e "s/@VERSION@/$VERSION/g" -e "s/@DATE@/$SOLVECRAFT_BUILD_DATE/g" \ sed -e "s/@VERSION@/$VERSION/g" -e "s/@DATE@/$SOLIDCRAFT_BUILD_DATE/g" \
"$LINUX/$APP_ID.metainfo.xml.in" >"$STAGE/share/metainfo/$APP_ID.metainfo.xml" "$LINUX/$APP_ID.metainfo.xml.in" >"$STAGE/share/metainfo/$APP_ID.metainfo.xml"
make_icons "$STAGE/bin/solvecraft-cli" "$WORK/icons" make_icons "$STAGE/bin/solidcraft-cli" "$WORK/icons"
cp -R "$WORK/icons/hicolor" "$STAGE/share/icons/" cp -R "$WORK/icons/hicolor" "$STAGE/share/icons/"
copy_docs "$STAGE/share/doc/solvecraft" copy_docs "$STAGE/share/doc/solidcraft"
for f in bin/solvecraft bin/solvecraft-cli "share/applications/$APP_ID.desktop" \ for f in bin/solidcraft bin/solidcraft-cli bin/solvecraft-cli "share/applications/$APP_ID.desktop" \
"share/icons/hicolor/256x256/apps/$APP_ID.png" share/doc/solvecraft/LICENSE-MIT \ "share/icons/hicolor/256x256/apps/$APP_ID.png" share/doc/solidcraft/LICENSE-MIT \
share/doc/solvecraft/LICENSE-APACHE share/doc/solvecraft/THIRD-PARTY-LICENSES.txt; do share/doc/solidcraft/LICENSE-APACHE share/doc/solidcraft/THIRD-PARTY-LICENSES.txt; do
if [ ! -e "$STAGE/$f" ]; then echo "error: $f is missing from the package" >&2; exit 1; fi if [ ! -e "$STAGE/$f" ]; then echo "error: $f is missing from the package" >&2; exit 1; fi
done done
tar -C "$WORK" -czf "$DIST/$BASENAME.tar.gz" "$BASENAME" tar -C "$WORK" -czf "$DIST/$BASENAME.tar.gz" "$BASENAME"
echo "wrote $DIST/$BASENAME.tar.gz" echo "wrote $DIST/$BASENAME.tar.gz"
"$STAGE/bin/solvecraft-cli" --version "$STAGE/bin/solidcraft-cli" --version
echo "==> done" echo "==> done"
+6 -4
View File
@@ -3,20 +3,22 @@
# Adapted from PhotoCraft's AppRun (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md). # Adapted from PhotoCraft's AppRun (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md).
# #
# On Wayland the compositor resolves a window's dock icon by taking the window's # On Wayland the compositor resolves a window's dock icon by taking the window's
# app_id (ai.storyteller.solvecraft) and looking up an installed .desktop file. # app_id (ai.storyteller.solvecraft, kept as a compatibility shim) and looking up an installed .desktop file.
# An AppImage installs nothing, so every AppImage run would otherwise show the # An AppImage installs nothing, so every AppImage run would otherwise show the
# generic "Wayland" icon. Best-effort desktop integration: on first run # generic "Wayland" icon. Best-effort desktop integration: on first run
# (and whenever the AppImage's path changes) install the .desktop entry and the # (and whenever the AppImage's path changes) install the .desktop entry and the
# hicolor icons into $XDG_DATA_HOME, then launch. Every failure here must leave # hicolor icons into $XDG_DATA_HOME, then launch. Every failure here must leave
# the launch untouched. Opt out with SOLVECRAFT_NO_DESKTOP_INTEGRATION=1. # the launch untouched. Opt out with SOLIDCRAFT_NO_DESKTOP_INTEGRATION=1 (the pre-rename
# SOLVECRAFT_NO_DESKTOP_INTEGRATION still works: compatibility shim, docs/compatibility.md).
set -u set -u
APPDIR="$(dirname "$(readlink -f "$0")")" APPDIR="$(dirname "$(readlink -f "$0")")"
# Compatibility shim (docs/compatibility.md): the pre-rename reverse-DNS id.
DESK_ID=ai.storyteller.solvecraft DESK_ID=ai.storyteller.solvecraft
integrate() { integrate() {
case "${SOLVECRAFT_NO_DESKTOP_INTEGRATION:-}" in case "${SOLIDCRAFT_NO_DESKTOP_INTEGRATION:-${SOLVECRAFT_NO_DESKTOP_INTEGRATION:-}}" in
1 | true | yes) return 0 ;; 1 | true | yes) return 0 ;;
esac esac
# The AppImage runtime exports $APPIMAGE; without it (an extracted AppDir) there # The AppImage runtime exports $APPIMAGE; without it (an extracted AppDir) there
@@ -70,4 +72,4 @@ integrate() {
} }
integrate integrate
exec "$APPDIR/usr/bin/solvecraft" "$@" exec "$APPDIR/usr/bin/solidcraft" "$@"
@@ -3,12 +3,12 @@ Type=Application
Name=SolidCraft Name=SolidCraft
GenericName=3D CAD GenericName=3D CAD
Comment=Parametric 3D CAD: sketch, constrain, extrude, and change a parameter to rebuild Comment=Parametric 3D CAD: sketch, constrain, extrude, and change a parameter to rebuild
Exec=solvecraft %f Exec=solidcraft %f
TryExec=solvecraft TryExec=solidcraft
Icon=ai.storyteller.solvecraft Icon=ai.storyteller.solvecraft
Terminal=false Terminal=false
StartupNotify=true StartupNotify=true
StartupWMClass=solvecraft StartupWMClass=solidcraft
Categories=Graphics;3DGraphics;Engineering; Categories=Graphics;3DGraphics;Engineering;
Keywords=cad;3d;parametric;sketch;step;stl;modelling;modeling; Keywords=cad;3d;parametric;sketch;step;stl;modelling;modeling;
MimeType=application/x-solvecraft;model/step;model/iges;model/stl;model/3mf; MimeType=application/x-solidcraft;model/step;model/iges;model/stl;model/3mf;
@@ -53,9 +53,9 @@
<control>pointing</control> <control>pointing</control>
</supports> </supports>
<provides> <provides>
<binary>solvecraft</binary> <binary>solidcraft</binary>
<binary>solvecraft-cli</binary> <binary>solidcraft-cli</binary>
<mediatype>application/x-solvecraft</mediatype> <mediatype>application/x-solidcraft</mediatype>
</provides> </provides>
<content_rating type="oars-1.1"/> <content_rating type="oars-1.1"/>
<releases> <releases>
@@ -2,10 +2,13 @@
<!-- shared-mime-info definitions for types the system database may not have. <!-- shared-mime-info definitions for types the system database may not have.
Installed to /usr/share/mime/packages/ (update-mime-database runs on install). --> Installed to /usr/share/mime/packages/ (update-mime-database runs on install). -->
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-solvecraft"> <mime-type type="application/x-solidcraft">
<comment>SolidCraft design</comment> <comment>SolidCraft design</comment>
<icon name="ai.storyteller.solvecraft"/> <icon name="ai.storyteller.solvecraft"/>
<sub-class-of type="application/json"/> <sub-class-of type="application/json"/>
<glob pattern="*.solidcraft"/>
<!-- Compatibility shim (docs/compatibility.md): designs saved before the rename. -->
<glob pattern="*.solvecraft"/> <glob pattern="*.solvecraft"/>
<alias type="application/x-solvecraft"/>
</mime-type> </mime-type>
</mime-info> </mime-info>
+6 -6
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Repackage a SolidCraft Linux tarball as a single-file Flatpak bundle: # Repackage a SolidCraft Linux tarball as a single-file Flatpak bundle:
# #
# $DIST/solvecraft-<version>-linux-<arch>.flatpak # $DIST/solidcraft-<version>-linux-<arch>.flatpak
# #
# Usage: packaging/linux/flatpak-bundle.sh [--no-test] [TARBALL] # Usage: packaging/linux/flatpak-bundle.sh [--no-test] [TARBALL]
# #
# TARBALL defaults to $DIST/solvecraft-<version>-linux-<arch>.tar.gz from package.sh. The bundle # TARBALL defaults to $DIST/solidcraft-<version>-linux-<arch>.tar.gz from package.sh. The bundle
# is built for the host architecture (x86_64 or aarch64), which must match the tarball's. # is built for the host architecture (x86_64 or aarch64), which must match the tarball's.
# Needs flatpak, flatpak-builder and the SVG pixbuf loader (librsvg2-common) for the host's # Needs flatpak, flatpak-builder and the SVG pixbuf loader (librsvg2-common) for the host's
# `appstreamcli compose`; the freedesktop runtime and SDK named in the manifest are # `appstreamcli compose`; the freedesktop runtime and SDK named in the manifest are
@@ -37,7 +37,7 @@ case "$ARCH" in
aarch64 | arm64) ARCH=aarch64 ;; aarch64 | arm64) ARCH=aarch64 ;;
*) echo "unsupported architecture $ARCH" >&2; exit 2 ;; *) echo "unsupported architecture $ARCH" >&2; exit 2 ;;
esac esac
BASENAME="solvecraft-$VERSION-linux-$ARCH" BASENAME="solidcraft-$VERSION-linux-$ARCH"
TARBALL="${TARBALL:-$DIST/$BASENAME.tar.gz}" TARBALL="${TARBALL:-$DIST/$BASENAME.tar.gz}"
[ -f "$TARBALL" ] || { echo "error: $TARBALL not found (run packaging/linux/package.sh --formats tar first)" >&2; exit 1; } [ -f "$TARBALL" ] || { echo "error: $TARBALL not found (run packaging/linux/package.sh --formats tar first)" >&2; exit 1; }
for tool in flatpak flatpak-builder; do for tool in flatpak flatpak-builder; do
@@ -50,7 +50,7 @@ WORK="$CARGO_TARGET_DIR/flatpak-bundle"
rm -rf "$WORK" rm -rf "$WORK"
mkdir -p "$WORK/stage" mkdir -p "$WORK/stage"
tar -xzf "$TARBALL" -C "$WORK/stage" --strip-components=1 tar -xzf "$TARBALL" -C "$WORK/stage" --strip-components=1
[ -x "$WORK/stage/bin/solvecraft" ] || { echo "error: $TARBALL has no bin/solvecraft" >&2; exit 1; } [ -x "$WORK/stage/bin/solidcraft" ] || { echo "error: $TARBALL has no bin/solidcraft" >&2; exit 1; }
cp "$HERE/flatpak/$APP_ID.bundle.yml" "$WORK/$APP_ID.yml" cp "$HERE/flatpak/$APP_ID.bundle.yml" "$WORK/$APP_ID.yml"
flatpak remote-add --user --if-not-exists flathub "$FLATHUB" flatpak remote-add --user --if-not-exists flathub "$FLATHUB"
@@ -66,8 +66,8 @@ echo "wrote $OUT"
if [ "$TEST" = 1 ]; then if [ "$TEST" = 1 ]; then
flatpak install --user -y --noninteractive --reinstall "$OUT" flatpak install --user -y --noninteractive --reinstall "$OUT"
flatpak info --user "$APP_ID" flatpak info --user "$APP_ID"
flatpak run --command=solvecraft-cli "$APP_ID" --version flatpak run --command=solidcraft-cli "$APP_ID" --version
flatpak run --command=sh "$APP_ID" -c 'ls /app/share/applications /app/share/metainfo /app/share/mime/packages /app/share/icons/hicolor/256x256/apps /app/share/doc/solvecraft' flatpak run --command=sh "$APP_ID" -c 'ls /app/share/applications /app/share/metainfo /app/share/mime/packages /app/share/icons/hicolor/256x256/apps /app/share/doc/solidcraft'
python3 "$HERE/flatpak-smoke.py" --backend both python3 "$HERE/flatpak-smoke.py" --backend both
fi fi
echo "==> done" echo "==> done"
+4 -3
View File
@@ -28,7 +28,7 @@ work=$(mktemp -d)
export XDG_CONFIG_HOME="$work/config" XDG_DATA_HOME="$work/data" XDG_CACHE_HOME="$work/cache" export XDG_CONFIG_HOME="$work/config" XDG_DATA_HOME="$work/data" XDG_CACHE_HOME="$work/cache"
mkdir -p "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" mkdir -p "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME"
unset WGPU_BACKEND WGPU_BACKENDS unset WGPU_BACKEND WGPU_BACKENDS
solvecraft --control 18837 >"$work/app.log" 2>&1 & solidcraft --control 18837 >"$work/app.log" 2>&1 &
app=$! app=$!
cleanup() { cleanup() {
kill "$app" 2>/dev/null || true kill "$app" 2>/dev/null || true
@@ -165,10 +165,10 @@ def frame_statistics(png):
def probe(gl_saved_four=False): def probe(gl_saved_four=False):
shell = SANDBOX_PROBE shell = SANDBOX_PROBE
if gl_saved_four: if gl_saved_four:
shell = shell.replace('solvecraft --control', shell = shell.replace('solidcraft --control',
'mkdir -p "$XDG_DATA_HOME/solvecraft"\n' 'mkdir -p "$XDG_DATA_HOME/solvecraft"\n'
'printf \'{"msaa":4}\' >"$XDG_DATA_HOME/solvecraft/graphics.json"\n' 'printf \'{"msaa":4}\' >"$XDG_DATA_HOME/solvecraft/graphics.json"\n'
'export WGPU_BACKEND=gl\nsolvecraft --control') 'export WGPU_BACKEND=gl\nsolidcraft --control')
result = subprocess.run(["flatpak", "run", "--user", "--command=bash", APP_ID, "-c", shell], result = subprocess.run(["flatpak", "run", "--user", "--command=bash", APP_ID, "-c", shell],
text=True, capture_output=True, timeout=125) text=True, capture_output=True, timeout=125)
if result.returncode: if result.returncode:
@@ -201,6 +201,7 @@ def run_backend(backend):
env.pop("WAYLAND_DISPLAY", None) env.pop("WAYLAND_DISPLAY", None)
env.pop("WAYLAND_SOCKET", None) env.pop("WAYLAND_SOCKET", None)
env.pop("DISPLAY", None) env.pop("DISPLAY", None)
env.pop("SOLIDCRAFT_WAYLAND", None)
env.pop("SOLVECRAFT_WAYLAND", None) env.pop("SOLVECRAFT_WAYLAND", None)
command = ["dbus-run-session", "--"] command = ["dbus-run-session", "--"]
compositor = None compositor = None
@@ -1,17 +1,19 @@
# Flatpak manifest for the single-file bundle attached to every GitHub release # Flatpak manifest for the single-file bundle attached to every GitHub release
# (solvecraft-<version>-linux-<arch>.flatpak). Build it with packaging/linux/flatpak-bundle.sh. # (solidcraft-<version>-linux-<arch>.flatpak). Build it with packaging/linux/flatpak-bundle.sh.
# Adapted from PhotoCraft's (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md). # Adapted from PhotoCraft's (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md).
# #
# It repackages the release's own Linux tarball (solvecraft-<version>-linux-<arch>.tar.gz, built # It repackages the release's own Linux tarball (solidcraft-<version>-linux-<arch>.tar.gz, built
# on Ubuntu 22.04 by package.sh) instead of compiling Rust inside flatpak-builder: no network # on Ubuntu 22.04 by package.sh) instead of compiling Rust inside flatpak-builder: no network
# during the build, and the same binaries as the AppImage/deb/rpm. The binaries need glibc >= 2.35 # during the build, and the same binaries as the AppImage/deb/rpm. The binaries need glibc >= 2.35
# and load X11, Wayland, xkbcommon and Vulkan at runtime; the freedesktop runtime has all of # and load X11, Wayland, xkbcommon and Vulkan at runtime; the freedesktop runtime has all of
# them, and the GPU driver comes from its org.freedesktop.Platform.GL extension. # them, and the GPU driver comes from its org.freedesktop.Platform.GL extension.
# Compatibility shim, see docs/compatibility.md: the Flatpak app id keeps its pre-rename value.
# A new id would be a different app to Flatpak, and existing installs would stop updating.
id: ai.storyteller.solvecraft id: ai.storyteller.solvecraft
runtime: org.freedesktop.Platform runtime: org.freedesktop.Platform
runtime-version: '26.08' runtime-version: '26.08'
sdk: org.freedesktop.Sdk sdk: org.freedesktop.Sdk
command: solvecraft command: solidcraft
finish-args: finish-args:
# Display: Wayland first; X11 only when no Wayland compositor is running. # Display: Wayland first; X11 only when no Wayland compositor is running.
- --socket=wayland - --socket=wayland
@@ -28,16 +30,18 @@ finish-args:
# the sandbox; `flatpak override --user --share=network ai.storyteller.solvecraft` exposes it to # the sandbox; `flatpak override --user --share=network ai.storyteller.solvecraft` exposes it to
# host agents) and home/host filesystem access. # host agents) and home/host filesystem access.
modules: modules:
- name: solvecraft - name: solidcraft
buildsystem: simple buildsystem: simple
build-commands: build-commands:
- install -Dm755 bin/solvecraft /app/bin/solvecraft - install -Dm755 bin/solidcraft /app/bin/solidcraft
- install -Dm755 bin/solidcraft-cli /app/bin/solidcraft-cli
# The old CLI name, forwarding to solidcraft-cli (compatibility shim, docs/compatibility.md).
- install -Dm755 bin/solvecraft-cli /app/bin/solvecraft-cli - install -Dm755 bin/solvecraft-cli /app/bin/solvecraft-cli
- install -Dm644 share/applications/ai.storyteller.solvecraft.desktop /app/share/applications/ai.storyteller.solvecraft.desktop - install -Dm644 share/applications/ai.storyteller.solvecraft.desktop /app/share/applications/ai.storyteller.solvecraft.desktop
- install -Dm644 share/mime/packages/ai.storyteller.solvecraft.xml /app/share/mime/packages/ai.storyteller.solvecraft.xml - install -Dm644 share/mime/packages/ai.storyteller.solvecraft.xml /app/share/mime/packages/ai.storyteller.solvecraft.xml
# Already has the release's version and date substituted by package.sh. # Already has the release's version and date substituted by package.sh.
- install -Dm644 share/metainfo/ai.storyteller.solvecraft.metainfo.xml /app/share/metainfo/ai.storyteller.solvecraft.metainfo.xml - install -Dm644 share/metainfo/ai.storyteller.solvecraft.metainfo.xml /app/share/metainfo/ai.storyteller.solvecraft.metainfo.xml
- mkdir -p /app/share/icons /app/share/doc && cp -R share/icons/hicolor /app/share/icons/ && cp -R share/doc/solvecraft /app/share/doc/ - mkdir -p /app/share/icons /app/share/doc && cp -R share/icons/hicolor /app/share/icons/ && cp -R share/doc/solidcraft /app/share/doc/
sources: sources:
- type: dir - type: dir
path: stage path: stage
+20 -5
View File
@@ -1,7 +1,15 @@
# .deb and .rpm packages (nfpm: https://nfpm.goreleaser.com). Run by package.sh, which stages # .deb and .rpm packages (nfpm: https://nfpm.goreleaser.com). Run by package.sh, which stages
# the file tree, substitutes its path for ${STAGE} (nfpm doesn't expand env vars in `src`) and # the file tree, substitutes its path for ${STAGE} (nfpm doesn't expand env vars in `src`) and
# exports VERSION and NFPM_ARCH. Adapted from PhotoCraft's (storytold/photocraft, Apache-2.0). # exports VERSION and NFPM_ARCH. Adapted from PhotoCraft's (storytold/photocraft, Apache-2.0).
name: solvecraft name: solidcraft
# Compatibility shim (docs/compatibility.md): releases before the rename were packaged as `solvecraft`.
# Installing this package replaces that one (Debian Replaces/Conflicts, set under overrides.deb;
# nfpm writes `replaces` as RPM Obsoletes), so `apt install ./solidcraft-….deb` or `dnf install ./solidcraft-….rpm`
# upgrades an old install instead of failing on the shared desktop and icon files.
replaces:
- solvecraft
provides:
- solvecraft
arch: ${NFPM_ARCH} arch: ${NFPM_ARCH}
platform: linux platform: linux
version: ${VERSION} version: ${VERSION}
@@ -10,14 +18,14 @@ version_schema: semver
release: 1 release: 1
section: graphics section: graphics
priority: optional priority: optional
maintainer: ${SOLVECRAFT_MAINTAINER} maintainer: ${SOLIDCRAFT_MAINTAINER}
vendor: SolidCraft contributors vendor: SolidCraft contributors
homepage: https://bherbruck.github.io/solidcraft/ homepage: https://bherbruck.github.io/solidcraft/
license: MIT OR Apache-2.0 license: MIT OR Apache-2.0
description: |- description: |-
Open-source parametric 3D CAD in the style of Fusion Open-source parametric 3D CAD in the style of Fusion
Sketches with a constraint solver, a parametric feature timeline, components and Sketches with a constraint solver, a parametric feature timeline, components and
joints, sheet metal; STEP, IGES, 3MF, STL and OBJ. Includes solvecraft-cli, a joints, sheet metal; STEP, IGES, 3MF, STL and OBJ. Includes solidcraft-cli, a
headless command runner and MCP server for AI agents. headless command runner and MCP server for AI agents.
# The binaries link only glibc and libgcc_s directly. Windowing (X11/Wayland, xkbcommon) and the # The binaries link only glibc and libgcc_s directly. Windowing (X11/Wayland, xkbcommon) and the
@@ -25,6 +33,9 @@ description: |-
# the package tools can't find them: list them here. # the package tools can't find them: list them here.
overrides: overrides:
deb: deb:
# Debian's rename pattern: Replaces + Conflicts + Provides (docs/compatibility.md).
conflicts:
- solvecraft
depends: depends:
- libc6 (>= 2.35) - libc6 (>= 2.35)
- libgcc-s1 - libgcc-s1
@@ -59,9 +70,13 @@ overrides:
- xdg-desktop-portal - xdg-desktop-portal
contents: contents:
- src: ${STAGE}/usr/bin/solvecraft - src: ${STAGE}/usr/bin/solidcraft
dst: /usr/bin/solvecraft dst: /usr/bin/solidcraft
file_info: { mode: 0755 } file_info: { mode: 0755 }
- src: ${STAGE}/usr/bin/solidcraft-cli
dst: /usr/bin/solidcraft-cli
file_info: { mode: 0755 }
# Compatibility shim (docs/compatibility.md): the old CLI name forwards to solidcraft-cli.
- src: ${STAGE}/usr/bin/solvecraft-cli - src: ${STAGE}/usr/bin/solvecraft-cli
dst: /usr/bin/solvecraft-cli dst: /usr/bin/solvecraft-cli
file_info: { mode: 0755 } file_info: { mode: 0755 }
+28 -19
View File
@@ -1,11 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Build and package SolidCraft for Linux (<arch> is x86_64 or aarch64): # Build and package SolidCraft for Linux (<arch> is x86_64 or aarch64):
# #
# $DIST/solvecraft-<version>-linux-<arch>.AppImage any distro with glibc >= the build host's # $DIST/solidcraft-<version>-linux-<arch>.AppImage any distro with glibc >= the build host's
# $DIST/solvecraft-<version>-linux-<arch>.AppImage.zsync delta updates (needs zsyncmake) # $DIST/solidcraft-<version>-linux-<arch>.AppImage.zsync delta updates (needs zsyncmake)
# $DIST/solvecraft-<version>-linux-<arch>.deb Debian, Ubuntu, Mint, Pop!_OS, ... # $DIST/solvecraft-<version>-linux-<arch>.AppImage.zsync the same, for pre-rename AppImages
# $DIST/solvecraft-<version>-linux-<arch>.rpm Fedora, openSUSE, RHEL, ... # $DIST/solidcraft-<version>-linux-<arch>.deb Debian, Ubuntu, Mint, Pop!_OS, ...
# $DIST/solvecraft-<version>-linux-<arch>.tar.gz plain FHS-style tree (bin/, share/) # $DIST/solidcraft-<version>-linux-<arch>.rpm Fedora, openSUSE, RHEL, ...
# $DIST/solidcraft-<version>-linux-<arch>.tar.gz plain FHS-style tree (bin/, share/)
# #
# Usage: packaging/linux/package.sh [--skip-build] [--formats "appimage deb rpm tar"] # Usage: packaging/linux/package.sh [--skip-build] [--formats "appimage deb rpm tar"]
# #
@@ -37,17 +38,17 @@ case "$ARCH" in
aarch64 | arm64) ARCH=aarch64; DEB_ARCH=arm64 ;; aarch64 | arm64) ARCH=aarch64; DEB_ARCH=arm64 ;;
*) echo "unsupported architecture $ARCH" >&2; exit 2 ;; *) echo "unsupported architecture $ARCH" >&2; exit 2 ;;
esac esac
export SOLVECRAFT_MAINTAINER="${SOLVECRAFT_MAINTAINER:-SolidCraft contributors <https://github.com/bherbruck/solidcraft>}" export SOLIDCRAFT_MAINTAINER="${SOLIDCRAFT_MAINTAINER:-${SOLVECRAFT_MAINTAINER:-SolidCraft contributors <https://github.com/bherbruck/solidcraft>}}" # SOLVECRAFT_*: compatibility shim, see docs/compatibility.md
BASENAME="solvecraft-$VERSION-linux-$ARCH" BASENAME="solidcraft-$VERSION-linux-$ARCH"
echo "==> SolidCraft $VERSION for Linux $ARCH ($FORMATS)" echo "==> SolidCraft $VERSION for Linux $ARCH ($FORMATS)"
if [ "$SKIP_BUILD" = 0 ]; then if [ "$SKIP_BUILD" = 0 ]; then
if [ -n "${CROSS_TARGET:-}" ]; then if [ -n "${CROSS_TARGET:-}" ]; then
(cd "$ROOT" && cargo build --release --locked -p solvecraft -p solvecraft-cli --target "$CROSS_TARGET") (cd "$ROOT" && cargo build --release --locked -p solidcraft -p solidcraft-cli --target "$CROSS_TARGET")
BIN="$CARGO_TARGET_DIR/$CROSS_TARGET/release" BIN="$CARGO_TARGET_DIR/$CROSS_TARGET/release"
else else
(cd "$ROOT" && cargo build --release --locked -p solvecraft -p solvecraft-cli) (cd "$ROOT" && cargo build --release --locked -p solidcraft -p solidcraft-cli)
BIN="$CARGO_TARGET_DIR/release" BIN="$CARGO_TARGET_DIR/release"
fi fi
else else
@@ -62,19 +63,21 @@ STAGE="$WORK/root"
rm -rf "$WORK" rm -rf "$WORK"
# ---- stage an FHS tree (shared by every format) ------------------------------------------------- # ---- stage an FHS tree (shared by every format) -------------------------------------------------
install -Dm755 "$BIN/solvecraft" "$STAGE/usr/bin/solvecraft" install -Dm755 "$BIN/solidcraft" "$STAGE/usr/bin/solidcraft"
install -Dm755 "$BIN/solidcraft-cli" "$STAGE/usr/bin/solidcraft-cli"
# Compatibility shim (docs/compatibility.md): the old CLI name forwards to solidcraft-cli.
install -Dm755 "$BIN/solvecraft-cli" "$STAGE/usr/bin/solvecraft-cli" install -Dm755 "$BIN/solvecraft-cli" "$STAGE/usr/bin/solvecraft-cli"
strip "$STAGE/usr/bin/solvecraft" "$STAGE/usr/bin/solvecraft-cli" 2>/dev/null || true strip "$STAGE/usr/bin/solidcraft" "$STAGE/usr/bin/solidcraft-cli" "$STAGE/usr/bin/solvecraft-cli" 2>/dev/null || true
install -Dm644 "$HERE/$APP_ID.desktop" "$STAGE/usr/share/applications/$APP_ID.desktop" install -Dm644 "$HERE/$APP_ID.desktop" "$STAGE/usr/share/applications/$APP_ID.desktop"
install -Dm644 "$HERE/$APP_ID.mime.xml" "$STAGE/usr/share/mime/packages/$APP_ID.xml" install -Dm644 "$HERE/$APP_ID.mime.xml" "$STAGE/usr/share/mime/packages/$APP_ID.xml"
mkdir -p "$STAGE/usr/share/metainfo" mkdir -p "$STAGE/usr/share/metainfo"
sed -e "s/@VERSION@/$VERSION/g" -e "s/@DATE@/$SOLVECRAFT_BUILD_DATE/g" \ sed -e "s/@VERSION@/$VERSION/g" -e "s/@DATE@/$SOLIDCRAFT_BUILD_DATE/g" \
"$HERE/$APP_ID.metainfo.xml.in" >"$STAGE/usr/share/metainfo/$APP_ID.metainfo.xml" "$HERE/$APP_ID.metainfo.xml.in" >"$STAGE/usr/share/metainfo/$APP_ID.metainfo.xml"
make_icons "$STAGE/usr/bin/solvecraft-cli" "$WORK/icons" make_icons "$STAGE/usr/bin/solidcraft-cli" "$WORK/icons"
mkdir -p "$STAGE/usr/share/icons" mkdir -p "$STAGE/usr/share/icons"
cp -R "$WORK/icons/hicolor" "$STAGE/usr/share/icons/" cp -R "$WORK/icons/hicolor" "$STAGE/usr/share/icons/"
mkdir -p "$STAGE/usr/share/doc/solvecraft" mkdir -p "$STAGE/usr/share/doc/solidcraft"
copy_docs "$STAGE/usr/share/doc/solvecraft" copy_docs "$STAGE/usr/share/doc/solidcraft"
if command -v desktop-file-validate >/dev/null; then if command -v desktop-file-validate >/dev/null; then
desktop-file-validate "$STAGE/usr/share/applications/$APP_ID.desktop" desktop-file-validate "$STAGE/usr/share/applications/$APP_ID.desktop"
@@ -107,7 +110,7 @@ fi
# ---- AppImage ----------------------------------------------------------------------------------- # ---- AppImage -----------------------------------------------------------------------------------
if has appimage; then if has appimage; then
APPDIR="$WORK/SolveCraft.AppDir" APPDIR="$WORK/SolidCraft.AppDir"
cp -R "$STAGE" "$APPDIR" cp -R "$STAGE" "$APPDIR"
mv "$APPDIR/usr/share/doc" "$WORK/doc-unused" mv "$APPDIR/usr/share/doc" "$WORK/doc-unused"
# AppRun is a script, not a symlink: it installs the .desktop entry and icons into # AppRun is a script, not a symlink: it installs the .desktop entry and icons into
@@ -133,19 +136,25 @@ if has appimage; then
# Update information: AppImageUpdate and the like fetch only the changed blocks of a newer # Update information: AppImageUpdate and the like fetch only the changed blocks of a newer
# release through the .zsync published next to each AppImage. `latest` is the newest published # release through the .zsync published next to each AppImage. `latest` is the newest published
# release that is not a pre-release. # release that is not a pre-release.
REPO="${GITHUB_REPOSITORY:-bherbruck/solvecraft}" REPO="${GITHUB_REPOSITORY:-bherbruck/solidcraft}"
UPDATE_INFO="gh-releases-zsync|${REPO%%/*}|${REPO#*/}|latest|solvecraft-*-linux-$ARCH.AppImage.zsync" UPDATE_INFO="gh-releases-zsync|${REPO%%/*}|${REPO#*/}|latest|solidcraft-*-linux-$ARCH.AppImage.zsync"
# Extract-and-run: works without FUSE (containers, CI). With zsyncmake on the host appimagetool # Extract-and-run: works without FUSE (containers, CI). With zsyncmake on the host appimagetool
# also writes the .zsync, into its working directory, hence the cd. # also writes the .zsync, into its working directory, hence the cd.
(cd "$DIST" && ARCH="$ARCH" APPIMAGE_EXTRACT_AND_RUN=1 "$TOOL" --no-appstream -u "$UPDATE_INFO" "$APPDIR" "$OUT") (cd "$DIST" && ARCH="$ARCH" APPIMAGE_EXTRACT_AND_RUN=1 "$TOOL" --no-appstream -u "$UPDATE_INFO" "$APPDIR" "$OUT")
echo "wrote $OUT" echo "wrote $OUT"
if [ -s "$OUT.zsync" ]; then if [ -s "$OUT.zsync" ]; then
echo "wrote $OUT.zsync" echo "wrote $OUT.zsync"
# Compatibility shim (docs/compatibility.md): AppImages from before the rename look for
# `solvecraft-*-linux-$ARCH.AppImage.zsync` in the latest release. The same .zsync under that
# name (its URL is the new AppImage's file name, relative to the release) updates them to
# SolidCraft.
cp "$OUT.zsync" "$DIST/solvecraft-$VERSION-linux-$ARCH.AppImage.zsync"
echo "wrote $DIST/solvecraft-$VERSION-linux-$ARCH.AppImage.zsync (legacy update alias)"
else else
warn "zsyncmake not found, so $OUT.zsync was not written; AppImage delta updates need it" warn "zsyncmake not found, so $OUT.zsync was not written; AppImage delta updates need it"
fi fi
fi fi
"$STAGE/usr/bin/solvecraft-cli" --version "$STAGE/usr/bin/solidcraft-cli" --version
echo "==> done" echo "==> done"
ls -lh "$DIST" ls -lh "$DIST"
+4 -3
View File
@@ -13,7 +13,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>SolidCraft</string> <string>SolidCraft</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>ai.storyteller.solvecraft</string> <string>ai.storyteller.solidcraft</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
@@ -24,7 +24,7 @@
<string>@SHORT_VERSION@</string> <string>@SHORT_VERSION@</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>@SHORT_VERSION@</string> <string>@SHORT_VERSION@</string>
<key>SolveCraftVersion</key> <key>SolidCraftVersion</key>
<string>@VERSION@</string> <string>@VERSION@</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>SolidCraft</string> <string>SolidCraft</string>
@@ -43,7 +43,8 @@
<key>CFBundleTypeName</key> <key>CFBundleTypeName</key>
<string>SolidCraft design</string> <string>SolidCraft design</string>
<key>CFBundleTypeExtensions</key> <key>CFBundleTypeExtensions</key>
<array><string>solvecraft</string></array> <!-- solvecraft: designs saved before the rename (compatibility shim, docs/compatibility.md). -->
<array><string>solidcraft</string><string>solvecraft</string></array>
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Editor</string> <string>Editor</string>
<key>LSHandlerRank</key> <key>LSHandlerRank</key>
+6 -9
View File
@@ -2,16 +2,13 @@ Install SolidCraft
Drag SolidCraft.app onto Applications. Drag SolidCraft.app onto Applications.
Updating an older SolveCraft.app installation Updating an older installation
1. Quit the app. 1. Quit the app.
2. In Applications, rename the existing SolveCraft.app to SolidCraft.app. 2. Drag SolidCraft.app from this disk image onto Applications and choose Replace.
3. Drag SolidCraft.app from this disk image onto Applications and choose Replace.
If both names are already present, keep SolidCraft.app and move the old Some earlier releases were installed as SolveCraft.app. Move that one to the Trash
SolveCraft.app to the Trash. The disk image does not remove old installations. once SolidCraft.app is in Applications, and replace any Dock shortcut with the
If your Dock shortcut still uses the old name, remove it from the Dock, then old name (open SolidCraft.app, then choose Options > Keep in Dock).
open SolidCraft.app from Applications and choose Options > Keep in Dock.
Your designs and settings keep their existing locations. The bundle identifier Your designs and settings are not affected by the update.
remains ai.storyteller.solvecraft; saved designs still use .solvecraft.
+21 -15
View File
@@ -1,8 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Build and package SolidCraft for macOS: # Build and package SolidCraft for macOS:
# #
# $DIST/solvecraft-<version>-macos-<arch>.dmg SolidCraft.app on a drag-to-Applications DMG # $DIST/solidcraft-<version>-macos-<arch>.dmg SolidCraft.app on a drag-to-Applications DMG
# $DIST/solvecraft-cli-<version>-macos-<arch>.zip the headless CLI with the licence files # $DIST/solidcraft-cli-<version>-macos-<arch>.zip the headless CLI (and its solvecraft-cli
# compatibility alias) with the licence files
# #
# Usage: packaging/macos/package.sh [--arch universal|aarch64|x86_64] [--skip-build] # Usage: packaging/macos/package.sh [--arch universal|aarch64|x86_64] [--skip-build]
# #
@@ -12,6 +13,9 @@ set -euo pipefail
# shellcheck source=../env.sh # shellcheck source=../env.sh
. "$(dirname "${BASH_SOURCE[0]}")/../env.sh" . "$(dirname "${BASH_SOURCE[0]}")/../env.sh"
HERE="$ROOT/packaging/macos" HERE="$ROOT/packaging/macos"
# macOS has no Flatpak-style update channel keyed by this id, so it follows the new name
# (the Linux reverse-DNS APP_ID stays as a compatibility shim; docs/compatibility.md).
MACOS_BUNDLE_ID=ai.storyteller.solidcraft
ARCH=universal ARCH=universal
SKIP_BUILD=0 SKIP_BUILD=0
@@ -35,19 +39,19 @@ export MACOSX_DEPLOYMENT_TARGET=11.0
SHORT_VERSION="${VERSION%%-*}" SHORT_VERSION="${VERSION%%-*}"
WORK="$CARGO_TARGET_DIR/macos-package" WORK="$CARGO_TARGET_DIR/macos-package"
APP="$WORK/SolidCraft.app" APP="$WORK/SolidCraft.app"
DMG="$DIST/solvecraft-$VERSION-macos-$ARCH.dmg" DMG="$DIST/solidcraft-$VERSION-macos-$ARCH.dmg"
CLI_ZIP="$DIST/solvecraft-cli-$VERSION-macos-$ARCH.zip" CLI_ZIP="$DIST/solidcraft-cli-$VERSION-macos-$ARCH.zip"
echo "==> SolidCraft $VERSION for macOS ($ARCH)" echo "==> SolidCraft $VERSION for macOS ($ARCH)"
if [ "$SKIP_BUILD" = 0 ]; then if [ "$SKIP_BUILD" = 0 ]; then
args=() args=()
for t in "${TARGETS[@]}"; do args+=(--target "$t"); done for t in "${TARGETS[@]}"; do args+=(--target "$t"); done
(cd "$ROOT" && cargo build --release --locked -p solvecraft -p solvecraft-cli "${args[@]}") (cd "$ROOT" && cargo build --release --locked -p solidcraft -p solidcraft-cli "${args[@]}")
fi fi
rm -rf "$WORK" rm -rf "$WORK"
mkdir -p "$WORK/bin" mkdir -p "$WORK/bin"
for bin in solvecraft solvecraft-cli; do for bin in solidcraft solidcraft-cli solvecraft-cli; do
inputs=() inputs=()
for t in "${TARGETS[@]}"; do inputs+=("$CARGO_TARGET_DIR/$t/release/$bin"); done for t in "${TARGETS[@]}"; do inputs+=("$CARGO_TARGET_DIR/$t/release/$bin"); done
lipo -create -output "$WORK/bin/$bin" "${inputs[@]}" lipo -create -output "$WORK/bin/$bin" "${inputs[@]}"
@@ -57,13 +61,13 @@ done
# ---- SolidCraft.app ---------------------------------------------------------------------------- # ---- SolidCraft.app ----------------------------------------------------------------------------
echo "==> assembling $APP" echo "==> assembling $APP"
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources" mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources"
cp "$WORK/bin/solvecraft" "$APP/Contents/MacOS/SolidCraft" cp "$WORK/bin/solidcraft" "$APP/Contents/MacOS/SolidCraft"
# The icon, drawn by the CLI (no image files are committed). # The icon, drawn by the CLI (no image files are committed).
SET="$WORK/SolidCraft.iconset" SET="$WORK/SolidCraft.iconset"
mkdir -p "$SET" mkdir -p "$SET"
for s in 16 32 128 256 512; do for s in 16 32 128 256 512; do
"$WORK/bin/solvecraft-cli" icon --size "$s" --out "$SET/icon_${s}x${s}.png" >/dev/null "$WORK/bin/solidcraft-cli" icon --size "$s" --out "$SET/icon_${s}x${s}.png" >/dev/null
"$WORK/bin/solvecraft-cli" icon --size $((s * 2)) --out "$SET/icon_${s}x${s}@2x.png" >/dev/null "$WORK/bin/solidcraft-cli" icon --size $((s * 2)) --out "$SET/icon_${s}x${s}@2x.png" >/dev/null
done done
iconutil -c icns -o "$APP/Contents/Resources/SolidCraft.icns" "$SET" iconutil -c icns -o "$APP/Contents/Resources/SolidCraft.icns" "$SET"
mkdir -p "$APP/Contents/Resources/Licenses" mkdir -p "$APP/Contents/Resources/Licenses"
@@ -95,12 +99,11 @@ hdiutil attach -readonly -nobrowse -mountpoint "$MNT" "$DMG"
ls -la "$MNT" "$MNT/SolidCraft.app/Contents" "$MNT/SolidCraft.app/Contents/MacOS" "$MNT/SolidCraft.app/Contents/Resources" ls -la "$MNT" "$MNT/SolidCraft.app/Contents" "$MNT/SolidCraft.app/Contents/MacOS" "$MNT/SolidCraft.app/Contents/Resources"
test -L "$MNT/Applications" && test "$(readlink "$MNT/Applications")" = /Applications test -L "$MNT/Applications" && test "$(readlink "$MNT/Applications")" = /Applications
plutil -lint "$MNT/SolidCraft.app/Contents/Info.plist" plutil -lint "$MNT/SolidCraft.app/Contents/Info.plist"
# Check the names Finder/LaunchServices actually use, as well as compatibility identity. # Check the names Finder/LaunchServices actually use, and the bundle identity.
for key in CFBundleName CFBundleDisplayName CFBundleExecutable CFBundleIconFile; do for key in CFBundleName CFBundleDisplayName CFBundleExecutable CFBundleIconFile; do
test "$(/usr/libexec/PlistBuddy -c "Print :$key" "$MNT/SolidCraft.app/Contents/Info.plist")" = SolidCraft test "$(/usr/libexec/PlistBuddy -c "Print :$key" "$MNT/SolidCraft.app/Contents/Info.plist")" = SolidCraft
done done
test "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$MNT/SolidCraft.app/Contents/Info.plist")" = "$APP_ID" test "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$MNT/SolidCraft.app/Contents/Info.plist")" = "$MACOS_BUNDLE_ID"
test ! -e "$MNT/SolveCraft.app"
test -s "$MNT/SolidCraft.app/Contents/Resources/SolidCraft.icns" test -s "$MNT/SolidCraft.app/Contents/Resources/SolidCraft.icns"
cmp "$HERE/README.txt" "$MNT/README.txt" cmp "$HERE/README.txt" "$MNT/README.txt"
case "$ARCH" in universal) WANT=(arm64 x86_64) ;; aarch64) WANT=(arm64) ;; *) WANT=(x86_64) ;; esac case "$ARCH" in universal) WANT=(arm64 x86_64) ;; aarch64) WANT=(arm64) ;; *) WANT=(x86_64) ;; esac
@@ -115,14 +118,17 @@ hdiutil detach "$MNT"
# ---- CLI --------------------------------------------------------------------------------------- # ---- CLI ---------------------------------------------------------------------------------------
echo "==> building $CLI_ZIP" echo "==> building $CLI_ZIP"
CLI_DIR="$WORK/solvecraft-cli-$VERSION-macos-$ARCH" CLI_DIR="$WORK/solidcraft-cli-$VERSION-macos-$ARCH"
mkdir -p "$CLI_DIR" mkdir -p "$CLI_DIR"
cp "$WORK/bin/solidcraft-cli" "$CLI_DIR/"
codesign --force --sign - --timestamp=none --identifier "$MACOS_BUNDLE_ID-cli" "$CLI_DIR/solidcraft-cli"
# Compatibility shim (docs/compatibility.md): the old CLI name forwards to solidcraft-cli.
cp "$WORK/bin/solvecraft-cli" "$CLI_DIR/" cp "$WORK/bin/solvecraft-cli" "$CLI_DIR/"
codesign --force --sign - --timestamp=none --identifier ai.storyteller.solvecraft-cli "$CLI_DIR/solvecraft-cli" codesign --force --sign - --timestamp=none --identifier "$MACOS_BUNDLE_ID-cli-alias" "$CLI_DIR/solvecraft-cli"
copy_docs "$CLI_DIR" copy_docs "$CLI_DIR"
rm -f "$CLI_ZIP" rm -f "$CLI_ZIP"
ditto -c -k --keepParent "$CLI_DIR" "$CLI_ZIP" ditto -c -k --keepParent "$CLI_DIR" "$CLI_ZIP"
"$WORK/bin/solvecraft-cli" --version "$WORK/bin/solidcraft-cli" --version
echo "==> done" echo "==> done"
ls -lh "$DMG" "$CLI_ZIP" ls -lh "$DMG" "$CLI_ZIP"
+1 -1
View File
@@ -69,7 +69,7 @@ class DesktopProbe(unittest.TestCase):
def test_cli_version_or_partial_control_output_is_not_desktop_success(self): def test_cli_version_or_partial_control_output_is_not_desktop_success(self):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
SMOKE.validate_replies("solvecraft-cli 0.3.0\n") SMOKE.validate_replies("solidcraft-cli 0.3.0\n")
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
SMOKE.validate_replies(output(healthy_replies()[:1])) SMOKE.validate_replies(output(healthy_replies()[:1]))
+3 -3
View File
@@ -1,10 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Build the browser version and zip it: $DIST/solvecraft-web-<version>.zip # Build the browser version and zip it: $DIST/solidcraft-web-<version>.zip
# #
# Usage: packaging/web/package.sh [--skip-build] # Usage: packaging/web/package.sh [--skip-build]
# #
# Needs: trunk and the wasm32-unknown-unknown target. The zip holds a self-contained static site # Needs: trunk and the wasm32-unknown-unknown target. The zip holds a self-contained static site
# in solvecraft-web-<version>/ that works from any URL path (public_url = "./" in Trunk.toml). # in solidcraft-web-<version>/ that works from any URL path (public_url = "./" in Trunk.toml).
# Saving designs needs HTTPS or localhost (the browser's private file storage). # Saving designs needs HTTPS or localhost (the browser's private file storage).
# Adapted from PhotoCraft's packaging (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md). # Adapted from PhotoCraft's packaging (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md).
set -euo pipefail set -euo pipefail
@@ -24,7 +24,7 @@ if grep -Eq '(src|href)="/[^/]' "$SITE/index.html"; then
exit 1 exit 1
fi fi
NAME="solvecraft-web-$VERSION" NAME="solidcraft-web-$VERSION"
WORK="$CARGO_TARGET_DIR/web-package" WORK="$CARGO_TARGET_DIR/web-package"
rm -rf "$WORK" rm -rf "$WORK"
mkdir -p "$WORK/$NAME" mkdir -p "$WORK/$NAME"
+25 -22
View File
@@ -1,15 +1,16 @@
<# <#
.SYNOPSIS .SYNOPSIS
Build and package SolveCraft for Windows. Build and package SolidCraft for Windows.
.DESCRIPTION .DESCRIPTION
Produces, in $env:DIST (default: dist/release): Produces, in $env:DIST (default: dist/release):
solvecraft-<version>-windows-<arch>.msi per-machine installer (WiX v5) solidcraft-<version>-windows-<arch>.msi per-machine installer (WiX v5)
solvecraft-<version>-windows-<arch>-portable.zip solvecraft.exe + solvecraft-cli.exe + licences solidcraft-<version>-windows-<arch>-portable.zip solidcraft.exe + solidcraft-cli.exe + licences
SolveCraft-<version>-windows-<arch>.exe the app alone (x64 only: a plain download) (+ the solvecraft-cli.exe compatibility alias)
SolidCraft-<version>-windows-<arch>.exe the app alone (x64 only: a plain download)
The binaries link the C runtime statically (+crt-static), so nothing else needs installing. The binaries link the C runtime statically (+crt-static), so nothing else needs installing.
The icon comes from $env:SOLVECRAFT_ICONS (solvecraft.ico, made by `solvecraft-cli icon`), or The icon comes from $env:SOLIDCRAFT_ICONS (solidcraft.ico, made by `solidcraft-cli icon`), or
is drawn by the CLI just built when this machine can run it. Nothing is signed. is drawn by the CLI just built when this machine can run it. Nothing is signed.
Needs: Rust (MSVC toolchain + the target) and WiX v5: Needs: Rust (MSVC toolchain + the target) and WiX v5:
@@ -36,7 +37,7 @@ function Invoke-Native([string] $What, [scriptblock] $Block) {
} }
# The version lives in one place: [workspace.package] version in the root Cargo.toml. # The version lives in one place: [workspace.package] version in the root Cargo.toml.
$Version = $env:SOLVECRAFT_VERSION $Version = $env:SOLIDCRAFT_VERSION
if (-not $Version) { if (-not $Version) {
$inPkg = $false $inPkg = $false
foreach ($line in Get-Content (Join-Path $Root 'Cargo.toml')) { foreach ($line in Get-Content (Join-Path $Root 'Cargo.toml')) {
@@ -60,7 +61,7 @@ if (-not $SkipBuild) {
# proc-macros are unaffected. # proc-macros are unaffected.
$flagVar = 'CARGO_TARGET_' + ($Target.ToUpper() -replace '-', '_') + '_RUSTFLAGS' $flagVar = 'CARGO_TARGET_' + ($Target.ToUpper() -replace '-', '_') + '_RUSTFLAGS'
[Environment]::SetEnvironmentVariable($flagVar, '-C target-feature=+crt-static') [Environment]::SetEnvironmentVariable($flagVar, '-C target-feature=+crt-static')
Invoke-Native "cargo build ($Target)" { cargo build --release --locked -p solvecraft -p solvecraft-cli --target $Target } Invoke-Native "cargo build ($Target)" { cargo build --release --locked -p solidcraft -p solidcraft-cli --target $Target }
} }
$Bin = Join-Path $TargetDir "$Target\release" $Bin = Join-Path $TargetDir "$Target\release"
@@ -72,33 +73,35 @@ function Get-PeHeader([string] $Path) {
return @{ Machine = [BitConverter]::ToUInt16($bytes, $pe + 4); Subsystem = [BitConverter]::ToUInt16($bytes, $pe + 0x5C) } return @{ Machine = [BitConverter]::ToUInt16($bytes, $pe + 4); Subsystem = [BitConverter]::ToUInt16($bytes, $pe + 0x5C) }
} }
$Machine = switch ($Arch) { 'x64' { 0x8664 } 'x86' { 0x14C } 'arm64' { 0xAA64 } } $Machine = switch ($Arch) { 'x64' { 0x8664 } 'x86' { 0x14C } 'arm64' { 0xAA64 } }
foreach ($check in @(@('solvecraft.exe', 2), @('solvecraft-cli.exe', 3))) { # solvecraft-cli.exe: the old CLI name, forwarding to solidcraft-cli.exe (compatibility shim,
# docs/compatibility.md). Built by `-p solidcraft-cli` with the CLI.
foreach ($check in @(@('solidcraft.exe', 2), @('solidcraft-cli.exe', 3), @('solvecraft-cli.exe', 3))) {
$h = Get-PeHeader (Join-Path $Bin $check[0]) $h = Get-PeHeader (Join-Path $Bin $check[0])
if ($h.Machine -ne $Machine) { throw "$($check[0]) is for machine 0x$('{0:X}' -f $h.Machine), expected 0x$('{0:X}' -f $Machine) ($Arch)" } if ($h.Machine -ne $Machine) { throw "$($check[0]) is for machine 0x$('{0:X}' -f $h.Machine), expected 0x$('{0:X}' -f $Machine) ($Arch)" }
if ($h.Subsystem -ne $check[1]) { throw "$($check[0]) has PE subsystem $($h.Subsystem), expected $($check[1])" } if ($h.Subsystem -ne $check[1]) { throw "$($check[0]) has PE subsystem $($h.Subsystem), expected $($check[1])" }
Write-Output "ok $($check[0]): $Arch, PE subsystem $($h.Subsystem)" Write-Output "ok $($check[0]): $Arch, PE subsystem $($h.Subsystem)"
} }
$Stage = Join-Path $TargetDir "windows-package\$Arch" $Stage = Join-Path $TargetDir "windows-package\$Arch"
& (Join-Path $PSScriptRoot 'check-icon.ps1') -Path (Join-Path $Bin 'solvecraft.exe') & (Join-Path $PSScriptRoot 'check-icon.ps1') -Path (Join-Path $Bin 'solidcraft.exe')
Remove-Item -Recurse -Force $Stage -ErrorAction SilentlyContinue Remove-Item -Recurse -Force $Stage -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path $Stage | Out-Null New-Item -ItemType Directory -Force -Path $Stage | Out-Null
Copy-Item (Join-Path $Bin 'solvecraft.exe'), (Join-Path $Bin 'solvecraft-cli.exe') $Stage Copy-Item (Join-Path $Bin 'solidcraft.exe'), (Join-Path $Bin 'solidcraft-cli.exe'), (Join-Path $Bin 'solvecraft-cli.exe') $Stage
foreach ($f in 'LICENSE-MIT', 'LICENSE-APACHE', 'NOTICE', 'THIRD-PARTY-LICENSES.txt') { Copy-Item (Join-Path $Root $f) $Stage } foreach ($f in 'LICENSE-MIT', 'LICENSE-APACHE', 'NOTICE', 'THIRD-PARTY-LICENSES.txt') { Copy-Item (Join-Path $Root $f) $Stage }
$HostArch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant() $HostArch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant()
$CanRun = ($Arch -ne 'arm64' -or $HostArch -eq 'arm64') $CanRun = ($Arch -ne 'arm64' -or $HostArch -eq 'arm64')
$Icon = if ($env:SOLVECRAFT_ICONS) { Join-Path $env:SOLVECRAFT_ICONS 'solvecraft.ico' } else { Join-Path $Stage 'solvecraft.ico' } $Icon = if ($env:SOLIDCRAFT_ICONS) { Join-Path $env:SOLIDCRAFT_ICONS 'solidcraft.ico' } else { Join-Path $Stage 'solidcraft.ico' }
if (-not (Test-Path $Icon)) { if (-not (Test-Path $Icon)) {
if (-not $CanRun) { throw "no icon: set SOLVECRAFT_ICONS to a folder with solvecraft.ico (an $Arch CLI can't run on this $HostArch machine)" } if (-not $CanRun) { throw "no icon: set SOLIDCRAFT_ICONS to a folder with solidcraft.ico (an $Arch CLI can't run on this $HostArch machine)" }
Invoke-Native 'draw the icon' { & (Join-Path $Stage 'solvecraft-cli.exe') icon --out $Icon } Invoke-Native 'draw the icon' { & (Join-Path $Stage 'solidcraft-cli.exe') icon --out $Icon }
} }
# ---- MSI --------------------------------------------------------------------------------------- # ---- MSI ---------------------------------------------------------------------------------------
$Msi = Join-Path $Dist "solvecraft-$Version-windows-$Arch.msi" $Msi = Join-Path $Dist "solidcraft-$Version-windows-$Arch.msi"
Invoke-Native 'wix build' { Invoke-Native 'wix build' {
wix build (Join-Path $PSScriptRoot 'solvecraft.wxs') -arch $Arch ` wix build (Join-Path $PSScriptRoot 'solidcraft.wxs') -arch $Arch `
-ext WixToolset.UI.wixext -ext WixToolset.Util.wixext ` -ext WixToolset.UI.wixext -ext WixToolset.Util.wixext `
-culture en-US -loc (Join-Path $PSScriptRoot 'solvecraft.en-us.wxl') ` -culture en-US -loc (Join-Path $PSScriptRoot 'solidcraft.en-us.wxl') `
-d "Version=$MsiVersion" -d "DisplayVersion=$Version" -d "BinDir=$Stage" -d "IconPath=$Icon" ` -d "Version=$MsiVersion" -d "DisplayVersion=$Version" -d "BinDir=$Stage" -d "IconPath=$Icon" `
-o $Msi -o $Msi
} }
@@ -109,26 +112,26 @@ Invoke-Native 'MSI shortcut icon validation (ICE50)' {
Remove-Item -Force -ErrorAction SilentlyContinue ([IO.Path]::ChangeExtension($Msi, '.wixpdb')) Remove-Item -Force -ErrorAction SilentlyContinue ([IO.Path]::ChangeExtension($Msi, '.wixpdb'))
# ---- portable zip ------------------------------------------------------------------------------ # ---- portable zip ------------------------------------------------------------------------------
$Portable = Join-Path $TargetDir "windows-package\solvecraft-$Version-windows-$Arch-portable" $Portable = Join-Path $TargetDir "windows-package\solidcraft-$Version-windows-$Arch-portable"
Remove-Item -Recurse -Force $Portable -ErrorAction SilentlyContinue Remove-Item -Recurse -Force $Portable -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path $Portable | Out-Null New-Item -ItemType Directory -Force -Path $Portable | Out-Null
Copy-Item (Join-Path $Stage '*.exe') $Portable Copy-Item (Join-Path $Stage '*.exe') $Portable
foreach ($f in 'README.md', 'LICENSE-MIT', 'LICENSE-APACHE', 'NOTICE', 'THIRD-PARTY-LICENSES.txt') { Copy-Item (Join-Path $Root $f) $Portable } foreach ($f in 'README.md', 'LICENSE-MIT', 'LICENSE-APACHE', 'NOTICE', 'THIRD-PARTY-LICENSES.txt') { Copy-Item (Join-Path $Root $f) $Portable }
$Zip = Join-Path $Dist "solvecraft-$Version-windows-$Arch-portable.zip" $Zip = Join-Path $Dist "solidcraft-$Version-windows-$Arch-portable.zip"
Remove-Item -Force $Zip -ErrorAction SilentlyContinue Remove-Item -Force $Zip -ErrorAction SilentlyContinue
Compress-Archive -Path $Portable -DestinationPath $Zip Compress-Archive -Path $Portable -DestinationPath $Zip
# ---- the app as a plain download (x64) --------------------------------------------------------- # ---- the app as a plain download (x64) ---------------------------------------------------------
$Outputs = @($Msi, $Zip) $Outputs = @($Msi, $Zip)
if ($Arch -eq 'x64') { if ($Arch -eq 'x64') {
$Exe = Join-Path $Dist "SolveCraft-$Version-windows-$Arch.exe" $Exe = Join-Path $Dist "SolidCraft-$Version-windows-$Arch.exe"
Copy-Item (Join-Path $Stage 'solvecraft.exe') $Exe Copy-Item (Join-Path $Stage 'solidcraft.exe') $Exe
$Outputs += $Exe $Outputs += $Exe
} }
if ($CanRun) { if ($CanRun) {
Invoke-Native 'solvecraft-cli --version' { & (Join-Path $Stage 'solvecraft-cli.exe') --version } Invoke-Native 'solidcraft-cli --version' { & (Join-Path $Stage 'solidcraft-cli.exe') --version }
} else { } else {
Write-Output "skipping solvecraft-cli --version: an $Arch build doesn't run on this $HostArch machine" Write-Output "skipping solidcraft-cli --version: an $Arch build doesn't run on this $HostArch machine"
} }
Get-Item $Outputs | Format-Table Name, Length Get-Item $Outputs | Format-Table Name, Length
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Overrides for the setup wizard's WixUI strings, so its pages name the version being installed Overrides for the setup wizard's WixUI strings, so its pages name the version being installed
([SolvecraftVersion] is the full version, pre-release tag included, set in solvecraft.wxs). ([SolidcraftVersion] is the full version, pre-release tag included, set in solidcraft.wxs).
Adapted from PhotoCraft's (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md). Adapted from PhotoCraft's (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md).
--> -->
<WixLocalization Culture="en-US" xmlns="http://wixtoolset.org/schemas/v4/wxl"> <WixLocalization Culture="en-US" xmlns="http://wixtoolset.org/schemas/v4/wxl">
<String Id="WelcomeDlgTitle" Value="{\WixUI_Font_Bigger}Welcome to the [ProductName] [SolvecraftVersion] Setup Wizard" /> <String Id="WelcomeDlgTitle" Value="{\WixUI_Font_Bigger}Welcome to the [ProductName] [SolidcraftVersion] Setup Wizard" />
<String Id="WelcomeDlgDescription" Value="The Setup Wizard will install [ProductName] version [SolvecraftVersion] on your computer. Click Next to continue or Cancel to exit the Setup Wizard." /> <String Id="WelcomeDlgDescription" Value="The Setup Wizard will install [ProductName] version [SolidcraftVersion] on your computer. Click Next to continue or Cancel to exit the Setup Wizard." />
<String Id="VerifyReadyDlgInstallTitle" Value="{\WixUI_Font_Title}Ready to install [ProductName] [SolvecraftVersion]" /> <String Id="VerifyReadyDlgInstallTitle" Value="{\WixUI_Font_Title}Ready to install [ProductName] [SolidcraftVersion]" />
<String Id="ExitDialogTitle" Value="{\WixUI_Font_Bigger}Completed the [ProductName] [SolvecraftVersion] Setup Wizard" /> <String Id="ExitDialogTitle" Value="{\WixUI_Font_Bigger}Completed the [ProductName] [SolidcraftVersion] Setup Wizard" />
</WixLocalization> </WixLocalization>
@@ -2,19 +2,21 @@
<!-- <!--
SolidCraft MSI (WiX Toolset v5, plus the UI and Util extensions). Built by package.ps1: SolidCraft MSI (WiX Toolset v5, plus the UI and Util extensions). Built by package.ps1:
wix build solvecraft.wxs -arch x64 -ext WixToolset.UI.wixext -ext WixToolset.Util.wixext wix build solidcraft.wxs -arch x64 -ext WixToolset.UI.wixext -ext WixToolset.Util.wixext
-culture en-US -loc solvecraft.en-us.wxl -d Version=1.2.3 -d DisplayVersion=1.2.3-rc.1 -culture en-US -loc solidcraft.en-us.wxl -d Version=1.2.3 -d DisplayVersion=1.2.3-rc.1
-d BinDir=... -d IconPath=... -o out.msi -d BinDir=... -d IconPath=... -o out.msi
Per-machine install with a setup wizard: Welcome, install folder (Program Files\SolveCraft by Per-machine install with a setup wizard: Welcome, install folder (Program Files\SolidCraft by
default, remembered for upgrades), Ready, progress, and a Finish page with a ticked "Launch default, remembered for upgrades), Ready, progress, and a Finish page with a ticked "Launch
SolidCraft" box. Installs a Start Menu shortcut, solvecraft-cli, the licence files (including SolidCraft" box. Installs a Start Menu shortcut, solidcraft-cli, the licence files (including
THIRD-PARTY-LICENSES.txt), makes SolidCraft the owner of `.solvecraft` and offers it under THIRD-PARTY-LICENSES.txt), makes SolidCraft the owner of `.solidcraft` (and of the pre-rename `.solvecraft`), and offers it under
"Open with" for STEP, IGES, 3MF and STL. `msiexec /qn` installs silently. "Open with" for STEP, IGES, 3MF and STL. `msiexec /qn` installs silently.
Adapted from PhotoCraft's (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md). Adapted from PhotoCraft's (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md).
--> -->
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui"> xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
<!-- Never change the UpgradeCode: it is what lets a new MSI replace every earlier install,
including those from before the SolveCraft -> SolidCraft rename (docs/compatibility.md). -->
<Package <Package
Name="SolidCraft" Name="SolidCraft"
Manufacturer="SolidCraft contributors" Manufacturer="SolidCraft contributors"
@@ -30,24 +32,27 @@
<MediaTemplate EmbedCab="yes" CompressionLevel="high" /> <MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<!-- Advertised shortcuts to an .exe need an .exe icon identifier (ICE50). --> <!-- Advertised shortcuts to an .exe need an .exe icon identifier (ICE50). -->
<Icon Id="SolvecraftIcon.exe" SourceFile="$(var.IconPath)" /> <Icon Id="SolidcraftIcon.exe" SourceFile="$(var.IconPath)" />
<Property Id="ARPPRODUCTICON" Value="SolvecraftIcon.exe" /> <Property Id="ARPPRODUCTICON" Value="SolidcraftIcon.exe" />
<Property Id="ARPURLINFOABOUT" Value="https://bherbruck.github.io/solidcraft/" /> <Property Id="ARPURLINFOABOUT" Value="https://bherbruck.github.io/solidcraft/" />
<Property Id="ARPURLUPDATEINFO" Value="https://github.com/bherbruck/solidcraft/releases" /> <Property Id="ARPURLUPDATEINFO" Value="https://github.com/bherbruck/solidcraft/releases" />
<Property Id="ARPHELPLINK" Value="https://github.com/bherbruck/solidcraft/issues" /> <Property Id="ARPHELPLINK" Value="https://github.com/bherbruck/solidcraft/issues" />
<StandardDirectory Id="ProgramFiles6432Folder"> <StandardDirectory Id="ProgramFiles6432Folder">
<Directory Id="INSTALLFOLDER" Name="SolveCraft" /> <Directory Id="INSTALLFOLDER" Name="SolidCraft" />
</StandardDirectory> </StandardDirectory>
<StandardDirectory Id="ProgramMenuFolder" /> <StandardDirectory Id="ProgramMenuFolder" />
<!-- An upgrade installs where the user put the previous version (written by SolvecraftApp). --> <!-- An upgrade installs where the user put the previous version (written by SolidcraftApp). -->
<!-- Since the rename the folder and this key say SolidCraft. A pre-rename install recorded
Software\SolveCraft, which isn't read: its upgrade (same UpgradeCode) removes the old
folder and installs into Program Files\SolidCraft (docs/compatibility.md). -->
<Property Id="INSTALLFOLDER"> <Property Id="INSTALLFOLDER">
<RegistrySearch Id="PreviousInstallFolder" Root="HKLM" Key="Software\SolveCraft" Name="InstallDir" Type="raw" /> <RegistrySearch Id="PreviousInstallFolder" Root="HKLM" Key="Software\SolidCraft" Name="InstallDir" Type="raw" />
</Property> </Property>
<Feature Id="Main" Title="SolidCraft" Level="1"> <Feature Id="Main" Title="SolidCraft" Level="1">
<ComponentGroupRef Id="SolvecraftFiles" /> <ComponentGroupRef Id="SolidcraftFiles" />
</Feature> </Feature>
<!-- WixUI_InstallDir without its licence page (MIT OR Apache-2.0: nothing to accept). --> <!-- WixUI_InstallDir without its licence page (MIT OR Apache-2.0: nothing to accept). -->
@@ -55,63 +60,75 @@
<UI> <UI>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg" Order="2" Condition="NOT Installed" /> <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg" Order="2" Condition="NOT Installed" />
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2" /> <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2" />
<Publish Dialog="ExitDialog" Control="Finish" Event="DoAction" Value="LaunchSolvecraft" <Publish Dialog="ExitDialog" Control="Finish" Event="DoAction" Value="LaunchSolidcraft"
Condition="WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 AND NOT Installed" /> Condition="WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 AND NOT Installed" />
</UI> </UI>
<Property Id="SolvecraftVersion" Value="$(var.DisplayVersion)" /> <Property Id="SolidcraftVersion" Value="$(var.DisplayVersion)" />
<Property Id="WIXUI_EXITDIALOGOPTIONALTEXT" Value="SolidCraft $(var.DisplayVersion) is installed. You can start it any time from the Start menu." /> <Property Id="WIXUI_EXITDIALOGOPTIONALTEXT" Value="SolidCraft $(var.DisplayVersion) is installed. You can start it any time from the Start menu." />
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch SolidCraft" /> <Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch SolidCraft" />
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1" /> <Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1" />
<Property Id="WixShellExecTarget" Value="[#SolvecraftExe]" /> <Property Id="WixShellExecTarget" Value="[#SolidcraftExe]" />
<!-- Runs in the wizard's own (unelevated) process, so the app starts as the user. --> <!-- Runs in the wizard's own (unelevated) process, so the app starts as the user. -->
<CustomAction Id="LaunchSolvecraft" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" DllEntry="WixShellExec" Impersonate="yes" Return="ignore" /> <CustomAction Id="LaunchSolidcraft" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" DllEntry="WixShellExec" Impersonate="yes" Return="ignore" />
</Package> </Package>
<Fragment> <Fragment>
<ComponentGroup Id="SolvecraftFiles" Directory="INSTALLFOLDER"> <ComponentGroup Id="SolidcraftFiles" Directory="INSTALLFOLDER">
<Component Id="SolvecraftApp" Guid="290BEF27-C200-4069-AA43-7DE6A39CDB0A"> <!-- A new GUID with the rename: the key file changed from solvecraft.exe to solidcraft.exe.
<File Id="SolvecraftExe" Source="$(var.BinDir)\solvecraft.exe" KeyPath="yes"> The UpgradeCode above is unchanged, so this MSI major-upgrades a pre-rename install. -->
<Component Id="SolidcraftApp" Guid="A379D509-D776-4B34-A3A4-71FBF5724971">
<File Id="SolidcraftExe" Source="$(var.BinDir)\solidcraft.exe" KeyPath="yes">
<Shortcut Id="StartMenuShortcut" Directory="ProgramMenuFolder" Name="SolidCraft" <Shortcut Id="StartMenuShortcut" Directory="ProgramMenuFolder" Name="SolidCraft"
Description="SolidCraft parametric 3D CAD" WorkingDirectory="INSTALLFOLDER" Advertise="yes" Description="SolidCraft parametric 3D CAD" WorkingDirectory="INSTALLFOLDER" Advertise="yes"
Icon="SolvecraftIcon.exe" IconIndex="0" /> Icon="SolidcraftIcon.exe" IconIndex="0" />
</File> </File>
<!-- .solvecraft: SolidCraft's own format; SolidCraft is its default app. --> <!-- .solidcraft: SolidCraft's own format; SolidCraft is its default app. -->
<ProgId Id="Solvecraft.Design" Description="SolidCraft Design" Icon="SolvecraftExe" IconIndex="0"> <ProgId Id="Solidcraft.Design" Description="SolidCraft Design" Icon="SolidcraftExe" IconIndex="0">
<Extension Id="solvecraft" ContentType="application/x-solvecraft"> <Extension Id="solidcraft" ContentType="application/x-solidcraft">
<Verb Id="open" Command="Open" TargetFile="SolvecraftExe" Argument="&quot;%1&quot;" /> <Verb Id="open" Command="Open" TargetFile="SolidcraftExe" Argument="&quot;%1&quot;" />
</Extension> </Extension>
</ProgId> </ProgId>
<!-- Compatibility shim (docs/compatibility.md): designs saved before the rename open as
the same ProgId. Registered by hand: a second Extension under one ProgId would write
its open verb twice (WIX0091). -->
<RegistryValue Root="HKLM" Key="Software\Classes\.solvecraft" Value="Solidcraft.Design" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\.solvecraft" Name="Content Type" Value="application/x-solvecraft" Type="string" />
<!-- STEP, IGES and meshes: offered under "Open with", never forced as the default. --> <!-- STEP, IGES and meshes: offered under "Open with", never forced as the default. -->
<ProgId Id="Solvecraft.Model" Description="3D model" Icon="SolvecraftExe" IconIndex="0" /> <ProgId Id="Solidcraft.Model" Description="3D model" Icon="SolidcraftExe" IconIndex="0" />
<RegistryValue Root="HKLM" Key="Software\Classes\Solvecraft.Model\shell\open\command" Value="&quot;[#SolvecraftExe]&quot; &quot;%1&quot;" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Solidcraft.Model\shell\open\command" Value="&quot;[#SolidcraftExe]&quot; &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\.step\OpenWithProgids" Name="Solvecraft.Model" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\.step\OpenWithProgids" Name="Solidcraft.Model" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\.stp\OpenWithProgids" Name="Solvecraft.Model" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\.stp\OpenWithProgids" Name="Solidcraft.Model" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\.igs\OpenWithProgids" Name="Solvecraft.Model" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\.igs\OpenWithProgids" Name="Solidcraft.Model" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\.iges\OpenWithProgids" Name="Solvecraft.Model" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\.iges\OpenWithProgids" Name="Solidcraft.Model" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\.3mf\OpenWithProgids" Name="Solvecraft.Model" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\.3mf\OpenWithProgids" Name="Solidcraft.Model" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\.stl\OpenWithProgids" Name="Solvecraft.Model" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\.stl\OpenWithProgids" Name="Solidcraft.Model" Value="" Type="string" />
<!-- "Open with" app list and the Run dialog (Win+R "solvecraft"). --> <!-- "Open with" app list and the Run dialog (Win+R "solidcraft"). -->
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\solvecraft.exe" Name="FriendlyAppName" Value="SolidCraft" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe" Name="FriendlyAppName" Value="SolidCraft" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\solvecraft.exe\shell\open\command" Value="&quot;[#SolvecraftExe]&quot; &quot;%1&quot;" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe\shell\open\command" Value="&quot;[#SolidcraftExe]&quot; &quot;%1&quot;" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\solvecraft.exe\SupportedTypes" Name=".solvecraft" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe\SupportedTypes" Name=".solidcraft" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\solvecraft.exe\SupportedTypes" Name=".step" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe\SupportedTypes" Name=".solvecraft" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\solvecraft.exe\SupportedTypes" Name=".stp" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe\SupportedTypes" Name=".step" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\solvecraft.exe\SupportedTypes" Name=".igs" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe\SupportedTypes" Name=".stp" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\solvecraft.exe\SupportedTypes" Name=".iges" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe\SupportedTypes" Name=".igs" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\solvecraft.exe\SupportedTypes" Name=".3mf" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe\SupportedTypes" Name=".iges" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Classes\Applications\solvecraft.exe\SupportedTypes" Name=".stl" Value="" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe\SupportedTypes" Name=".3mf" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\App Paths\solvecraft.exe" Value="[#SolvecraftExe]" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Classes\Applications\solidcraft.exe\SupportedTypes" Name=".stl" Value="" Type="string" />
<RegistryValue Root="HKLM" Key="Software\SolveCraft" Name="InstallDir" Value="[INSTALLFOLDER]" Type="string" /> <RegistryValue Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\App Paths\solidcraft.exe" Value="[#SolidcraftExe]" Type="string" />
<RegistryValue Root="HKLM" Key="Software\SolidCraft" Name="InstallDir" Value="[INSTALLFOLDER]" Type="string" />
</Component> </Component>
<Component Id="SolvecraftCli"> <Component Id="SolidcraftCli">
<File Id="SolvecraftCliExe" Source="$(var.BinDir)\solvecraft-cli.exe" KeyPath="yes" /> <File Id="SolidcraftCliExe" Source="$(var.BinDir)\solidcraft-cli.exe" KeyPath="yes" />
</Component>
<!-- Compatibility shim (docs/compatibility.md): the old CLI name, forwarding to solidcraft-cli. -->
<Component Id="SolidcraftCliAlias">
<File Id="SolvecraftCliAliasExe" Source="$(var.BinDir)\solvecraft-cli.exe" KeyPath="yes" />
</Component> </Component>
<!-- Several unversioned files: an explicit GUID (WIX0367). --> <!-- Several unversioned files: an explicit GUID (WIX0367). -->
<Component Id="SolvecraftLicences" Guid="CDEDEE8D-4BE9-4872-A2EA-EE623A6C7E91"> <Component Id="SolidcraftLicences" Guid="CDEDEE8D-4BE9-4872-A2EA-EE623A6C7E91">
<File Id="LicenseMit" Source="$(var.BinDir)\LICENSE-MIT" KeyPath="yes" /> <File Id="LicenseMit" Source="$(var.BinDir)\LICENSE-MIT" KeyPath="yes" />
<File Id="LicenseApache" Source="$(var.BinDir)\LICENSE-APACHE" /> <File Id="LicenseApache" Source="$(var.BinDir)\LICENSE-APACHE" />
<File Id="Notice" Source="$(var.BinDir)\NOTICE" /> <File Id="Notice" Source="$(var.BinDir)\NOTICE" />
+3 -3
View File
@@ -20,8 +20,8 @@ const SNAPSHOT_SIZE: (&str, &str) = ("960", "600");
pub fn run(root: &Path, build: bool) -> Result<(), String> { pub fn run(root: &Path, build: bool) -> Result<(), String> {
let book = root.join("docs/book"); let book = root.join("docs/book");
let mut c = cargo(); let mut c = cargo();
c.args(["build", "-q", "--release", "-p", "solvecraft-cli"]); c.args(["build", "-q", "--release", "-p", "solidcraft-cli"]);
crate::run(c, "cargo build -p solvecraft-cli")?; crate::run(c, "cargo build -p solidcraft-cli")?;
let out = cli().arg("commands").output().map_err(|e| format!("solvecraft-cli: {e}"))?; let out = cli().arg("commands").output().map_err(|e| format!("solvecraft-cli: {e}"))?;
if !out.status.success() { if !out.status.success() {
@@ -61,7 +61,7 @@ pub fn run(root: &Path, build: bool) -> Result<(), String> {
/// The release solvecraft-cli just built. /// The release solvecraft-cli just built.
fn cli() -> std::process::Command { fn cli() -> std::process::Command {
let mut c = cargo(); let mut c = cargo();
c.args(["run", "-q", "--release", "-p", "solvecraft-cli", "--"]); c.args(["run", "-q", "--release", "-p", "solidcraft-cli", "--"]);
c c
} }
+1 -1
View File
@@ -30,7 +30,7 @@ const AREAS: &[(&str, &str)] = &[
pub fn run(root: &Path) -> Result<(), String> { pub fn run(root: &Path) -> Result<(), String> {
let out = crate::cargo() let out = crate::cargo()
.args(["run", "-q", "--release", "-p", "solvecraft-cli", "--", "commands"]) .args(["run", "-q", "--release", "-p", "solidcraft-cli", "--", "commands"])
.output() .output()
.map_err(|e| format!("solvecraft-cli: {e}"))?; .map_err(|e| format!("solvecraft-cli: {e}"))?;
if !out.status.success() { if !out.status.success() {
+4 -4
View File
@@ -46,8 +46,8 @@ pub const TABLE: &[(&str, Class)] = &[
("mcp", Class::Layer(5)), ("mcp", Class::Layer(5)),
("testkit", Class::Testkit), ("testkit", Class::Testkit),
// apps and tooling // apps and tooling
("solvecraft", Class::Exempt), ("solidcraft", Class::Exempt),
("cli", Class::Exempt), ("solidcraft-cli", Class::Exempt),
("web", Class::Exempt), ("web", Class::Exempt),
("xtask", Class::Exempt), ("xtask", Class::Exempt),
]; ];
@@ -240,7 +240,7 @@ mod tests {
c("solvecraft-doc", &[("solvecraft-geom", Normal, true)]), c("solvecraft-doc", &[("solvecraft-geom", Normal, true)]),
c("solvecraft-engine", &[("solvecraft-doc", Normal, true), ("solvecraft-testkit", Dev, true)]), c("solvecraft-engine", &[("solvecraft-doc", Normal, true), ("solvecraft-testkit", Dev, true)]),
c("solvecraft-ui-egui", &[("solvecraft-engine", Normal, true), ("egui", Normal, false)]), c("solvecraft-ui-egui", &[("solvecraft-engine", Normal, true), ("egui", Normal, false)]),
c("solvecraft-cli", &[("solvecraft-ui-egui", Normal, true)]), c("solidcraft-cli", &[("solvecraft-ui-egui", Normal, true)]),
]; ];
assert!(check(&g).is_empty(), "{:?}", check(&g)); assert!(check(&g).is_empty(), "{:?}", check(&g));
} }
@@ -295,7 +295,7 @@ mod tests {
#[test] #[test]
fn apps_and_xtask_exempt() { fn apps_and_xtask_exempt() {
for app in ["solvecraft", "solvecraft-cli", "xtask"] { for app in ["solidcraft", "solidcraft-cli", "xtask"] {
assert!(check(&[c(app, &[("egui", Normal, false), ("solvecraft-ui-egui", Normal, true)])]).is_empty()); assert!(check(&[c(app, &[("egui", Normal, false), ("solvecraft-ui-egui", Normal, true)])]).is_empty());
} }
} }
+1 -1
View File
@@ -13,7 +13,7 @@ use serde_json::Value;
use crate::cargo; use crate::cargo;
pub const FILE: &str = "THIRD-PARTY-LICENSES.txt"; pub const FILE: &str = "THIRD-PARTY-LICENSES.txt";
const ROOTS: &[&str] = &["solvecraft", "solvecraft-cli", "solvecraft-web"]; const ROOTS: &[&str] = &["solidcraft", "solidcraft-cli", "solvecraft-web"];
pub fn run(root: &Path, check: bool) -> Result<(), String> { pub fn run(root: &Path, check: bool) -> Result<(), String> {
let text = generate(root)?; let text = generate(root)?;
+1 -1
View File
@@ -165,7 +165,7 @@ fn cmd_oracle(cli: Option<&str>) -> Result<(), String> {
} }
None => { None => {
let mut c = cargo(); let mut c = cargo();
c.args(["run", "-q", "--release", "-p", "solvecraft-cli", "--"]); c.args(["run", "-q", "--release", "-p", "solidcraft-cli", "--"]);
c c
} }
}; };