use heroforge_core::{Permissions, Repository, Result};
use std::fs;
fn main() -> Result<()> {
let tmp_dir = std::env::temp_dir().join("heroforge_fs_example");
let _ = fs::remove_dir_all(&tmp_dir);
fs::create_dir_all(&tmp_dir)?;
let repo_path = tmp_dir.join("project.forge");
println!("=== Filesystem Operations Example ===\n");
let repo = Repository::init(&repo_path)?;
println!("Created repository: {}", repo_path.display());
let init_hash = repo
.commit_builder()
.message("Initial structure")
.author("developer")
.initial()
.file("README.md", b"# My Project\n\nA sample project.\n")
.file(
"src/main.rs",
b"fn main() {\n println!(\"Hello!\");\n}\n",
)
.file("src/lib.rs", b"pub mod utils;\npub mod config;\n")
.file("src/utils.rs", b"pub fn helper() {}\n")
.file("src/config.rs", b"pub const VERSION: &str = \"1.0\";\n")
.file("tests/test_main.rs", b"#[test]\nfn it_works() {}\n")
.file("docs/guide.md", b"# User Guide\n")
.file("docs/api.md", b"# API Reference\n")
.file(".gitignore", b"target/\n*.log\n")
.file("scripts/build.sh", b"#!/bin/bash\ncargo build\n")
.file("scripts/test.sh", b"#!/bin/bash\ncargo test\n")
.execute()?;
println!("Initial commit: {}\n", &init_hash[..16]);
println!("=== Files before operations ===");
let files = repo.files().on_trunk().list()?;
for f in &files {
println!(" {}", f.name);
}
println!();
println!("=== Copy Operations ===");
let hash = repo
.fs()
.modify()
.message("Copy README to docs")
.author("developer")
.copy_file("README.md", "docs/README.md")
.execute()?;
println!("Copied README.md -> docs/README.md ({})", &hash[..16]);
let hash = repo
.fs()
.modify()
.message("Backup src directory")
.author("developer")
.copy_dir("src", "src_backup")
.execute()?;
println!("Copied src/ -> src_backup/ ({})", &hash[..16]);
let backup_files = repo.files().at_commit(&hash).find("src_backup/**")?;
println!(" Files in src_backup/:");
for f in &backup_files {
println!(" {}", f.name);
}
println!();
println!("=== Move/Rename Operations ===");
let hash = repo
.fs()
.modify()
.message("Rename utils.rs to helpers.rs")
.author("developer")
.rename("src/utils.rs", "src/helpers.rs")
.execute()?;
println!("Renamed src/utils.rs -> src/helpers.rs ({})", &hash[..16]);
let hash = repo
.fs()
.modify()
.message("Move scripts to tools directory")
.author("developer")
.move_dir("scripts", "tools")
.execute()?;
println!("Moved scripts/ -> tools/ ({})", &hash[..16]);
let tools_files = repo.files().at_commit(&hash).find("tools/**")?;
println!(" Files in tools/:");
for f in &tools_files {
println!(" {}", f.name);
}
println!();
println!("=== Delete Operations ===");
let hash = repo
.fs()
.modify()
.message("Remove backup directory")
.author("developer")
.delete_dir("src_backup")
.execute()?;
println!("Deleted src_backup/ ({})", &hash[..16]);
let hash = repo
.fs()
.modify()
.message("Remove all markdown in docs except guide")
.author("developer")
.delete_file("docs/api.md")
.execute()?;
println!("Deleted docs/api.md ({})", &hash[..16]);
let hash = repo
.fs()
.modify()
.message("Try to delete non-existent file")
.author("developer")
.delete_file("does/not/exist.txt")
.execute()?;
println!("Attempted delete of non-existent file ({})\n", &hash[..16]);
println!("=== Chmod Operations ===");
let hash = repo
.fs()
.modify()
.message("Make build script executable")
.author("developer")
.make_executable("tools/build.sh")
.make_executable("tools/test.sh")
.execute()?;
println!("Made tools/*.sh executable ({})", &hash[..16]);
let hash = repo
.fs()
.modify()
.message("Set config as read-only")
.author("developer")
.chmod("src/config.rs", 0o444)
.execute()?;
println!("Set src/config.rs to 444 (read-only) ({})", &hash[..16]);
let perms = Permissions::from_octal(0o640);
println!(
" Permissions 640 = {} (octal: {:o})",
perms.to_string_repr(),
perms.to_octal()
);
println!();
println!("=== Symlink Operations ===");
let hash = repo
.fs()
.modify()
.message("Create symlinks")
.author("developer")
.symlink("GUIDE.md", "docs/guide.md")
.symlink("build", "tools/build.sh")
.execute()?;
println!("Created symlinks ({})", &hash[..16]);
let files = repo.files().at_commit(&hash).list()?;
println!(" Symlinks in repository:");
for f in &files {
if let Ok(content) = repo.files().at_commit(&hash).read(&f.name) {
if let Ok(text) = String::from_utf8(content) {
if text.starts_with("link ") {
let target = text[5..].trim();
println!(" {} -> {}", f.name, target);
}
}
}
}
println!();
println!("=== Combined Operations (atomic) ===");
let hash = repo
.fs()
.modify()
.message("Reorganize project structure")
.author("developer")
.copy_file("README.md", "README.bak")
.write_str("README.md", "# Updated Project\n\nNew content!\n")
.move_file("docs/guide.md", "docs/manual.md")
.touch("docs/.keep")
.delete_file(".gitignore")
.execute()?;
println!(
"Performed multiple operations atomically ({})\n",
&hash[..16]
);
println!("=== Preview Operations ===");
let preview = repo
.fs()
.modify()
.message("Preview these changes")
.author("developer")
.copy_file("README.md", "README2.md")
.delete_dir("tools")
.chmod("src/main.rs", 0o755)
.preview()?;
println!("Preview of pending operations:");
println!(" Base commit: {}", &preview.base_commit[..16]);
println!(" Base file count: {}", preview.base_file_count);
println!(" Operations:");
for desc in preview.describe() {
println!(" {}", desc);
}
println!();
println!("=== Final Repository State (at latest commit) ===");
let files = repo.files().at_commit(&hash).list()?;
for f in &files {
println!(" {}", f.name);
}
println!();
println!("=== Utility Functions ===");
println!(" exists('README.md'): {}", repo.fs().exists("README.md")?);
println!(
" exists('nonexistent.txt'): {}",
repo.fs().exists("nonexistent.txt")?
);
println!(" is_dir('src'): {}", repo.fs().is_dir("src")?);
println!(" is_dir('README.md'): {}", repo.fs().is_dir("README.md")?);
if let Some(stat) = repo.fs().stat("README.md")? {
println!(" stat('README.md'):");
println!(" path: {}", stat.path);
println!(" hash: {}", &stat.hash[..16]);
println!(" size: {:?} bytes", stat.size);
}
let total_size = repo.fs().du("**/*.rs")?;
println!(" Total size of *.rs files: {} bytes", total_size);
let rs_count = repo.fs().count("**/*.rs")?;
println!(" Number of *.rs files: {}", rs_count);
let _ = fs::remove_dir_all(&tmp_dir);
println!("\n=== Example completed successfully! ===");
Ok(())
}