# How Arnis Detects and Reports Available Software Updates on Startup: Version Checking Explained

> Learn how Arnis detects and reports software updates on startup. Discover the version checking process explained step by step for seamless updates.

- Repository: [Louis Erbkamm/arnis](https://github.com/louis-e/arnis)
- Tags: internals
- Published: 2026-03-20

---

**The Arnis binary performs a synchronous version check on startup by downloading the remote Cargo.toml from GitHub, parsing its version field, and comparing it against the locally compiled version using semantic versioning rules.**

When the **Arnis** terrain generator initializes, it executes a lightweight version checking feature to determine if a newer release is available. This process runs before any heavy computational work begins, ensuring users are immediately notified of updates without impacting the application's core functionality.

## How the Version Checking Feature Works on Startup

### Triggering the Check in main.rs

The version detection sequence begins immediately after the application banner displays. In [`src/main.rs`](https://github.com/louis-e/arnis/blob/main/src/main.rs) at lines 84-91, the main entry point invokes `version_check::check_for_updates()` and gracefully handles any errors that bubble up from the network stack.

```rust
// From src/main.rs
match version_check::check_for_updates() {
    Ok(true) => println!("Update available"),
    Ok(false) => println!("Running latest version"),
    Err(e) => eprintln!("Version check failed: {}", e),
}

```

### Fetching the Remote Cargo.toml

The `check_for_updates()` function in [`src/version_check.rs`](https://github.com/louis-e/arnis/blob/main/src/version_check.rs) creates a blocking `reqwest::Client` at line 14 to perform a synchronous HTTP request. The client retrieves the raw [`Cargo.toml`](https://github.com/louis-e/arnis/blob/main/Cargo.toml) file from the canonical repository URL with a custom User-Agent header identifying the Arnis client.

```rust
// From src/version_check.rs:L16-L20
let client = reqwest::blocking::Client::new();
let response = client
    .get("https://raw.githubusercontent.com/louis-e/arnis/main/Cargo.toml")
    .header("User-Agent", "arnis-version-checker")
    .send()?;

```

### Parsing and Comparing Versions

Once the HTTP response returns successfully, the system extracts the version string through a multi-step validation process. The `extract_version_from_cargo_toml` function scans the downloaded TOML content for lines beginning with `version`, parsing the semantic version string using the `semver` crate.

The local version is determined at compile time using the `env!("CARGO_PKG_VERSION")` macro, ensuring the binary always reports the exact version it was built from without requiring runtime configuration files.

```rust
// From src/version_check.rs:L30-L44
let remote_version = extract_version_from_cargo_toml(&response.text()?)?;
let local_version = semver::Version::parse(env!("CARGO_PKG_VERSION"))?;

if remote_version > local_version {
    println!("A new version is available: {} → {}", 
             local_version, remote_version);
    return Ok(true);
}
Ok(false)

```

### Error Handling and Graceful Degradation

The version checking feature implements comprehensive error handling to ensure network failures never prevent the application from running. The `handle_http_error` function at lines 22-28 catches non-2xx status codes and prints a friendly message before returning `Ok(false)` to indicate no update is available.

Network timeouts and connection errors are captured by `handle_request_error` at lines 48-52, which logs a concise message and treats the situation as if the user is running the latest version. This graceful degradation ensures that users behind firewalls or without internet access can continue using Arnis without interruption.

## Implementation Details in version_check.rs

The [`src/version_check.rs`](https://github.com/louis-e/arnis/blob/main/src/version_check.rs) module encapsulates all update detection logic. Developers can manually trigger version checks or integrate the functionality into custom scripts using the public API.

### Manual Version Check Example

```rust
use arnis::version_check;

fn main() {
    match version_check::check_for_updates() {
        Ok(true) => println!("Update available – see the banner above."),
        Ok(false) => println!("You are already on the latest version."),
        Err(e) => eprintln!("Failed to check for updates: {}", e),
    }
}

```

The function returns `Result<bool, Box<dyn Error>>`, where `true` indicates a newer release exists on GitHub.

### Parsing Remote Versions Directly

For testing or custom implementations, the version extraction logic can be used independently without performing network requests.

```rust
use std::error::Error;
use arnis::version_check::extract_version_from_cargo_toml;

fn main() -> Result<(), Box<dyn Error>> {
    let cargo_toml = std::fs::read_to_string("Cargo.toml")?;
    let remote = extract_version_from_cargo_toml(&cargo_toml)?;
    println!("Remote version: {}", remote);
    Ok(())
}

```

This approach is useful for validating parsing logic against local TOML files before deploying network-dependent code.

## Key Files and Functions

The version checking feature spans three primary locations in the Arnis codebase:

- **[`src/version_check.rs`](https://github.com/louis-e/arnis/blob/main/src/version_check.rs)** – Implements the full update-checking flow including the network request, TOML parsing, semantic version comparison, and error handling. [View source](https://github.com/louis-e/arnis/blob/main/src/version_check.rs)

- **[`src/main.rs`](https://github.com/louis-e/arnis/blob/main/src/main.rs)** – Invokes `check_for_updates()` at program startup (lines 84-91) and displays any errors to the console. [View source](https://github.com/louis-e/arnis/blob/main/src/main.rs)

- **[`Cargo.toml`](https://github.com/louis-e/arnis/blob/main/Cargo.toml)** (repository root) – Contains the canonical version string that the remote check reads to determine if updates are available. [View source](https://github.com/louis-e/arnis/blob/main/Cargo.toml)

## Summary

- **Arnis** detects software updates by comparing the local binary version against the remote [`Cargo.toml`](https://github.com/louis-e/arnis/blob/main/Cargo.toml) hosted on GitHub.
- The check runs synchronously in [`main.rs`](https://github.com/louis-e/arnis/blob/main/main.rs) before heavy operations begin, using a blocking `reqwest` client to fetch `https://raw.githubusercontent.com/louis-e/arnis/main/Cargo.toml`.
- `extract_version_from_cargo_toml` parses the semantic version from the remote TOML, while `env!("CARGO_PKG_VERSION")` provides the compile-time local version.
- The system uses **graceful degradation**: network failures, HTTP errors, or parsing issues result in `Ok(false)`, allowing the application to continue uninterrupted.
- When `remote_version > local_version`, a colored console message notifies users of the available update.

## Frequently Asked Questions

### How does Arnis handle network failures during the version check?

Arnis treats all network failures as non-fatal events. The `handle_request_error` function catches timeouts and connection errors, logs a concise message, and returns `Ok(false)` to indicate no update is available. This ensures users behind corporate firewalls or offline can continue using the terrain generator without interruption.

### Where does Arnis look to find the latest version number?

The application fetches the raw [`Cargo.toml`](https://github.com/louis-e/arnis/blob/main/Cargo.toml) file directly from the GitHub repository at `https://raw.githubusercontent.com/louis-e/arnis/main/Cargo.toml`. It parses the `version` field from this file to determine the latest release, comparing it against the local version compiled into the binary via `env!("CARGO_PKG_VERSION")`.

### Can I disable the automatic version check when starting Arnis?

Currently, the version check is hardcoded in [`src/main.rs`](https://github.com/louis-e/arnis/blob/main/src/main.rs) and runs automatically on every startup. There is no configuration flag to disable it in the current implementation. However, because the check uses graceful degradation and returns immediately on network errors, it adds minimal overhead and never blocks execution for more than a few seconds.

### What happens if the remote Cargo.toml contains an invalid version string?

If `extract_version_from_cargo_toml` cannot find a line starting with `version` or fails to parse the semantic version string, the function returns an error. This error propagates up to the caller in [`main.rs`](https://github.com/louis-e/arnis/blob/main/main.rs), where it is caught and logged. The application treats this as a failed check and continues execution assuming no update is available, preventing malformed remote files from crashing the program.