heroforge 0.1.0

Pure Rust client library for reading and writing Fossil SCM repositories
Documentation
heroforge-0.1.0 has been yanked.

heroforge

A pure Rust client library for reading and writing Fossil SCM repositories.

Crates.io Documentation License

Overview

heroforge provides a complete API for interacting with Fossil repositories programmatically, without requiring the Fossil CLI to be installed. It supports both reading from existing repositories and creating new ones from scratch.

Features

Read Operations

  • Open and read existing Fossil repositories
  • Browse repository history and check-ins
  • List and read files at any check-in
  • Find files using glob patterns
  • Navigate directory structures
  • Access branch and tag information

Write Operations

  • Create new repositories from scratch
  • Commit files with full manifest generation
  • Create and manage branches
  • Add tags to check-ins
  • Manage users and permissions

Synchronization (Optional Features)

  • HTTP sync - Standard Fossil sync over HTTP/HTTPS
  • TCP sync - Direct TCP connections with optional LZ4 compression
  • Encrypted sync - ChaCha20-Poly1305 encryption for TCP
  • QUIC sync - Modern UDP-based protocol with TLS 1.3

Installation

Add heroforge to your Cargo.toml:

[dependencies]
heroforge = "0.1"

Optional Features

Enable additional sync protocols as needed:

[dependencies]
# HTTP sync support
heroforge = { version = "0.1", features = ["sync-http"] }

# TCP sync with compression and encryption
heroforge = { version = "0.1", features = ["sync-tcp-full"] }

# QUIC sync (modern, fast)
heroforge = { version = "0.1", features = ["sync-quic"] }

# All features
heroforge = { version = "0.1", features = ["sync-http", "sync-tcp-full", "sync-quic"] }

Quick Start

Reading from an Existing Repository

use heroforge::Repository;

fn main() -> heroforge::Result<()> {
    // Open a Fossil repository
    let repo = Repository::open("project.fossil")?;

    // Get the latest check-in on trunk
    let tip = repo.trunk_tip()?;
    println!("Latest: {} by {}", tip.hash, tip.user);
    println!("Comment: {}", tip.comment);

    // List all files in the latest check-in
    let files = repo.list_files(&tip.hash)?;
    for file in &files {
        println!("  {}", file.name);
    }

    // Read a specific file
    let content = repo.read_file(&tip.hash, "README.md")?;
    println!("README:\n{}", String::from_utf8_lossy(&content));

    Ok(())
}

Creating a New Repository

use heroforge::Repository;

fn main() -> heroforge::Result<()> {
    // Create a new repository
    let repo = Repository::init("new_project.fossil")?;

    // Create initial check-in
    let init_hash = repo.create_initial_checkin("admin")?;

    // Add some files
    let files: Vec<(&str, &[u8])> = vec![
        ("README.md", b"# My Project\n"),
        ("src/main.rs", b"fn main() { println!(\"Hello!\"); }\n"),
    ];
    
    let commit_hash = repo.commit(
        &files,
        "Initial project structure",
        "developer",
        Some(&init_hash),
        None, // stays on trunk
    )?;

    // Tag the release
    repo.add_tag("v1.0.0", &commit_hash, "developer")?;

    // Create a feature branch
    let branch_hash = repo.create_branch("feature-x", &commit_hash, "developer")?;

    Ok(())
}

Finding Files with Glob Patterns

use heroforge::Repository;

fn main() -> heroforge::Result<()> {
    let repo = Repository::open("project.fossil")?;
    let tip = repo.trunk_tip()?;

    // Find all Rust files
    let rust_files = repo.find_files(&tip.hash, "**/*.rs")?;
    for file in rust_files {
        println!("Found: {}", file.name);
    }

    // Find files in a specific directory
    let src_files = repo.find_files(&tip.hash, "src/**/*")?;
    
    Ok(())
}

Browsing History

use heroforge::Repository;

fn main() -> heroforge::Result<()> {
    let repo = Repository::open("project.fossil")?;

    // Get recent check-ins
    let history = repo.get_checkins(10)?;
    for checkin in history {
        println!("{} | {} | {}", 
            &checkin.hash[..12], 
            checkin.user, 
            checkin.comment
        );
    }

    // List all branches
    let branches = repo.list_branches()?;
    for branch in branches {
        println!("Branch: {}", branch);
    }

    // List all tags
    let tags = repo.list_tags()?;
    for tag in tags {
        println!("Tag: {}", tag);
    }

    Ok(())
}

HTTP Synchronization

use heroforge::Repository;
use heroforge::sync::HttpSyncClient;

fn main() -> heroforge::Result<()> {
    let repo = Repository::open("project.fossil")?;
    
    // Create sync client
    let client = HttpSyncClient::new(
        "https://fossil.example.com/repo",
        Some("username"),
        Some("password"),
    )?;
    
    // Perform sync
    client.sync(&repo)?;
    
    Ok(())
}

Using heroforge in Your Project

As a Library Dependency

  1. Add to your Cargo.toml:
[dependencies]
heroforge = "0.1"
  1. Import and use:
use heroforge::{Repository, Result, FossilError};

fn main() -> Result<()> {
    let repo = Repository::open("my-repo.fossil")?;
    // ... your code
    Ok(())
}

Building a CLI Tool

use heroforge::Repository;
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    
    if args.len() < 2 {
        eprintln!("Usage: {} <repository.fossil>", args[0]);
        std::process::exit(1);
    }
    
    match Repository::open(&args[1]) {
        Ok(repo) => {
            match repo.trunk_tip() {
                Ok(tip) => {
                    println!("Repository: {}", args[1]);
                    println!("Latest commit: {}", tip.hash);
                    println!("Author: {}", tip.user);
                    println!("Message: {}", tip.comment);
                }
                Err(e) => eprintln!("Error reading tip: {}", e),
            }
        }
        Err(e) => eprintln!("Error opening repository: {}", e),
    }
}

Repository Compatibility

Repositories created with heroforge are fully compatible with the Fossil CLI:

  • Use fossil ui to browse repositories created by this library
  • heroforge can read repositories created by the Fossil CLI
  • Sync with remote Fossil servers works seamlessly

Feature Flags

Feature Description Dependencies
sync-http HTTP/HTTPS sync support ureq
sync-tcp Basic TCP sync -
sync-tcp-compression TCP with LZ4 compression lz4_flex
sync-tcp-encryption TCP with ChaCha20-Poly1305 chacha20poly1305, rand
sync-tcp-full All TCP features compression + encryption
sync-quic QUIC protocol sync quinn, rustls, tokio

Examples

The repository includes many examples demonstrating various features:

# Basic repository reading
cargo run --example read_repo

# Find files with glob patterns
cargo run --example find_and_read

# Full demo with repository creation
cargo run --example full_demo

# HTTP sync (requires sync-http feature)
cargo run --example sync_demo --features sync-http

# TCP sync benchmark (requires sync-tcp-full feature)
cargo run --example tcp_sync_benchmark --features sync-tcp-full

# QUIC sync (requires sync-quic feature)
cargo run --example quic_sync_benchmark --features sync-quic

Documentation

Full API documentation is available at docs.rs/heroforge.

Generate local documentation with:

cargo doc --open --all-features

Architecture

A Fossil repository is a SQLite database containing:

  • Blobs: Compressed file contents and manifests (zlib)
  • Manifests: Check-in metadata with file lists, timestamps, comments
  • Tags: Branch names, version tags, and other labels
  • Events: Timeline of repository activity
  • Delta encoding: Efficient storage of similar content

License

Licensed under either of:

at your option.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.