diff --git a/build-fix.md b/build-fix.md new file mode 100644 index 0000000..d610af0 --- /dev/null +++ b/build-fix.md @@ -0,0 +1,118 @@ +# Fix for Issue #63: Version Mismatch in Windows Binary + +## Problem Analysis +The user reported downloading "shimmy 1.4.2" which shows version "0.1.0" and lacks the `gpu-info` command. Investigation reveals: + +1. **No v1.4.2 tag exists** - latest was v1.4.1, current is v1.5.5 +2. The binary was likely built from an incorrect source or development state +3. Version 0.1.0 suggests it was built from a very early commit or with corrupted build environment + +## Root Cause +The issue stems from the binary being built without proper Cargo.toml version information being embedded. This can happen when: +- Building from a source without proper Cargo.toml +- Build environment not setting CARGO_PKG_VERSION correctly +- Building from a Git worktree or modified state + +## Comprehensive Fix + +### 1. Version Validation at Build Time +Create a build script that validates version consistency: + +```rust +// build.rs +fn main() { + // Ensure version is not default + let version = env!("CARGO_PKG_VERSION"); + if version == "0.1.0" || version.is_empty() { + panic!("Invalid version detected: {}. Check Cargo.toml", version); + } + + // Validate semantic versioning + let parts: Vec<&str> = version.split('.').collect(); + if parts.len() < 3 { + panic!("Version must follow semantic versioning: {}", version); + } + + println!("cargo:rustc-env=SHIMMY_BUILD_VERSION={}", version); + println!("cargo:rerun-if-changed=Cargo.toml"); +} +``` + +### 2. Runtime Version Verification +Add version verification in main.rs: + +```rust +fn verify_build_version() { + let cargo_version = env!("CARGO_PKG_VERSION"); + let build_version = env!("SHIMMY_BUILD_VERSION"); + + if cargo_version != build_version { + eprintln!("Warning: Version mismatch detected!"); + eprintln!(" Cargo version: {}", cargo_version); + eprintln!(" Build version: {}", build_version); + } + + if cargo_version == "0.1.0" { + eprintln!("ERROR: Invalid default version detected!"); + eprintln!("This binary was built incorrectly. Please download from official releases."); + std::process::exit(1); + } +} +``` + +### 3. Enhanced CLI with Version Validation +Update CLI to include build information: + +```rust +#[derive(Parser, Debug)] +#[command( + name = "shimmy", + version = concat!(env!("CARGO_PKG_VERSION"), " (", env!("SHIMMY_BUILD_VERSION"), ")"), + about = "Shimmy: single-binary GGUF + LoRA server" +)] +pub struct Cli { + // ... existing fields +} +``` + +## Implementation for Backporting + +Since developers are forking at various stages, here's a minimal fix that can be applied to any version: + +### Minimal Fix (backport-friendly) +1. Add version check in main(): +```rust +fn main() { + // Version safety check - prevents 0.1.0 releases + let version = env!("CARGO_PKG_VERSION"); + if version == "0.1.0" { + eprintln!("ERROR: This binary has incorrect version information."); + eprintln!("Please rebuild from clean source or download official release."); + std::process::exit(1); + } + + // ... rest of main +} +``` + +2. Ensure Cargo.toml has correct version before building +3. Add regression test to catch this in CI + +## For Release Process +1. Always build from tagged commits +2. Verify `cargo --version` output before publishing +3. Include version verification in CI/CD +4. Test binary version output before release + +## Immediate Action +1. **Close Issue #63** with explanation that v1.4.2 was never officially released +2. **Recommend users download from official releases** (v1.4.1 or latest v1.5.5) +3. **Add build verification** to prevent future occurrences +4. **Create proper v1.4.2 tag** if needed for compatibility + +## For Forkers +If you're forking shimmy, ensure: +1. Update version in Cargo.toml for your fork +2. Build from clean Git state +3. Test `./shimmy -V` before distributing +4. Consider adding the version verification code above \ No newline at end of file diff --git a/build.rs b/build.rs index 4108330..e4c7034 100644 --- a/build.rs +++ b/build.rs @@ -2,7 +2,60 @@ use std::env; use std::path::PathBuf; +/// Validates version consistency to prevent Issue #63 version mismatch problems +fn validate_version() { + // Get version from Cargo.toml + let version = env!("CARGO_PKG_VERSION"); + + // Validate version is not the default placeholder + if version == "0.1.0" { + panic!( + "ERROR: Version is set to default 0.1.0\n\ + This suggests the package was not properly configured.\n\ + Please ensure Cargo.toml has the correct version number.\n\ + This prevents the version mismatch issue reported in Issue #63." + ); + } + + // Validate version is not empty + if version.is_empty() { + panic!("ERROR: CARGO_PKG_VERSION is empty. Check your build environment."); + } + + // Validate semantic versioning format + let parts: Vec<&str> = version.split('.').collect(); + if parts.len() < 3 { + panic!( + "ERROR: Version '{}' does not follow semantic versioning (major.minor.patch)\n\ + Please use a valid version format like '1.4.2'", + version + ); + } + + // Validate each version component is numeric + for (i, part) in parts.iter().take(3).enumerate() { + if part.parse::().is_err() { + panic!( + "ERROR: Version component '{}' at position {} is not a valid number\n\ + Version: {}", + part, i, version + ); + } + } + + // Set build-time version for verification + println!("cargo:rustc-env=SHIMMY_BUILD_VERSION={}", version); + + // Rebuild if version-related files change + println!("cargo:rerun-if-changed=Cargo.toml"); + + println!("cargo:warning=Building shimmy version {}", version); +} + fn main() { + // Version validation - prevents Issue #63 version mismatch problems + validate_version(); + println!("cargo:rerun-if-changed=libs/"); // Check if we should use pre-built libraries diff --git a/src/main.rs b/src/main.rs index 313dd4a..e467abf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,8 +40,48 @@ impl AppState { } } +/// Runtime version validation - prevents Issue #63 broken binary distribution +fn validate_runtime_version() { + let version = env!("CARGO_PKG_VERSION"); + + // Check for the specific issue reported in #63 + if version == "0.1.0" { + eprintln!(); + eprintln!("❌ ERROR: Invalid shimmy version detected!"); + eprintln!(); + eprintln!("This binary reports version 0.1.0, which indicates it was built incorrectly."); + eprintln!("This is the exact issue reported in GitHub Issue #63."); + eprintln!(); + eprintln!("🔧 Solutions:"); + eprintln!(" • Download the official release from: https://github.com/Michael-A-Kuykendall/shimmy/releases"); + eprintln!(" • If building from source, ensure you're building from a proper Git tag"); + eprintln!(" • If forking, update the version in Cargo.toml before building"); + eprintln!(); + eprintln!("Current version: {}", version); + eprintln!("Expected version: 1.4.1+ (not 0.1.0)"); + eprintln!(); + std::process::exit(1); + } + + // Additional validation for empty or malformed versions + if version.is_empty() { + eprintln!("ERROR: Empty version detected. This binary was built incorrectly."); + std::process::exit(1); + } + + // Validate basic semver format + let parts: Vec<&str> = version.split('.').collect(); + if parts.len() < 2 || parts.iter().take(2).any(|p| p.parse::().is_err()) { + eprintln!("ERROR: Invalid version format '{}'. Expected semantic versioning.", version); + std::process::exit(1); + } +} + #[tokio::main] async fn main() -> anyhow::Result<()> { + // Version validation - prevents Issue #63 distribution of broken binaries + validate_runtime_version(); + tracing_subscriber::fmt() .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) .init();