heroforge-0.2.0 has been yanked.
heroforge

Overview
heroforge provides a complete API for interacting with Heroforge repositories programmatically, without requiring the Heroforge CLI to be installed. It supports both reading from existing repositories and creating new ones from scratch.
Features
Read Operations
- Open and read existing Heroforge 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
Filesystem Operations
- Copy, move, rename files and directories
- Delete files and directories
- Change permissions (chmod)
- Create symbolic links
- Advanced find with ignore patterns
Synchronization
- QUIC sync - Modern UDP-based protocol with TLS 1.3 (requires
sync-quic feature)
Installation
Add heroforge to your Cargo.toml:
[dependencies]
heroforge = "0.1"
Optional Features
Enable QUIC sync for remote repository synchronization:
[dependencies]
heroforge = { version = "0.1", features = ["sync-quic"] }
Quick Start
Reading from an Existing Repository
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::open("project.heroforge")?;
let tip = repo.history().trunk_tip()?;
println!("Latest: {} by {}", tip.hash, tip.user);
println!("Comment: {}", tip.comment);
let files = repo.files().on_trunk().list()?;
for file in &files {
println!(" {}", file.name);
}
let content = repo.files().on_trunk().read("README.md")?;
println!("README:\n{}", String::from_utf8_lossy(&content));
Ok(())
}
Creating a New Repository
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::init("new_project.heroforge")?;
let init_hash = repo.commit_builder()
.message("initial empty check-in")
.author("admin")
.initial()
.execute()?;
let commit_hash = repo.commit_builder()
.message("Initial project structure")
.author("developer")
.parent(&init_hash)
.file("README.md", b"# My Project\n")
.file("src/main.rs", b"fn main() { println!(\"Hello!\"); }\n")
.execute()?;
repo.tags()
.create("v1.0.0")
.at_commit(&commit_hash)
.author("developer")
.execute()?;
repo.branches()
.create("feature-x")
.from_commit(&commit_hash)
.author("developer")
.execute()?;
Ok(())
}
Finding Files with Glob Patterns
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::open("project.heroforge")?;
let rust_files = repo.files().on_trunk().find("**/*.rs")?;
for file in rust_files {
println!("Found: {}", file.name);
}
let src_files = repo.files().on_branch("feature-x").find("src/**/*")?;
let tagged_files = repo.files().at_tag("v1.0.0").find("*.md")?;
Ok(())
}
Browsing History
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::open("project.heroforge")?;
let history = repo.history().recent(10)?;
for checkin in history {
println!("{} | {} | {}",
&checkin.hash[..12],
checkin.user,
checkin.comment
);
}
let branches = repo.branches().list()?;
for branch in branches {
println!("Branch: {}", branch);
}
let tags = repo.tags().list()?;
for tag in tags {
println!("Tag: {}", tag);
}
let feature_tip = repo.history().branch_tip("feature-x")?;
println!("Feature branch tip: {}", feature_tip.hash);
Ok(())
}
User Management
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::init("project.heroforge")?;
repo.users()
.create("developer")
.password("secret123")
.capabilities("ei") .execute()?;
let users = repo.users().list()?;
for (login, caps) in users {
println!("User: {} ({})", login, caps);
}
if let Some(caps) = repo.users().get_capabilities("developer")? {
println!("Developer capabilities: {}", caps);
}
Ok(())
}
QUIC Synchronization
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::open("project.heroforge")?;
repo.sync()
.url("quic://heroforge.example.com:4443/repo")
.execute()?;
Ok(())
}
Filesystem Operations
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::open_rw("project.heroforge")?;
let hash = repo.fs().modify()
.message("Reorganize project")
.author("developer")
.copy_file("README.md", "docs/README.md")
.move_dir("scripts", "tools")
.delete_file("old_config.txt")
.make_executable("tools/build.sh")
.symlink("build", "tools/build.sh")
.execute()?;
let files = repo.fs().find()
.pattern("**/*.rs")
.ignore("target/**")
.ignore_hidden()
.max_depth(3)
.paths()?;
println!("Exists: {}", repo.fs().exists("README.md")?);
println!("Is dir: {}", repo.fs().is_dir("src")?);
println!("Total size: {} bytes", repo.fs().du("**/*.rs")?);
Ok(())
}
Builder API Overview
The library uses a fluent builder pattern for all operations:
| Builder |
Entry Point |
Purpose |
FilesBuilder |
repo.files() |
Read files, list directories, find with glob patterns |
CommitBuilder |
repo.commit_builder() |
Create new check-ins with files |
BranchesBuilder |
repo.branches() |
List and create branches |
TagsBuilder |
repo.tags() |
List, create, and resolve tags |
HistoryBuilder |
repo.history() |
Browse commits and history |
UsersBuilder |
repo.users() |
Manage repository users |
SyncBuilder |
repo.sync() |
Synchronize with remote repositories (QUIC) |
FsOpsBuilder |
repo.fs() |
Filesystem operations (copy, move, delete, chmod, find, symlinks) |
Using heroforge in Your Project
As a Library Dependency
- Add to your
Cargo.toml:
[dependencies]
heroforge = "0.1"
- Import and use:
use heroforge::{Repository, Result, FossilError};
fn main() -> Result<()> {
let repo = Repository::open("my-repo.heroforge")?;
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.heroforge>", args[0]);
std::process::exit(1);
}
match Repository::open(&args[1]) {
Ok(repo) => {
match repo.history().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 Heroforge CLI:
- Use
heroforge ui to browse repositories created by this library
heroforge can read repositories created by the Heroforge CLI
- Sync with remote Heroforge servers works seamlessly
Feature Flags
| Feature |
Description |
Dependencies |
sync-quic |
QUIC protocol sync |
quinn, rustls, tokio |
Examples
The repository includes many examples demonstrating various features:
cargo run --example read_repo
cargo run --example find_and_read
cargo run --example branch_tag_test
cargo run --example comprehensive_test
cargo run --example fs_operations
cargo run --example fs_find
cargo run --example quic_incremental_sync_test --features sync-quic
Documentation
Full API documentation is available at docs.rs/heroforge.
Generate local documentation with:
cargo doc --open --all-features
Architecture
A Heroforge 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
Many thanks to
- The Fossil SCM project for creating and maintaining Fossil on which this is based.