# heroforge
[](https://crates.io/crates/heroforge)
[](https://docs.rs/heroforge)
[](LICENSE)
## 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`:
```toml
[dependencies]
heroforge = "0.1"
```
### Optional Features
Enable QUIC sync for remote repository synchronization:
```toml
[dependencies]
heroforge = { version = "0.1", features = ["sync-quic"] }
```
## Quick Start
### Reading from an Existing Repository
```rust
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
// Open a Heroforge repository
let repo = Repository::open("project.heroforge")?;
// Get the latest check-in on trunk
let tip = repo.history().trunk_tip()?;
println!("Latest: {} by {}", tip.hash, tip.user);
println!("Comment: {}", tip.comment);
// List all files on trunk
let files = repo.files().on_trunk().list()?;
for file in &files {
println!(" {}", file.name);
}
// Read a specific file from trunk
let content = repo.files().on_trunk().read("README.md")?;
println!("README:\n{}", String::from_utf8_lossy(&content));
Ok(())
}
```
### Creating a New Repository
```rust
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
// Create a new repository
let repo = Repository::init("new_project.heroforge")?;
// Create initial check-in
let init_hash = repo.commit_builder()
.message("initial empty check-in")
.author("admin")
.initial()
.execute()?;
// Add some files in a new commit
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()?;
// Tag the release
repo.tags()
.create("v1.0.0")
.at_commit(&commit_hash)
.author("developer")
.execute()?;
// Create a feature branch
repo.branches()
.create("feature-x")
.from_commit(&commit_hash)
.author("developer")
.execute()?;
Ok(())
}
```
### Finding Files with Glob Patterns
```rust
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::open("project.heroforge")?;
// Find all Rust files on trunk
let rust_files = repo.files().on_trunk().find("**/*.rs")?;
for file in rust_files {
println!("Found: {}", file.name);
}
// Find files in a specific directory on a branch
let src_files = repo.files().on_branch("feature-x").find("src/**/*")?;
// Find files at a specific tag
let tagged_files = repo.files().at_tag("v1.0.0").find("*.md")?;
Ok(())
}
```
### Browsing History
```rust
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::open("project.heroforge")?;
// Get recent check-ins
let history = repo.history().recent(10)?;
for checkin in history {
println!("{} | {} | {}",
&checkin.hash[..12],
checkin.user,
checkin.comment
);
}
// List all branches
let branches = repo.branches().list()?;
for branch in branches {
println!("Branch: {}", branch);
}
// List all tags
let tags = repo.tags().list()?;
for tag in tags {
println!("Tag: {}", tag);
}
// Get the tip of a specific branch
let feature_tip = repo.history().branch_tip("feature-x")?;
println!("Feature branch tip: {}", feature_tip.hash);
Ok(())
}
```
### User Management
```rust
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::init("project.heroforge")?;
// Create a new user
repo.users()
.create("developer")
.password("secret123")
.capabilities("ei") // edit + check-in
.execute()?;
// List all users
let users = repo.users().list()?;
for (login, caps) in users {
println!("User: {} ({})", login, caps);
}
// Get user capabilities
if let Some(caps) = repo.users().get_capabilities("developer")? {
println!("Developer capabilities: {}", caps);
}
Ok(())
}
```
### QUIC Synchronization
```rust
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::open("project.heroforge")?;
// Sync with a remote repository over QUIC
repo.sync()
.url("quic://heroforge.example.com:4443/repo")
.execute()?;
Ok(())
}
```
### Filesystem Operations
```rust
use heroforge::Repository;
fn main() -> heroforge::Result<()> {
let repo = Repository::open_rw("project.heroforge")?;
// Copy, move, delete files atomically
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()?;
// Advanced find with ignore patterns
let files = repo.fs().find()
.pattern("**/*.rs")
.ignore("target/**")
.ignore_hidden()
.max_depth(3)
.paths()?;
// Utility functions
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:
| `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
1. Add to your `Cargo.toml`:
```toml
[dependencies]
heroforge = "0.1"
```
2. Import and use:
```rust
use heroforge::{Repository, Result, FossilError};
fn main() -> Result<()> {
let repo = Repository::open("my-repo.heroforge")?;
// ... your code
Ok(())
}
```
### Building a CLI Tool
```rust
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
| `sync-quic` | QUIC protocol sync | `quinn`, `rustls`, `tokio` |
## Examples
The repository includes many examples demonstrating various features:
```bash
# Basic repository reading
cargo run --example read_repo
# Find files with glob patterns
cargo run --example find_and_read
# Branches and tags demonstration
cargo run --example branch_tag_test
# Comprehensive API demo
cargo run --example comprehensive_test
# Filesystem operations (copy, move, delete, chmod, symlinks)
cargo run --example fs_operations
# Advanced find with ignore patterns
cargo run --example fs_find
# QUIC sync (requires sync-quic feature)
cargo run --example quic_incremental_sync_test --features sync-quic
```
## Documentation
Full API documentation is available at [docs.rs/heroforge](https://docs.rs/heroforge).
Generate local documentation with:
```bash
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.