diff --git a/.github/release-notes.md b/.github/release-notes.md index 4224aca0..05f01db5 100644 --- a/.github/release-notes.md +++ b/.github/release-notes.md @@ -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/) · [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: -`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 -IDs and archive filenames still work. Published 0.2.0 and 0.2.1 releases keep their original -SolveCraft branding. Documentation, the browser app and the Flatpak feed use the new -SolidCraft project Pages URLs; old-name Pages addresses are not permanent aliases. +**Renamed to SolidCraft.** Downloads, installers and programs now carry the SolidCraft name: +the desktop app is `solidcraft`, the command line `solidcraft-cli`. `solvecraft-cli` is still +installed as a deprecated alias that forwards to `solidcraft-cli` (it prints a one-line note on +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?** -- **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). - **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 `.deb` or `.rpm`, the `.flatpak` (`flatpak install --user `), or the `.tar.gz`. -- **FreeBSD:** `tar -xzf solvecraft-{version}-freebsd-x86_64.tar.gz --strip-components 1 -C /usr/local`. -- **Web:** `solvecraft-web-{version}.zip` is a static site to host yourself. +- **FreeBSD:** `tar -xzf solidcraft-{version}-freebsd-x86_64.tar.gz --strip-components 1 -C /usr/local`. +- **Web:** `solidcraft-web-{version}.zip` is a static site to host yourself. - `SHA256SUMS.txt`: `sha256sum -c SHA256SUMS.txt --ignore-missing`. **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 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, -settings and the bundle identifier are unchanged. The DMG includes these instructions. +to the Trash. Remove any Dock shortcut with the old name and pin the new app. Designs +and settings are unchanged. The DMG includes these instructions. For Flatpak feed installation and updates, add Flathub for the required runtime before installing SolidCraft; keep both remotes in the same user installation: ```sh 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 install --user solvecraft ai.storyteller.solvecraft +flatpak remote-add --user --if-not-exists solidcraft https://bherbruck.github.io/solidcraft/flatpak/solidcraft.flatpakrepo +flatpak install --user solidcraft 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 **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**. -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: [ROADMAP.md](https://github.com/bherbruck/solidcraft/blob/main/ROADMAP.md#known-limitations). diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ab041b2..85bce754 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -218,9 +218,9 @@ jobs: with: version: v0.16.0 - 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 - run: cargo xtask oracle --cli target/ci/solvecraft-cli + run: cargo xtask oracle --cli target/ci/solidcraft-cli - name: Upload the report if: always() uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 diff --git a/.github/workflows/packaging-lint.yml b/.github/workflows/packaging-lint.yml index 602f73ef..4461c06f 100644 --- a/.github/workflows/packaging-lint.yml +++ b/.github/workflows/packaging-lint.yml @@ -52,8 +52,8 @@ jobs: } - name: XML, desktop entry, AppStream, Flatpak manifest 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 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" - 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'" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index af194d24..d6d65ccf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -79,7 +79,7 @@ jobs: { 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" - # 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. icons: needs: version @@ -91,10 +91,10 @@ jobs: - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 with: key: release-icons - - run: cargo build --release --locked -p solvecraft-cli + - run: cargo build --release --locked -p solidcraft-cli - run: | . 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 with: name: icons @@ -114,8 +114,8 @@ jobs: - { arch: x86_64, runner: ubuntu-22.04, deb: amd64 } - { arch: aarch64, runner: ubuntu-22.04-arm, deb: arm64 } env: - SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} - SOLVECRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} + SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }} + SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} NFPM_VERSION: 2.47.0 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -135,17 +135,22 @@ jobs: - name: Check the packages run: | 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 -qlp dist/release/*.rpm | grep -E '/usr/bin/solvecraft$|THIRD-PARTY-LICENSES.txt' - tar -tzf dist/release/*.tar.gz | grep -E '/bin/solvecraft$|THIRD-PARTY-LICENSES.txt' - ldd target/release/solvecraft + rpm -qlp dist/release/*.rpm | grep -E '/usr/bin/solidcraft$|THIRD-PARTY-LICENSES.txt' + tar -tzf dist/release/*.tar.gz | grep -E '/bin/solidcraft$|THIRD-PARTY-LICENSES.txt' + ldd target/release/solidcraft for appimage in dist/release/*.AppImage; do chmod +x "$appimage" APPIMAGE_EXTRACT_AND_RUN=1 "$appimage" --version "$appimage" --appimage-updateinformation | grep -F 'gh-releases-zsync|' test -s "$appimage.zsync" done + # Legacy AppImage update alias (docs/compatibility.md). + ls dist/release/solvecraft-*-linux-*.AppImage.zsync - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: release-linux-${{ matrix.arch }} @@ -166,8 +171,8 @@ jobs: - { arch: x86_64, runner: ubuntu-24.04 } - { arch: aarch64, runner: ubuntu-24.04-arm } env: - SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} - SOLVECRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} + SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }} + SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - 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. sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 - 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 with: name: release-flatpak-${{ matrix.arch }} @@ -198,8 +203,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 180 env: - SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} - SOLVECRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} + SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }} + SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Build and package in a FreeBSD VM (tar.gz) @@ -211,7 +216,7 @@ jobs: cpu: 4 mem: 12288 # 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: | 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 @@ -221,10 +226,10 @@ jobs: git config --global --add safe.directory "$PWD" # Build outside the checkout so only dist/ is copied back out of the VM. 4 jobs: more # 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 - tar -tzf dist/release/solvecraft-*-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$' + tar -tzf dist/release/solidcraft-*-freebsd-x86_64.tar.gz \ + | 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 with: name: release-freebsd-x86_64 @@ -237,8 +242,8 @@ jobs: if: needs.version.outputs.build == 'true' runs-on: macos-14 env: - SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} - SOLVECRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} + SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }} + SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: dtolnay/rust-toolchain@stable @@ -269,7 +274,7 @@ jobs: # Windows on ARM: cross-compiled on the x64 runner. - { arch: arm64, target: aarch64-pc-windows-msvc } env: - SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} + SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 @@ -290,7 +295,7 @@ jobs: - name: Build and package (msi, portable zip) shell: pwsh env: - SOLVECRAFT_ICONS: ${{ github.workspace }}/icons + SOLIDCRAFT_ICONS: ${{ github.workspace }}/icons run: ./packaging/windows/package.ps1 -Arch ${{ matrix.arch }} - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: @@ -304,7 +309,7 @@ jobs: if: needs.version.outputs.build == 'true' runs-on: ubuntu-latest env: - SOLVECRAFT_VERSION: ${{ needs.version.outputs.version }} + SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }} TRUNK_VERSION: 0.21.14 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/AGENTS.md b/AGENTS.md index d3a84cdd..4c78025b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -115,7 +115,7 @@ version bumps solely from commit prefixes, overwrite published versions, or push before the draft is verified. ## 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`. - 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}}}` @@ -128,7 +128,7 @@ before the draft is verified. - 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 values never come from a commercial CAD product. -- Build with `CARGO_TARGET_DIR=/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. +- Build with `CARGO_TARGET_DIR=/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solidcraft`. ## Roadmap `ROADMAP.md` (committed) tracks status, milestones and estimates. Update it whenever a diff --git a/CLAUDE.md b/CLAUDE.md index f4f88494..d6adbec2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -92,7 +92,7 @@ version bumps solely from commit prefixes, overwrite published versions, or push before the draft is verified. ## 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`. - 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}}}` @@ -105,7 +105,7 @@ before the draft is verified. - 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 values never come from a commercial CAD product. -- Build with `CARGO_TARGET_DIR=/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solvecraft`. +- Build with `CARGO_TARGET_DIR=/target`. Windows: `cargo xwin build --release --target x86_64-pc-windows-msvc -p solidcraft`. ## Roadmap `ROADMAP.md` (committed) tracks status, milestones and estimates. Update it whenever a diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20982b91..c345d5a5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,23 +17,23 @@ build you also need `rustup target add wasm32-unknown-unknown` and [`trunk`](htt ```sh 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 ci # everything a PR must pass (see below) ``` SolidCraft is the product and repository name. Cargo packages and executables retain 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 -`cargo build --release -p solvecraft-cli`. Run the CLI with -`cargo run --release -p solvecraft-cli -- commands` (or `target/release/solvecraft-cli commands` +Build the desktop app with `cargo build --release -p solidcraft`, or the CLI with +`cargo build --release -p solidcraft-cli`. Run the CLI with +`cargo run --release -p solidcraft-cli -- commands` (or `target/release/solidcraft-cli commands` after building). There is no Cargo package named `solidcraft`. 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 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` diff --git a/Cargo.lock b/Cargo.lock index d998f2ac..bca12999 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3289,7 +3289,7 @@ dependencies = [ ] [[package]] -name = "solvecraft" +name = "solidcraft" version = "0.5.0" dependencies = [ "eframe", @@ -3306,7 +3306,7 @@ dependencies = [ ] [[package]] -name = "solvecraft-cli" +name = "solidcraft-cli" version = "0.5.0" dependencies = [ "serde_json", diff --git a/README.md b/README.md index 781c523d..316e8669 100644 --- a/README.md +++ b/README.md @@ -100,16 +100,16 @@ renamed repository; old-name Pages and Flatpak URLs are not maintained as perman ## Build and run ```sh -cargo run --release -p solvecraft -- --sample # desktop app with a sample part -cargo run --release -p solvecraft-cli -- commands # the command registry -cargo run --release -p solvecraft-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 solvecraft -- 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 -- --sample # desktop app with a sample part +cargo run --release -p solidcraft-cli -- commands # the command registry +cargo run --release -p solidcraft-cli -- run examples/bracket.json --out bracket.step +cargo run --release -p solidcraft-cli -- snapshot examples/bracket.json --out bracket.png +cargo run --release -p solidcraft -- part.step # open a STEP file as a new design +cargo run --release -p solidcraft-cli -- eval part.step # measure an imported STEP file 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 multi-axis HID interface. Move the cap to pan and zoom, and tilt or twist it to rotate the 3D view. diff --git a/apps/solvecraft-cli/Cargo.toml b/apps/solvecraft-cli/Cargo.toml index 2a69012a..aacadb60 100644 --- a/apps/solvecraft-cli/Cargo.toml +++ b/apps/solvecraft-cli/Cargo.toml @@ -1,17 +1,24 @@ [package] -name = "solvecraft-cli" +name = "solidcraft-cli" description = "SolidCraft headless CLI: run command scripts, measure, export, render snapshots, replay oracle recipes" version.workspace = true edition.workspace = true license.workspace = true +default-run = "solidcraft-cli" [lints] workspace = true [[bin]] -name = "solvecraft-cli" +name = "solidcraft-cli" 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] solvecraft-engine = { workspace = true } solvecraft-mcp = { workspace = true } diff --git a/apps/solvecraft-cli/src/alias.rs b/apps/solvecraft-cli/src/alias.rs new file mode 100644 index 00000000..7030880d --- /dev/null +++ b/apps/solvecraft-cli/src/alias.rs @@ -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 + } + } +} diff --git a/apps/solvecraft-cli/src/fuzz.rs b/apps/solvecraft-cli/src/fuzz.rs index 0fb98fc3..6c76fede 100644 --- a/apps/solvecraft-cli/src/fuzz.rs +++ b/apps/solvecraft-cli/src/fuzz.rs @@ -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 //! is recorded like any other failure. diff --git a/apps/solvecraft-cli/src/main.rs b/apps/solvecraft-cli/src/main.rs index dd62bd43..8c3dd781 100644 --- a/apps/solvecraft-cli/src/main.rs +++ b/apps/solvecraft-cli/src/main.rs @@ -1,17 +1,17 @@ //! SolveCraft headless command line. //! //! ```text -//! solvecraft-cli run [--in design|part.step|mesh.3mf] [--out FILE]... [--save FILE] [--quiet] -//! solvecraft-cli eval (alias: inspect) measurements as JSON -//! solvecraft-cli bench-open [--parse-only] loading timings as JSON lines -//! solvecraft-cli snapshot --out shot.png [--width W] [--height H] [--view iso|front|top|…] -//! solvecraft-cli exec [json-params] run one command on an empty design -//! solvecraft-cli commands the command registry as JSON -//! solvecraft-cli recipe translate an oracle recipe to a script -//! solvecraft-cli oracle ... replay recipes and compare with expected.json -//! solvecraft-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 -//! solvecraft-cli icon --out F.png|F.ico [--size N] the app icon (packaging; drawn, not a file) +//! solidcraft-cli run [--in design|part.step|mesh.3mf] [--out FILE]... [--save FILE] [--quiet] +//! solidcraft-cli eval (alias: inspect) measurements as JSON +//! solidcraft-cli bench-open [--parse-only] loading timings as JSON lines +//! solidcraft-cli snapshot --out shot.png [--width W] [--height H] [--view iso|front|top|…] +//! solidcraft-cli exec [json-params] run one command on an empty design +//! solidcraft-cli commands the command registry as JSON +//! solidcraft-cli recipe translate an oracle recipe to a script +//! solidcraft-cli oracle ... replay recipes and compare with expected.json +//! solidcraft-cli mcp [--in design|script] [--connect HOST:PORT] MCP server on stdio (docs/mcp.md) +//! solidcraft-cli licences SolveCraft's licence and the third-party licences +//! 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)] #![forbid(unsafe_code)] @@ -31,19 +31,19 @@ use solvecraft_engine::Session; use solvecraft_engine::render::{StandardView, render_png}; const USAGE: &str = "usage: - solvecraft-cli run [--in design.solvecraft|part.step] [--out FILE]... [--save FILE] [--quiet] [--results] - solvecraft-cli run --in [--out FILE]... - solvecraft-cli eval (alias: inspect; or --in FILE) - solvecraft-cli bench-open [--parse-only] - solvecraft-cli snapshot --out shot.png [--width W] [--height H] [--view iso|front|back|top|bottom|left|right] - solvecraft-cli exec [json-params] - solvecraft-cli commands - solvecraft-cli recipe - solvecraft-cli oracle ... [--json] - solvecraft-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] - solvecraft-cli licences - solvecraft-cli icon --out icon.png [--size 256] | --out icon.ico + solidcraft-cli run [--in design.solvecraft|part.step] [--out FILE]... [--save FILE] [--quiet] [--results] + solidcraft-cli run --in [--out FILE]... + solidcraft-cli eval (alias: inspect; or --in FILE) + solidcraft-cli bench-open [--parse-only] + solidcraft-cli snapshot --out shot.png [--width W] [--height H] [--view iso|front|back|top|bottom|left|right] + solidcraft-cli exec [json-params] + solidcraft-cli commands + solidcraft-cli recipe + solidcraft-cli oracle ... [--json] + solidcraft-cli fuzz [--from N] [--count N] [--jobs J] [--timeout S] [--steps N] [--minimise] [--out DIR] [--report FILE] + solidcraft-cli mcp [--in design.solvecraft|script.json] [--connect 127.0.0.1:PORT] + solidcraft-cli licences + solidcraft-cli icon --out icon.png [--size 256] | --out icon.ico "; fn main() -> ExitCode { @@ -87,7 +87,7 @@ fn main() -> ExitCode { Some("bench-edit") => cmd_bench_edit(&args[1..]), Some("bench-open") => cmd_bench_open(&args[1..]), Some("--version" | "-V") => { - println!("solvecraft-cli {}", env!("CARGO_PKG_VERSION")); + println!("solidcraft-cli {}", env!("CARGO_PKG_VERSION")); Ok(()) } _ => 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. fn cmd_save_stress(args: &[String]) -> Result<(), String> { let (Some(path), Some(rounds)) = (args.first(), args.get(1).and_then(|n| n.parse::().ok())) else { - return Err("usage: solvecraft-cli save-stress ".into()); + return Err("usage: solidcraft-cli save-stress ".into()); }; let mut s = Session::default(); 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). fn cmd_bench_edit(args: &[String]) -> Result<(), String> { let (Some(path), Some(param), Some(expr)) = (args.first(), args.get(1), args.get(2)) else { - return Err("usage: solvecraft-cli bench-edit ".into()); + return Err("usage: solidcraft-cli bench-edit ".into()); }; let v = read_json(path)?; 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. fn cmd_bench_open(args: &[String]) -> Result<(), String> { - let path = args.first().ok_or("usage: solvecraft-cli bench-open [--parse-only]")?; + let path = args.first().ok_or("usage: solidcraft-cli bench-open [--parse-only]")?; let t = std::time::Instant::now(); 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 }; diff --git a/apps/solvecraft-cli/tests/commands_output.rs b/apps/solvecraft-cli/tests/commands_output.rs index 7637ba88..57c409da 100644 --- a/apps/solvecraft-cli/tests/commands_output.rs +++ b/apps/solvecraft-cli/tests/commands_output.rs @@ -4,7 +4,7 @@ use std::process::{Command, Stdio}; #[test] 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)); let registry: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); let commands = registry.as_array().unwrap(); @@ -16,7 +16,7 @@ fn registry_output_is_complete_json() { #[test] 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: // the registry is larger than the pipe buffer, so it cannot all be written first. drop(child.stdout.take()); diff --git a/apps/solvecraft-cli/tests/fuzz_range.rs b/apps/solvecraft-cli/tests/fuzz_range.rs index 60c2ae20..4c169d52 100644 --- a/apps/solvecraft-cli/tests/fuzz_range.rs +++ b/apps/solvecraft-cli/tests/fuzz_range.rs @@ -5,7 +5,7 @@ use std::process::Command; #[test] fn overflowing_seed_range_is_an_error_not_a_panic() { 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)); let stderr = String::from_utf8_lossy(&output.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] fn empty_seed_range_at_maximum_is_valid() { 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!(String::from_utf8_lossy(&output.stdout).starts_with("0 seeds, 0 design steps,")); } #[test] 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"]) .output() .unwrap(); diff --git a/apps/solvecraft-cli/tests/kill_mid_save.rs b/apps/solvecraft-cli/tests/kill_mid_save.rs index 57f48071..e63952dc 100644 --- a/apps/solvecraft-cli/tests/kill_mid_save.rs +++ b/apps/solvecraft-cli/tests/kill_mid_save.rs @@ -12,7 +12,7 @@ fn round_of(path: &std::path::Path) -> Option { #[test] 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 _ = std::fs::remove_dir_all(&dir); std::fs::create_dir_all(&dir).unwrap(); diff --git a/apps/solvecraft-cli/tests/legacy_alias.rs b/apps/solvecraft-cli/tests/legacy_alias.rs new file mode 100644 index 00000000..691b97a7 --- /dev/null +++ b/apps/solvecraft-cli/tests/legacy_alias.rs @@ -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); +} diff --git a/apps/solvecraft-cli/tests/mcp_connect.rs b/apps/solvecraft-cli/tests/mcp_connect.rs index 675c4400..92812d32 100644 --- a/apps/solvecraft-cli/tests/mcp_connect.rs +++ b/apps/solvecraft-cli/tests/mcp_connect.rs @@ -7,7 +7,7 @@ use std::process::{Command, Stdio}; fn mcp_connect_without_a_listening_app_names_the_control_flag() { // 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 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}")]) .stdin(Stdio::null()) .output() diff --git a/apps/solvecraft-cli/tests/run_results.rs b/apps/solvecraft-cli/tests/run_results.rs index 441502f0..8962e11b 100644 --- a/apps/solvecraft-cli/tests/run_results.rs +++ b/apps/solvecraft-cli/tests/run_results.rs @@ -31,7 +31,7 @@ impl Drop for Scratch { } 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 { diff --git a/apps/solvecraft/Cargo.toml b/apps/solvecraft/Cargo.toml index 84e1d0b4..8ccf63b0 100644 --- a/apps/solvecraft/Cargo.toml +++ b/apps/solvecraft/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "solvecraft" +name = "solidcraft" description = "SolidCraft desktop app" version.workspace = true edition.workspace = true license.workspace = true publish = false -default-run = "solvecraft" +default-run = "solidcraft" [lints] workspace = true diff --git a/apps/solvecraft/build.rs b/apps/solvecraft/build.rs index 6a065a80..7133a148 100644 --- a/apps/solvecraft/build.rs +++ b/apps/solvecraft/build.rs @@ -56,6 +56,6 @@ fn main() -> Result<(), Box> { let rc = out.join("solidcraft.rc"); 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. - embed_resource::compile_for(&rc, ["solvecraft"], embed_resource::NONE).manifest_required()?; + embed_resource::compile_for(&rc, ["solidcraft"], embed_resource::NONE).manifest_required()?; Ok(()) } diff --git a/apps/solvecraft/src/main.rs b/apps/solvecraft/src/main.rs index 763b5d1e..3267d450 100644 --- a/apps/solvecraft/src/main.rs +++ b/apps/solvecraft/src/main.rs @@ -155,11 +155,11 @@ fn main() -> eframe::Result { "--control" => control_port = args.next().and_then(|p| p.parse().ok()), "--sample" => sample = true, "--version" | "-V" => { - println!("solvecraft {}", env!("CARGO_PKG_VERSION")); + println!("solidcraft {}", env!("CARGO_PKG_VERSION")); return Ok(()); } "--help" | "-h" => { - println!("usage: solvecraft [--control PORT] [--sample] [design.solvecraft | part.step]"); + println!("usage: solidcraft [--control PORT] [--sample] [design.solvecraft | part.step]"); return Ok(()); } _ => files.push(a), diff --git a/docs/book/src/guide/getting-started.md b/docs/book/src/guide/getting-started.md index 848e5805..a6fd7386 100644 --- a/docs/book/src/guide/getting-started.md +++ b/docs/book/src/guide/getting-started.md @@ -12,12 +12,12 @@ stable Rust (1.95 or newer): ```sh 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 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 @@ -71,11 +71,11 @@ cd apps/solvecraft-web && trunk serve --release `solvecraft-cli` runs the same commands without a window: ```sh -cargo run --release -p solvecraft-cli -- commands # every command, as JSON -cargo run --release -p solvecraft-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 solvecraft-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 -- commands # every command, as JSON +cargo run --release -p solidcraft-cli -- run examples/bracket.json --out bracket.step +cargo run --release -p solidcraft-cli -- eval examples/bracket.json # volume, area, faces… +cargo run --release -p solidcraft-cli -- snapshot examples/bracket.json --out bracket.png +cargo run --release -p solidcraft-cli -- exec solid.box '{"length": 20, "width": 10, "height": 5}' ``` A script is a list of commands: diff --git a/docs/compatibility.md b/docs/compatibility.md new file mode 100644 index 00000000..4b69dc2c --- /dev/null +++ b/docs/compatibility.md @@ -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--linux-.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`. diff --git a/flake.nix b/flake.nix index bf3e5fea..fcc6e3c1 100644 --- a/flake.nix +++ b/flake.nix @@ -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 fi ''} - command -v cc >/dev/null || echo "solvecraft: no C linker on PATH, cargo cannot link — use nix develop .#rust" >&2 - echo "solvecraft: cargo run --release -p solvecraft -- --sample" + command -v cc >/dev/null || echo "solidcraft: no C linker on PATH, cargo cannot link — use nix develop .#rust" >&2 + echo "solidcraft: cargo run --release -p solidcraft -- --sample" ${pkgs.lib.optionalString pkgs.stdenv.isLinux '' export XDG_DATA_DIRS="${driverShareDir pkgs}:''${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" ''} @@ -97,7 +97,7 @@ CARGO_TARGET_DIR = "target/nix"; shellHook = '' ${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. cargoBuildFlags = [ "-p" - "solvecraft" + "solidcraft" "-p" - "solvecraft-cli" + "solidcraft-cli" ]; cargoInstallFlags = [ "-p" - "solvecraft" + "solidcraft" "-p" - "solvecraft-cli" + "solidcraft-cli" ]; # `cargo xtask ci` is the test gate (it wants a wasm target and a GPU); the sandbox has # neither. @@ -134,7 +134,6 @@ buildInputs = runtimeLibs pkgs; postInstall = '' - ln -s solvecraft $out/bin/solidcraft ${pkgs.lib.optionalString pkgs.stdenv.isLinux '' install -Dm644 packaging/linux/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 icon=$out/share/icons/hicolor/''${size}x''${size}/apps/ai.storyteller.solvecraft.png 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 ''} ''; @@ -151,7 +150,7 @@ # 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. postFixup = pkgs.lib.optionalString pkgs.stdenv.isLinux '' - wrapProgram $out/bin/solvecraft \ + wrapProgram $out/bin/solidcraft \ --prefix LD_LIBRARY_PATH : "${libraryPath pkgs}" \ --set-default XDG_DATA_DIRS /usr/local/share:/usr/share \ --prefix XDG_DATA_DIRS : "$out/share:${driverShareDir pkgs}" @@ -175,8 +174,7 @@ in { default = desktop; solidcraft = desktop; - solvecraft = { type = "app"; program = "${package}/bin/solvecraft"; }; - cli = { type = "app"; program = "${package}/bin/solvecraft-cli"; }; + cli = { type = "app"; program = "${package}/bin/solidcraft-cli"; }; }); }; } diff --git a/packaging/env.sh b/packaging/env.sh index 4cbc9643..e2461d08 100644 --- a/packaging/env.sh +++ b/packaging/env.sh @@ -4,9 +4,12 @@ # # Exports: # 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) -# 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) ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" @@ -20,7 +23,7 @@ workspace_version() { ' "$ROOT/Cargo.toml" } -VERSION="${SOLVECRAFT_VERSION:-$(workspace_version)}" +VERSION="${SOLIDCRAFT_VERSION:-${SOLVECRAFT_VERSION:-$(workspace_version)}}" if [ -z "$VERSION" ]; then echo "error: could not read [workspace.package] version from $ROOT/Cargo.toml" >&2 exit 1 @@ -32,8 +35,11 @@ mkdir -p "$DIST" DIST="$(cd "$DIST" && pwd)" 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}" +# 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 export APP_ID @@ -43,7 +49,7 @@ warn() { } # 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() { local dest="$1" f 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): -# $1 = the solvecraft-cli to run, $2 = output dir. Writes hicolor/x/apps/$APP_ID.png, -# solvecraft.ico and solvecraft-1024.png. +# $1 = the solidcraft-cli to run, $2 = output dir. Writes hicolor/x/apps/$APP_ID.png, +# solidcraft.ico and solidcraft-1024.png. make_icons() { local cli="$1" out="$2" s for s in 16 24 32 48 64 128 256 512; do mkdir -p "$out/hicolor/${s}x${s}/apps" "$cli" icon --size "$s" --out "$out/hicolor/${s}x${s}/apps/$APP_ID.png" >/dev/null done - "$cli" icon --out "$out/solvecraft.ico" >/dev/null - "$cli" icon --size 1024 --out "$out/solvecraft-1024.png" >/dev/null + "$cli" icon --out "$out/solidcraft.ico" >/dev/null + "$cli" icon --size 1024 --out "$out/solidcraft-1024.png" >/dev/null } diff --git a/packaging/flatpak-site.sh b/packaging/flatpak-site.sh index 9e2169f3..842b9345 100644 --- a/packaging/flatpak-site.sh +++ b/packaging/flatpak-site.sh @@ -5,6 +5,7 @@ set -euo pipefail site="${1:?site directory required}" tag="${RELEASE_TAG:-}" +# Compatibility shim (docs/compatibility.md): the Flatpak app id keeps its pre-rename value. app_id=ai.storyteller.solvecraft if [ -z "$tag" ]; then 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 fi 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" ( cd "$bundles" @@ -53,7 +54,7 @@ flatpak build-update-repo --title="SolidCraft" --comment='Official SolidCraft re --description='Official Flatpak repository for SolidCraft' \ --homepage="https://github.com/$GITHUB_REPOSITORY" --default-branch=stable "$repo_dir" test -s "$repo_dir/summary" -cat >"$site/flatpak/solvecraft.flatpakrepo" <"$site/flatpak/solidcraft.flatpakrepo" <"$site/flatpak/index.html" <SolidCraft Flatpak repository

SolidCraft Flatpak repository

Latest published release: $tag

Add the SolidCraft repository

Flathub provides the required Freedesktop runtime. Add both remotes to the same user installation:

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 install --user solvecraft $app_id
+SolidCraft Flatpak repository

SolidCraft Flatpak repository

Latest published release: $tag

Add the SolidCraft repository

Flathub provides the required Freedesktop runtime. Add both remotes to the same user installation:

flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
+flatpak remote-add --user --if-not-exists solidcraft $base_url/flatpak/solidcraft.flatpakrepo
+flatpak install --user solidcraft $app_id
 flatpak run $app_id
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" diff --git a/packaging/freebsd/package.sh b/packaging/freebsd/package.sh index 4995808a..e13404db 100755 --- a/packaging/freebsd/package.sh +++ b/packaging/freebsd/package.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash # Build and package SolidCraft for FreeBSD: # -# $DIST/solvecraft--freebsd-x86_64.tar.gz a /usr/local-style tree: -# solvecraft--freebsd-x86_64/{bin, share/applications, share/icons, share/mime, -# share/metainfo, share/doc/solvecraft} +# $DIST/solidcraft--freebsd-x86_64.tar.gz a /usr/local-style tree: +# solidcraft--freebsd-x86_64/{bin, share/applications, share/icons, share/mime, +# share/metainfo, share/doc/solidcraft} # # Install by copying the tree's contents into /usr/local: -# tar -xzf solvecraft--freebsd-x86_64.tar.gz --strip-components 1 -C /usr/local +# tar -xzf solidcraft--freebsd-x86_64.tar.gz --strip-components 1 -C /usr/local # # Usage: packaging/freebsd/package.sh [--skip-build] # 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 ;; *) echo "unsupported architecture $(uname -m)" >&2; exit 2 ;; esac -BASENAME="solvecraft-$VERSION-freebsd-$ARCH" +BASENAME="solidcraft-$VERSION-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. export CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-4}" 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 WORK="$CARGO_TARGET_DIR/freebsd-package" STAGE="$WORK/$BASENAME" @@ -46,25 +46,27 @@ rm -rf "$WORK" # FreeBSD's install(1) has no -D: create the directories first. mkdir -p "$STAGE/bin" "$STAGE/share/applications" "$STAGE/share/mime/packages" \ - "$STAGE/share/metainfo" "$STAGE/share/icons" "$STAGE/share/doc/solvecraft" -install -m 755 "$BIN/solvecraft" "$BIN/solvecraft-cli" "$STAGE/bin/" -strip "$STAGE/bin/solvecraft" "$STAGE/bin/solvecraft-cli" 2>/dev/null || true + "$STAGE/share/metainfo" "$STAGE/share/icons" "$STAGE/share/doc/solidcraft" +# solvecraft-cli: the old CLI name, forwarding to solidcraft-cli (compatibility shim, +# 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. 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" -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" -make_icons "$STAGE/bin/solvecraft-cli" "$WORK/icons" +make_icons "$STAGE/bin/solidcraft-cli" "$WORK/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" \ - "share/icons/hicolor/256x256/apps/$APP_ID.png" share/doc/solvecraft/LICENSE-MIT \ - share/doc/solvecraft/LICENSE-APACHE share/doc/solvecraft/THIRD-PARTY-LICENSES.txt; do +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/solidcraft/LICENSE-MIT \ + 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 done tar -C "$WORK" -czf "$DIST/$BASENAME.tar.gz" "$BASENAME" echo "wrote $DIST/$BASENAME.tar.gz" -"$STAGE/bin/solvecraft-cli" --version +"$STAGE/bin/solidcraft-cli" --version echo "==> done" diff --git a/packaging/linux/AppRun b/packaging/linux/AppRun index 8b2728ec..dc7f0d86 100755 --- a/packaging/linux/AppRun +++ b/packaging/linux/AppRun @@ -3,20 +3,22 @@ # 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 -# 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 # generic "Wayland" icon. Best-effort desktop integration: on first run # (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 -# 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 APPDIR="$(dirname "$(readlink -f "$0")")" +# Compatibility shim (docs/compatibility.md): the pre-rename reverse-DNS id. DESK_ID=ai.storyteller.solvecraft integrate() { - case "${SOLVECRAFT_NO_DESKTOP_INTEGRATION:-}" in + case "${SOLIDCRAFT_NO_DESKTOP_INTEGRATION:-${SOLVECRAFT_NO_DESKTOP_INTEGRATION:-}}" in 1 | true | yes) return 0 ;; esac # The AppImage runtime exports $APPIMAGE; without it (an extracted AppDir) there @@ -70,4 +72,4 @@ integrate() { } integrate -exec "$APPDIR/usr/bin/solvecraft" "$@" +exec "$APPDIR/usr/bin/solidcraft" "$@" diff --git a/packaging/linux/ai.storyteller.solvecraft.desktop b/packaging/linux/ai.storyteller.solvecraft.desktop index 0dad363e..6b4c7f64 100644 --- a/packaging/linux/ai.storyteller.solvecraft.desktop +++ b/packaging/linux/ai.storyteller.solvecraft.desktop @@ -3,12 +3,12 @@ Type=Application Name=SolidCraft GenericName=3D CAD Comment=Parametric 3D CAD: sketch, constrain, extrude, and change a parameter to rebuild -Exec=solvecraft %f -TryExec=solvecraft +Exec=solidcraft %f +TryExec=solidcraft Icon=ai.storyteller.solvecraft Terminal=false StartupNotify=true -StartupWMClass=solvecraft +StartupWMClass=solidcraft Categories=Graphics;3DGraphics;Engineering; 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; diff --git a/packaging/linux/ai.storyteller.solvecraft.metainfo.xml.in b/packaging/linux/ai.storyteller.solvecraft.metainfo.xml.in index e2b9e33d..7034c1c9 100644 --- a/packaging/linux/ai.storyteller.solvecraft.metainfo.xml.in +++ b/packaging/linux/ai.storyteller.solvecraft.metainfo.xml.in @@ -53,9 +53,9 @@ pointing - solvecraft - solvecraft-cli - application/x-solvecraft + solidcraft + solidcraft-cli + application/x-solidcraft diff --git a/packaging/linux/ai.storyteller.solvecraft.mime.xml b/packaging/linux/ai.storyteller.solvecraft.mime.xml index 90b811a3..38b4fb5c 100644 --- a/packaging/linux/ai.storyteller.solvecraft.mime.xml +++ b/packaging/linux/ai.storyteller.solvecraft.mime.xml @@ -2,10 +2,13 @@ - + SolidCraft design + + + diff --git a/packaging/linux/flatpak-bundle.sh b/packaging/linux/flatpak-bundle.sh index 58a09754..22424654 100755 --- a/packaging/linux/flatpak-bundle.sh +++ b/packaging/linux/flatpak-bundle.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash # Repackage a SolidCraft Linux tarball as a single-file Flatpak bundle: # -# $DIST/solvecraft--linux-.flatpak +# $DIST/solidcraft--linux-.flatpak # # Usage: packaging/linux/flatpak-bundle.sh [--no-test] [TARBALL] # -# TARBALL defaults to $DIST/solvecraft--linux-.tar.gz from package.sh. The bundle +# TARBALL defaults to $DIST/solidcraft--linux-.tar.gz from package.sh. The bundle # 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 # `appstreamcli compose`; the freedesktop runtime and SDK named in the manifest are @@ -37,7 +37,7 @@ case "$ARCH" in aarch64 | arm64) ARCH=aarch64 ;; *) echo "unsupported architecture $ARCH" >&2; exit 2 ;; esac -BASENAME="solvecraft-$VERSION-linux-$ARCH" +BASENAME="solidcraft-$VERSION-linux-$ARCH" TARBALL="${TARBALL:-$DIST/$BASENAME.tar.gz}" [ -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 @@ -50,7 +50,7 @@ WORK="$CARGO_TARGET_DIR/flatpak-bundle" rm -rf "$WORK" mkdir -p "$WORK/stage" 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" flatpak remote-add --user --if-not-exists flathub "$FLATHUB" @@ -66,8 +66,8 @@ echo "wrote $OUT" if [ "$TEST" = 1 ]; then flatpak install --user -y --noninteractive --reinstall "$OUT" flatpak info --user "$APP_ID" - flatpak run --command=solvecraft-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=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/solidcraft' python3 "$HERE/flatpak-smoke.py" --backend both fi echo "==> done" diff --git a/packaging/linux/flatpak-smoke.py b/packaging/linux/flatpak-smoke.py index 55a3d486..f92667fd 100644 --- a/packaging/linux/flatpak-smoke.py +++ b/packaging/linux/flatpak-smoke.py @@ -28,7 +28,7 @@ work=$(mktemp -d) 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" unset WGPU_BACKEND WGPU_BACKENDS -solvecraft --control 18837 >"$work/app.log" 2>&1 & +solidcraft --control 18837 >"$work/app.log" 2>&1 & app=$! cleanup() { kill "$app" 2>/dev/null || true @@ -165,10 +165,10 @@ def frame_statistics(png): def probe(gl_saved_four=False): shell = SANDBOX_PROBE if gl_saved_four: - shell = shell.replace('solvecraft --control', + shell = shell.replace('solidcraft --control', 'mkdir -p "$XDG_DATA_HOME/solvecraft"\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], text=True, capture_output=True, timeout=125) if result.returncode: @@ -201,6 +201,7 @@ def run_backend(backend): env.pop("WAYLAND_DISPLAY", None) env.pop("WAYLAND_SOCKET", None) env.pop("DISPLAY", None) + env.pop("SOLIDCRAFT_WAYLAND", None) env.pop("SOLVECRAFT_WAYLAND", None) command = ["dbus-run-session", "--"] compositor = None diff --git a/packaging/linux/flatpak/ai.storyteller.solvecraft.bundle.yml b/packaging/linux/flatpak/ai.storyteller.solvecraft.bundle.yml index 789eba4b..ccdf970f 100644 --- a/packaging/linux/flatpak/ai.storyteller.solvecraft.bundle.yml +++ b/packaging/linux/flatpak/ai.storyteller.solvecraft.bundle.yml @@ -1,17 +1,19 @@ # Flatpak manifest for the single-file bundle attached to every GitHub release -# (solvecraft--linux-.flatpak). Build it with packaging/linux/flatpak-bundle.sh. +# (solidcraft--linux-.flatpak). Build it with packaging/linux/flatpak-bundle.sh. # Adapted from PhotoCraft's (storytold/photocraft, Apache-2.0; see ATTRIBUTION.md). # -# It repackages the release's own Linux tarball (solvecraft--linux-.tar.gz, built +# It repackages the release's own Linux tarball (solidcraft--linux-.tar.gz, built # 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 # 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. +# 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 runtime: org.freedesktop.Platform runtime-version: '26.08' sdk: org.freedesktop.Sdk -command: solvecraft +command: solidcraft finish-args: # Display: Wayland first; X11 only when no Wayland compositor is running. - --socket=wayland @@ -28,16 +30,18 @@ finish-args: # the sandbox; `flatpak override --user --share=network ai.storyteller.solvecraft` exposes it to # host agents) and home/host filesystem access. modules: - - name: solvecraft + - name: solidcraft buildsystem: simple 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 -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 # 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 - - 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: - type: dir path: stage diff --git a/packaging/linux/nfpm.yaml b/packaging/linux/nfpm.yaml index bc0eca75..a258894b 100644 --- a/packaging/linux/nfpm.yaml +++ b/packaging/linux/nfpm.yaml @@ -1,7 +1,15 @@ # .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 # 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} platform: linux version: ${VERSION} @@ -10,14 +18,14 @@ version_schema: semver release: 1 section: graphics priority: optional -maintainer: ${SOLVECRAFT_MAINTAINER} +maintainer: ${SOLIDCRAFT_MAINTAINER} vendor: SolidCraft contributors homepage: https://bherbruck.github.io/solidcraft/ license: MIT OR Apache-2.0 description: |- Open-source parametric 3D CAD in the style of Fusion 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. # 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. overrides: deb: + # Debian's rename pattern: Replaces + Conflicts + Provides (docs/compatibility.md). + conflicts: + - solvecraft depends: - libc6 (>= 2.35) - libgcc-s1 @@ -59,9 +70,13 @@ overrides: - xdg-desktop-portal contents: - - src: ${STAGE}/usr/bin/solvecraft - dst: /usr/bin/solvecraft + - src: ${STAGE}/usr/bin/solidcraft + dst: /usr/bin/solidcraft 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 dst: /usr/bin/solvecraft-cli file_info: { mode: 0755 } diff --git a/packaging/linux/package.sh b/packaging/linux/package.sh index 9cbe9a40..27cf0e0d 100755 --- a/packaging/linux/package.sh +++ b/packaging/linux/package.sh @@ -1,11 +1,12 @@ #!/usr/bin/env bash # Build and package SolidCraft for Linux ( is x86_64 or aarch64): # -# $DIST/solvecraft--linux-.AppImage any distro with glibc >= the build host's -# $DIST/solvecraft--linux-.AppImage.zsync delta updates (needs zsyncmake) -# $DIST/solvecraft--linux-.deb Debian, Ubuntu, Mint, Pop!_OS, ... -# $DIST/solvecraft--linux-.rpm Fedora, openSUSE, RHEL, ... -# $DIST/solvecraft--linux-.tar.gz plain FHS-style tree (bin/, share/) +# $DIST/solidcraft--linux-.AppImage any distro with glibc >= the build host's +# $DIST/solidcraft--linux-.AppImage.zsync delta updates (needs zsyncmake) +# $DIST/solvecraft--linux-.AppImage.zsync the same, for pre-rename AppImages +# $DIST/solidcraft--linux-.deb Debian, Ubuntu, Mint, Pop!_OS, ... +# $DIST/solidcraft--linux-.rpm Fedora, openSUSE, RHEL, ... +# $DIST/solidcraft--linux-.tar.gz plain FHS-style tree (bin/, share/) # # 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 ;; *) echo "unsupported architecture $ARCH" >&2; exit 2 ;; esac -export SOLVECRAFT_MAINTAINER="${SOLVECRAFT_MAINTAINER:-SolidCraft contributors }" -BASENAME="solvecraft-$VERSION-linux-$ARCH" +export SOLIDCRAFT_MAINTAINER="${SOLIDCRAFT_MAINTAINER:-${SOLVECRAFT_MAINTAINER:-SolidCraft contributors }}" # SOLVECRAFT_*: compatibility shim, see docs/compatibility.md +BASENAME="solidcraft-$VERSION-linux-$ARCH" echo "==> SolidCraft $VERSION for Linux $ARCH ($FORMATS)" if [ "$SKIP_BUILD" = 0 ]; 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" 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" fi else @@ -62,19 +63,21 @@ STAGE="$WORK/root" rm -rf "$WORK" # ---- 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" -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.mime.xml" "$STAGE/usr/share/mime/packages/$APP_ID.xml" 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" -make_icons "$STAGE/usr/bin/solvecraft-cli" "$WORK/icons" +make_icons "$STAGE/usr/bin/solidcraft-cli" "$WORK/icons" mkdir -p "$STAGE/usr/share/icons" cp -R "$WORK/icons/hicolor" "$STAGE/usr/share/icons/" -mkdir -p "$STAGE/usr/share/doc/solvecraft" -copy_docs "$STAGE/usr/share/doc/solvecraft" +mkdir -p "$STAGE/usr/share/doc/solidcraft" +copy_docs "$STAGE/usr/share/doc/solidcraft" if command -v desktop-file-validate >/dev/null; then desktop-file-validate "$STAGE/usr/share/applications/$APP_ID.desktop" @@ -107,7 +110,7 @@ fi # ---- AppImage ----------------------------------------------------------------------------------- if has appimage; then - APPDIR="$WORK/SolveCraft.AppDir" + APPDIR="$WORK/SolidCraft.AppDir" cp -R "$STAGE" "$APPDIR" mv "$APPDIR/usr/share/doc" "$WORK/doc-unused" # 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 # release through the .zsync published next to each AppImage. `latest` is the newest published # release that is not a pre-release. - REPO="${GITHUB_REPOSITORY:-bherbruck/solvecraft}" - UPDATE_INFO="gh-releases-zsync|${REPO%%/*}|${REPO#*/}|latest|solvecraft-*-linux-$ARCH.AppImage.zsync" + REPO="${GITHUB_REPOSITORY:-bherbruck/solidcraft}" + 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 # 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") echo "wrote $OUT" if [ -s "$OUT.zsync" ]; then 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 warn "zsyncmake not found, so $OUT.zsync was not written; AppImage delta updates need it" fi fi -"$STAGE/usr/bin/solvecraft-cli" --version +"$STAGE/usr/bin/solidcraft-cli" --version echo "==> done" ls -lh "$DIST" diff --git a/packaging/macos/Info.plist.in b/packaging/macos/Info.plist.in index d2111bab..547172df 100644 --- a/packaging/macos/Info.plist.in +++ b/packaging/macos/Info.plist.in @@ -13,7 +13,7 @@ CFBundleExecutable SolidCraft CFBundleIdentifier - ai.storyteller.solvecraft + ai.storyteller.solidcraft CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType @@ -24,7 +24,7 @@ @SHORT_VERSION@ CFBundleVersion @SHORT_VERSION@ - SolveCraftVersion + SolidCraftVersion @VERSION@ CFBundleIconFile SolidCraft @@ -43,7 +43,8 @@ CFBundleTypeName SolidCraft design CFBundleTypeExtensions - solvecraft + + solidcraftsolvecraft CFBundleTypeRole Editor LSHandlerRank diff --git a/packaging/macos/README.txt b/packaging/macos/README.txt index 73ab6797..f18f1e73 100644 --- a/packaging/macos/README.txt +++ b/packaging/macos/README.txt @@ -2,16 +2,13 @@ Install SolidCraft Drag SolidCraft.app onto Applications. -Updating an older SolveCraft.app installation +Updating an older installation 1. Quit the app. -2. In Applications, rename the existing SolveCraft.app to SolidCraft.app. -3. Drag SolidCraft.app from this disk image onto Applications and choose Replace. +2. 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 -SolveCraft.app to the Trash. The disk image does not remove old installations. -If your Dock shortcut still uses the old name, remove it from the Dock, then -open SolidCraft.app from Applications and choose Options > Keep in Dock. +Some earlier releases were installed as SolveCraft.app. Move that one to the Trash +once SolidCraft.app is in Applications, and replace any Dock shortcut with the +old name (open SolidCraft.app, then choose Options > Keep in Dock). -Your designs and settings keep their existing locations. The bundle identifier -remains ai.storyteller.solvecraft; saved designs still use .solvecraft. +Your designs and settings are not affected by the update. diff --git a/packaging/macos/package.sh b/packaging/macos/package.sh index 2daf0a49..4b0b2ac7 100755 --- a/packaging/macos/package.sh +++ b/packaging/macos/package.sh @@ -1,8 +1,9 @@ #!/usr/bin/env bash # Build and package SolidCraft for macOS: # -# $DIST/solvecraft--macos-.dmg SolidCraft.app on a drag-to-Applications DMG -# $DIST/solvecraft-cli--macos-.zip the headless CLI with the licence files +# $DIST/solidcraft--macos-.dmg SolidCraft.app on a drag-to-Applications DMG +# $DIST/solidcraft-cli--macos-.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] # @@ -12,6 +13,9 @@ set -euo pipefail # shellcheck source=../env.sh . "$(dirname "${BASH_SOURCE[0]}")/../env.sh" 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 SKIP_BUILD=0 @@ -35,19 +39,19 @@ export MACOSX_DEPLOYMENT_TARGET=11.0 SHORT_VERSION="${VERSION%%-*}" WORK="$CARGO_TARGET_DIR/macos-package" APP="$WORK/SolidCraft.app" -DMG="$DIST/solvecraft-$VERSION-macos-$ARCH.dmg" -CLI_ZIP="$DIST/solvecraft-cli-$VERSION-macos-$ARCH.zip" +DMG="$DIST/solidcraft-$VERSION-macos-$ARCH.dmg" +CLI_ZIP="$DIST/solidcraft-cli-$VERSION-macos-$ARCH.zip" echo "==> SolidCraft $VERSION for macOS ($ARCH)" if [ "$SKIP_BUILD" = 0 ]; then args=() 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 rm -rf "$WORK" mkdir -p "$WORK/bin" -for bin in solvecraft solvecraft-cli; do +for bin in solidcraft solidcraft-cli solvecraft-cli; do inputs=() for t in "${TARGETS[@]}"; do inputs+=("$CARGO_TARGET_DIR/$t/release/$bin"); done lipo -create -output "$WORK/bin/$bin" "${inputs[@]}" @@ -57,13 +61,13 @@ done # ---- SolidCraft.app ---------------------------------------------------------------------------- echo "==> assembling $APP" 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). SET="$WORK/SolidCraft.iconset" mkdir -p "$SET" 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/solvecraft-cli" icon --size $((s * 2)) --out "$SET/icon_${s}x${s}@2x.png" >/dev/null + "$WORK/bin/solidcraft-cli" icon --size "$s" --out "$SET/icon_${s}x${s}.png" >/dev/null + "$WORK/bin/solidcraft-cli" icon --size $((s * 2)) --out "$SET/icon_${s}x${s}@2x.png" >/dev/null done iconutil -c icns -o "$APP/Contents/Resources/SolidCraft.icns" "$SET" 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" test -L "$MNT/Applications" && test "$(readlink "$MNT/Applications")" = /Applications 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 test "$(/usr/libexec/PlistBuddy -c "Print :$key" "$MNT/SolidCraft.app/Contents/Info.plist")" = SolidCraft done -test "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$MNT/SolidCraft.app/Contents/Info.plist")" = "$APP_ID" -test ! -e "$MNT/SolveCraft.app" +test "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$MNT/SolidCraft.app/Contents/Info.plist")" = "$MACOS_BUNDLE_ID" test -s "$MNT/SolidCraft.app/Contents/Resources/SolidCraft.icns" cmp "$HERE/README.txt" "$MNT/README.txt" case "$ARCH" in universal) WANT=(arm64 x86_64) ;; aarch64) WANT=(arm64) ;; *) WANT=(x86_64) ;; esac @@ -115,14 +118,17 @@ hdiutil detach "$MNT" # ---- CLI --------------------------------------------------------------------------------------- echo "==> building $CLI_ZIP" -CLI_DIR="$WORK/solvecraft-cli-$VERSION-macos-$ARCH" +CLI_DIR="$WORK/solidcraft-cli-$VERSION-macos-$ARCH" 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/" -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" rm -f "$CLI_ZIP" ditto -c -k --keepParent "$CLI_DIR" "$CLI_ZIP" -"$WORK/bin/solvecraft-cli" --version +"$WORK/bin/solidcraft-cli" --version echo "==> done" ls -lh "$DMG" "$CLI_ZIP" diff --git a/packaging/tests/flatpak_test.py b/packaging/tests/flatpak_test.py index ef3b3d5b..cfac0fdb 100644 --- a/packaging/tests/flatpak_test.py +++ b/packaging/tests/flatpak_test.py @@ -69,7 +69,7 @@ class DesktopProbe(unittest.TestCase): def test_cli_version_or_partial_control_output_is_not_desktop_success(self): 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): SMOKE.validate_replies(output(healthy_replies()[:1])) diff --git a/packaging/web/package.sh b/packaging/web/package.sh index 35f5f9ed..0c647846 100755 --- a/packaging/web/package.sh +++ b/packaging/web/package.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash -# Build the browser version and zip it: $DIST/solvecraft-web-.zip +# Build the browser version and zip it: $DIST/solidcraft-web-.zip # # Usage: packaging/web/package.sh [--skip-build] # # Needs: trunk and the wasm32-unknown-unknown target. The zip holds a self-contained static site -# in solvecraft-web-/ that works from any URL path (public_url = "./" in Trunk.toml). +# in solidcraft-web-/ that works from any URL path (public_url = "./" in Trunk.toml). # 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). set -euo pipefail @@ -24,7 +24,7 @@ if grep -Eq '(src|href)="/[^/]' "$SITE/index.html"; then exit 1 fi -NAME="solvecraft-web-$VERSION" +NAME="solidcraft-web-$VERSION" WORK="$CARGO_TARGET_DIR/web-package" rm -rf "$WORK" mkdir -p "$WORK/$NAME" diff --git a/packaging/windows/package.ps1 b/packaging/windows/package.ps1 index f70d172f..1ef9972c 100644 --- a/packaging/windows/package.ps1 +++ b/packaging/windows/package.ps1 @@ -1,15 +1,16 @@ <# .SYNOPSIS - Build and package SolveCraft for Windows. + Build and package SolidCraft for Windows. .DESCRIPTION Produces, in $env:DIST (default: dist/release): - solvecraft--windows-.msi per-machine installer (WiX v5) - solvecraft--windows--portable.zip solvecraft.exe + solvecraft-cli.exe + licences - SolveCraft--windows-.exe the app alone (x64 only: a plain download) + solidcraft--windows-.msi per-machine installer (WiX v5) + solidcraft--windows--portable.zip solidcraft.exe + solidcraft-cli.exe + licences + (+ the solvecraft-cli.exe compatibility alias) + SolidCraft--windows-.exe the app alone (x64 only: a plain download) 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. 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. -$Version = $env:SOLVECRAFT_VERSION +$Version = $env:SOLIDCRAFT_VERSION if (-not $Version) { $inPkg = $false foreach ($line in Get-Content (Join-Path $Root 'Cargo.toml')) { @@ -60,7 +61,7 @@ if (-not $SkipBuild) { # proc-macros are unaffected. $flagVar = 'CARGO_TARGET_' + ($Target.ToUpper() -replace '-', '_') + '_RUSTFLAGS' [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" @@ -72,33 +73,35 @@ function Get-PeHeader([string] $Path) { return @{ Machine = [BitConverter]::ToUInt16($bytes, $pe + 4); Subsystem = [BitConverter]::ToUInt16($bytes, $pe + 0x5C) } } $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]) 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])" } Write-Output "ok $($check[0]): $Arch, PE subsystem $($h.Subsystem)" } $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 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 } $HostArch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant() $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 $CanRun) { throw "no icon: set SOLVECRAFT_ICONS to a folder with solvecraft.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 } + 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 'solidcraft-cli.exe') icon --out $Icon } } # ---- MSI --------------------------------------------------------------------------------------- -$Msi = Join-Path $Dist "solvecraft-$Version-windows-$Arch.msi" +$Msi = Join-Path $Dist "solidcraft-$Version-windows-$Arch.msi" 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 ` - -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" ` -o $Msi } @@ -109,26 +112,26 @@ Invoke-Native 'MSI shortcut icon validation (ICE50)' { Remove-Item -Force -ErrorAction SilentlyContinue ([IO.Path]::ChangeExtension($Msi, '.wixpdb')) # ---- 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 New-Item -ItemType Directory -Force -Path $Portable | Out-Null 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 } -$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 Compress-Archive -Path $Portable -DestinationPath $Zip # ---- the app as a plain download (x64) --------------------------------------------------------- $Outputs = @($Msi, $Zip) if ($Arch -eq 'x64') { - $Exe = Join-Path $Dist "SolveCraft-$Version-windows-$Arch.exe" - Copy-Item (Join-Path $Stage 'solvecraft.exe') $Exe + $Exe = Join-Path $Dist "SolidCraft-$Version-windows-$Arch.exe" + Copy-Item (Join-Path $Stage 'solidcraft.exe') $Exe $Outputs += $Exe } 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 { - 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 diff --git a/packaging/windows/solvecraft.en-us.wxl b/packaging/windows/solidcraft.en-us.wxl similarity index 65% rename from packaging/windows/solvecraft.en-us.wxl rename to packaging/windows/solidcraft.en-us.wxl index f1cd7d43..184359e1 100644 --- a/packaging/windows/solvecraft.en-us.wxl +++ b/packaging/windows/solidcraft.en-us.wxl @@ -1,12 +1,12 @@ - - - - + + + + diff --git a/packaging/windows/solvecraft.wxs b/packaging/windows/solidcraft.wxs similarity index 55% rename from packaging/windows/solvecraft.wxs rename to packaging/windows/solidcraft.wxs index df464f8a..3dcdef06 100644 --- a/packaging/windows/solvecraft.wxs +++ b/packaging/windows/solidcraft.wxs @@ -2,19 +2,21 @@ + - - + + - + - + + - + - + @@ -55,63 +60,75 @@ - - + - + - + - - - + + + + + Icon="SolidcraftIcon.exe" IconIndex="0" /> - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + - - + + + + + + - + diff --git a/xtask/src/book.rs b/xtask/src/book.rs index cdd18a7f..5894a56f 100644 --- a/xtask/src/book.rs +++ b/xtask/src/book.rs @@ -20,8 +20,8 @@ const SNAPSHOT_SIZE: (&str, &str) = ("960", "600"); pub fn run(root: &Path, build: bool) -> Result<(), String> { let book = root.join("docs/book"); let mut c = cargo(); - c.args(["build", "-q", "--release", "-p", "solvecraft-cli"]); - crate::run(c, "cargo build -p solvecraft-cli")?; + c.args(["build", "-q", "--release", "-p", "solidcraft-cli"]); + crate::run(c, "cargo build -p solidcraft-cli")?; let out = cli().arg("commands").output().map_err(|e| format!("solvecraft-cli: {e}"))?; if !out.status.success() { @@ -61,7 +61,7 @@ pub fn run(root: &Path, build: bool) -> Result<(), String> { /// The release solvecraft-cli just built. fn cli() -> std::process::Command { let mut c = cargo(); - c.args(["run", "-q", "--release", "-p", "solvecraft-cli", "--"]); + c.args(["run", "-q", "--release", "-p", "solidcraft-cli", "--"]); c } diff --git a/xtask/src/features.rs b/xtask/src/features.rs index 776f4a09..de866c71 100644 --- a/xtask/src/features.rs +++ b/xtask/src/features.rs @@ -30,7 +30,7 @@ const AREAS: &[(&str, &str)] = &[ pub fn run(root: &Path) -> Result<(), String> { let out = crate::cargo() - .args(["run", "-q", "--release", "-p", "solvecraft-cli", "--", "commands"]) + .args(["run", "-q", "--release", "-p", "solidcraft-cli", "--", "commands"]) .output() .map_err(|e| format!("solvecraft-cli: {e}"))?; if !out.status.success() { diff --git a/xtask/src/layers.rs b/xtask/src/layers.rs index 29abb446..559cbb03 100644 --- a/xtask/src/layers.rs +++ b/xtask/src/layers.rs @@ -46,8 +46,8 @@ pub const TABLE: &[(&str, Class)] = &[ ("mcp", Class::Layer(5)), ("testkit", Class::Testkit), // apps and tooling - ("solvecraft", Class::Exempt), - ("cli", Class::Exempt), + ("solidcraft", Class::Exempt), + ("solidcraft-cli", Class::Exempt), ("web", Class::Exempt), ("xtask", Class::Exempt), ]; @@ -240,7 +240,7 @@ mod tests { c("solvecraft-doc", &[("solvecraft-geom", Normal, 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-cli", &[("solvecraft-ui-egui", Normal, true)]), + c("solidcraft-cli", &[("solvecraft-ui-egui", Normal, true)]), ]; assert!(check(&g).is_empty(), "{:?}", check(&g)); } @@ -295,7 +295,7 @@ mod tests { #[test] 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()); } } diff --git a/xtask/src/licences.rs b/xtask/src/licences.rs index 2a9ce96c..1a74b0de 100644 --- a/xtask/src/licences.rs +++ b/xtask/src/licences.rs @@ -13,7 +13,7 @@ use serde_json::Value; use crate::cargo; 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> { let text = generate(root)?; diff --git a/xtask/src/main.rs b/xtask/src/main.rs index ce79525a..d29a1823 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -165,7 +165,7 @@ fn cmd_oracle(cli: Option<&str>) -> Result<(), String> { } None => { let mut c = cargo(); - c.args(["run", "-q", "--release", "-p", "solvecraft-cli", "--"]); + c.args(["run", "-q", "--release", "-p", "solidcraft-cli", "--"]); c } };