Files
OneCAD/apps/solvecraft/build.rs
T
bherbruckandClaude Opus 5.5 6090e89b3f Release under the SolidCraft name: binaries, assets and installers (#383)
* Release under the SolidCraft name: binaries, assets and installers

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

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

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

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

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

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-12 16:05:35 -04:00

62 lines
2.5 KiB
Rust

#![forbid(unsafe_code)]
#[path = "../app_icon.rs"]
mod app_icon;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-changed=../app_icon.rs");
println!("cargo:rerun-if-changed=build.rs");
if std::env::var("CARGO_CFG_TARGET_OS")? != "windows" {
return Ok(());
}
let out = std::path::PathBuf::from(std::env::var_os("OUT_DIR").ok_or("missing OUT_DIR")?);
let sizes = [16usize, 24, 32, 48, 64, 128, 256];
let mut images = Vec::new();
for size in sizes {
let rgba = app_icon::rgba(size)?;
// ICO DIB: bottom-up BGRA plus a padded one-bit transparency mask.
let mask_stride = size.div_ceil(32) * 4;
let mut dib = Vec::new();
dib.extend_from_slice(&40u32.to_le_bytes());
dib.extend_from_slice(&(size as i32).to_le_bytes());
dib.extend_from_slice(&((size * 2) as i32).to_le_bytes());
dib.extend_from_slice(&1u16.to_le_bytes());
dib.extend_from_slice(&32u16.to_le_bytes());
dib.extend_from_slice(&[0; 24]);
for row in rgba.chunks_exact(size * 4).rev() {
for p in row.as_chunks::<4>().0.iter() {
dib.extend_from_slice(&[p[2], p[1], p[0], p[3]]);
}
}
for row in rgba.chunks_exact(size * 4).rev() {
let mut mask = vec![0u8; mask_stride];
for (x, p) in row.as_chunks::<4>().0.iter().enumerate() {
if p[3] == 0 {
mask[x / 8] |= 0x80 >> (x % 8);
}
}
dib.extend_from_slice(&mask);
}
images.push((size, dib));
}
let mut ico = vec![0, 0, 1, 0];
ico.extend_from_slice(&(images.len() as u16).to_le_bytes());
let mut offset = 6 + 16 * images.len();
for (size, data) in &images {
let dim = if *size == 256 { 0 } else { *size as u8 };
ico.extend_from_slice(&[dim, dim, 0, 0, 1, 0, 32, 0]);
ico.extend_from_slice(&(data.len() as u32).to_le_bytes());
ico.extend_from_slice(&(offset as u32).to_le_bytes());
offset += data.len();
}
for (_, data) in images {
ico.extend_from_slice(&data);
}
let icon = out.join("solidcraft.ico");
std::fs::write(&icon, ico)?;
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, ["solidcraft"], embed_resource::NONE).manifest_required()?;
Ok(())
}