doctree/doctreecmd/src/main.rs
2025-05-13 09:19:45 +03:00

420 lines
18 KiB
Rust

use clap::{App, Arg, SubCommand};
use doctree::{DocTree, RedisStorage, Result, from_directory};
use std::path::Path;
fn main() -> Result<()> {
let matches = App::new("doctree")
.version("0.1.0")
.author("Your Name")
.about("A tool to manage document collections")
.arg(
Arg::with_name("debug")
.long("debug")
.help("Enable debug logging")
.takes_value(false)
)
.subcommand(
SubCommand::with_name("scan")
.about("Scan a directory for .collection files and create collections")
.arg(Arg::with_name("path").required(true).help("Path to the directory"))
.arg(Arg::with_name("doctree").long("doctree").takes_value(true).help("Name of the doctree (default: 'default')")),
)
.subcommand(
SubCommand::with_name("list")
.about("List collections")
.arg(Arg::with_name("doctree").long("doctree").takes_value(true).help("Name of the doctree (default: 'default')")),
)
.subcommand(
SubCommand::with_name("info")
.about("Show detailed information about collections")
.arg(Arg::with_name("collection").help("Name of the collection (optional)"))
.arg(Arg::with_name("doctree").long("doctree").takes_value(true).help("Name of the doctree (default: 'default')")),
)
.subcommand(
SubCommand::with_name("get")
.about("Get page content")
.arg(Arg::with_name("collection")
.short("c".chars().next().unwrap())
.long("collection")
.takes_value(true)
.help("Name of the collection (optional)"))
.arg(Arg::with_name("page")
.short("p".chars().next().unwrap())
.long("page")
.required(true)
.takes_value(true)
.help("Name of the page"))
.arg(Arg::with_name("format")
.short("f".chars().next().unwrap())
.long("format")
.takes_value(true)
.help("Output format (html or markdown, default: markdown)"))
.arg(Arg::with_name("doctree").long("doctree").takes_value(true).help("Name of the doctree (default: 'default')")),
)
.subcommand(
SubCommand::with_name("html")
.about("Get page content as HTML")
.arg(Arg::with_name("collection").required(true).help("Name of the collection"))
.arg(Arg::with_name("page").required(true).help("Name of the page"))
.arg(Arg::with_name("doctree").long("doctree").takes_value(true).help("Name of the doctree (default: 'default')")),
)
.subcommand(
SubCommand::with_name("delete")
.about("Delete a collection from Redis")
.arg(Arg::with_name("collection").required(true).help("Name of the collection"))
.arg(Arg::with_name("doctree").long("doctree").takes_value(true).help("Name of the doctree (default: 'default')")),
)
.subcommand(
SubCommand::with_name("reset")
.about("Delete all collections from Redis")
.arg(Arg::with_name("doctree").long("doctree").takes_value(true).help("Name of the doctree (default: 'default')")),
)
.subcommand(
SubCommand::with_name("export_to_ipfs")
.about("Export a collection to IPFS")
.arg(Arg::with_name("collection").required(true).help("Name of the collection"))
.arg(Arg::with_name("output").required(true).help("Output directory for IPFS export"))
.arg(Arg::with_name("doctree").long("doctree").takes_value(true).help("Name of the doctree (default: 'default')")),
)
.get_matches();
// Check if debug mode is enabled
let debug_mode = matches.is_present("debug");
// Handle subcommands
if let Some(matches) = matches.subcommand_matches("scan") {
let path = matches.value_of("path").unwrap();
if debug_mode {
println!("DEBUG: Scanning path: {}", path);
}
let doctree_name = matches.value_of("doctree").unwrap_or("default");
println!("Recursively scanning for collections in: {}", path);
println!("Using doctree name: {}", doctree_name);
// Use the from_directory function to create a DocTree with all collections
let doctree = from_directory(Path::new(path), Some(doctree_name))?;
// Print the discovered collections
let collections = doctree.list_collections();
if collections.is_empty() {
println!("No collections found");
} else {
println!("Discovered collections:");
for collection in collections {
println!("- {}", collection);
}
}
} else if let Some(matches) = matches.subcommand_matches("list") {
let doctree_name = matches.value_of("doctree").unwrap_or("default");
if debug_mode {
println!("DEBUG: Listing collections for doctree: {}", doctree_name);
}
// Create a storage with the specified doctree name
let storage = RedisStorage::new("redis://localhost:6379")?;
storage.set_doctree_name(doctree_name);
storage.set_debug(debug_mode);
if debug_mode {
println!("DEBUG: Connected to Redis storage");
}
// Get collections directly from Redis to avoid debug output from DocTree
let collections = storage.list_all_collections()?;
if collections.is_empty() {
println!("No collections found in doctree '{}'", doctree_name);
} else {
println!("Collections in doctree '{}':", doctree_name);
for collection in collections {
println!("- {}", collection);
}
}
} else if let Some(matches) = matches.subcommand_matches("get") {
let collection = matches.value_of("collection");
let page = matches.value_of("page").unwrap();
let format = matches.value_of("format").unwrap_or("markdown");
let doctree_name = matches.value_of("doctree").unwrap_or("default");
if debug_mode {
println!("DEBUG: Getting page '{}' from collection '{}' in doctree '{}' with format '{}'",
page, collection.unwrap_or("(default)"), doctree_name, format);
}
// Create a storage with the specified doctree name
let storage = RedisStorage::new("redis://localhost:6379")?;
storage.set_doctree_name(doctree_name);
storage.set_debug(debug_mode);
if debug_mode {
println!("DEBUG: Connected to Redis storage");
}
// Create a DocTree with the specified doctree name
let mut doctree = DocTree::builder()
.with_storage(storage)
.with_doctree_name(doctree_name)
.build()?;
// Load collections from Redis
doctree.load_collections_from_redis()?;
if format.to_lowercase() == "html" {
let html = doctree.page_get_html(collection, page)?;
println!("{}", html);
} else {
let content = doctree.page_get(collection, page)?;
println!("{}", content);
}
} else if let Some(matches) = matches.subcommand_matches("html") {
let collection = matches.value_of("collection").unwrap();
let page = matches.value_of("page").unwrap();
let doctree_name = matches.value_of("doctree").unwrap_or("default");
if debug_mode {
println!("DEBUG: Getting HTML for page '{}' from collection '{}' in doctree '{}'",
page, collection, doctree_name);
}
// Create a storage with the specified doctree name
let storage = RedisStorage::new("redis://localhost:6379")?;
storage.set_doctree_name(doctree_name);
storage.set_debug(debug_mode);
if debug_mode {
println!("DEBUG: Connected to Redis storage");
}
// Create a DocTree with the specified doctree name
let mut doctree = DocTree::builder()
.with_storage(storage)
.with_doctree_name(doctree_name)
.build()?;
// Load collections from Redis
doctree.load_collections_from_redis()?;
let html = doctree.page_get_html(Some(collection), page)?;
println!("{}", html);
} else if let Some(matches) = matches.subcommand_matches("info") {
let doctree_name = matches.value_of("doctree").unwrap_or("default");
let collection_name = matches.value_of("collection");
if debug_mode {
if let Some(name) = collection_name {
println!("DEBUG: Getting info for collection '{}' in doctree '{}'", name, doctree_name);
} else {
println!("DEBUG: Getting info for all collections in doctree '{}'", doctree_name);
}
}
// Create a storage with the specified doctree name
let storage = RedisStorage::new("redis://localhost:6379")?;
storage.set_doctree_name(doctree_name);
storage.set_debug(debug_mode);
if debug_mode {
println!("DEBUG: Connected to Redis storage");
}
// Create a DocTree with the specified doctree name
let mut doctree = DocTree::builder()
.with_storage(storage)
.with_doctree_name(doctree_name)
.build()?;
// Load collections from Redis
doctree.load_collections_from_redis()?;
let collection_name = matches.value_of("collection");
if let Some(name) = collection_name {
// Show info for a specific collection
match doctree.get_collection(name) {
Ok(collection) => {
println!("Collection Information for '{}':", name);
println!(" Path: {:?}", collection.path);
println!(" Redis Key: {}:collections:{}", doctree_name, collection.name);
// List documents
match collection.page_list() {
Ok(pages) => {
println!(" Documents ({}):", pages.len());
for page in pages {
match collection.page_get_path(&page) {
Ok(path) => {
println!(" - {} => Redis: {}:collections:{} / {}", path, doctree_name, collection.name, page);
},
Err(_) => {
println!(" - {}", page);
}
}
}
},
Err(e) => println!(" Error listing documents: {}", e),
}
// List files
match collection.file_list() {
Ok(files) => {
// Filter images
let images: Vec<String> = files.iter()
.filter(|f|
f.ends_with(".png") || f.ends_with(".jpg") ||
f.ends_with(".jpeg") || f.ends_with(".gif") ||
f.ends_with(".svg"))
.cloned()
.collect();
println!(" Images ({}):", images.len());
for image in images {
println!(" - {} => Redis: {}:collections:{} / {}", image, doctree_name, collection.name, image);
}
// Filter other files
let other_files: Vec<String> = files.iter()
.filter(|f|
!f.ends_with(".png") && !f.ends_with(".jpg") &&
!f.ends_with(".jpeg") && !f.ends_with(".gif") &&
!f.ends_with(".svg"))
.cloned()
.collect();
println!(" Other Files ({}):", other_files.len());
for file in other_files {
println!(" - {} => Redis: {}:collections:{} / {}", file, doctree_name, collection.name, file);
}
},
Err(e) => println!(" Error listing files: {}", e),
}
},
Err(e) => println!("Error: {}", e),
}
} else {
// Show info for all collections
let collections = doctree.list_collections();
if collections.is_empty() {
println!("No collections found");
} else {
println!("Collections in doctree '{}':", doctree_name);
for name in collections {
if let Ok(collection) = doctree.get_collection(&name) {
println!("- {} (Redis Key: {}:collections:{})", name, doctree_name, collection.name);
println!(" Path: {:?}", collection.path);
// Count documents and images
if let Ok(pages) = collection.page_list() {
println!(" Documents: {}", pages.len());
}
if let Ok(files) = collection.file_list() {
let image_count = files.iter()
.filter(|f|
f.ends_with(".png") || f.ends_with(".jpg") ||
f.ends_with(".jpeg") || f.ends_with(".gif") ||
f.ends_with(".svg"))
.count();
println!(" Images: {}", image_count);
println!(" Other Files: {}", files.len() - image_count);
}
}
}
}
}
} else if let Some(matches) = matches.subcommand_matches("delete") {
let collection = matches.value_of("collection").unwrap();
let doctree_name = matches.value_of("doctree").unwrap_or("default");
if debug_mode {
println!("DEBUG: Deleting collection '{}' from doctree '{}'", collection, doctree_name);
}
// Create a storage with the specified doctree name
let storage = RedisStorage::new("redis://localhost:6379")?;
storage.set_doctree_name(doctree_name);
storage.set_debug(debug_mode);
if debug_mode {
println!("DEBUG: Connected to Redis storage");
}
// Create a DocTree with the specified doctree name
let mut doctree = DocTree::builder()
.with_storage(storage)
.with_doctree_name(doctree_name)
.build()?;
println!("Deleting collection '{}' from Redis in doctree '{}'...", collection, doctree_name);
doctree.delete_collection(collection)?;
println!("Collection '{}' deleted successfully", collection);
} else if let Some(matches) = matches.subcommand_matches("export_to_ipfs") {
let collection_name = matches.value_of("collection").unwrap();
let output_path = matches.value_of("output").unwrap();
let doctree_name = matches.value_of("doctree").unwrap_or("default");
if debug_mode {
println!("DEBUG: Exporting collection '{}' from doctree '{}' to IPFS output path '{}'",
collection_name, doctree_name, output_path);
}
// Create a storage with the specified doctree name
let storage = RedisStorage::new("redis://localhost:6379")?;
storage.set_doctree_name(doctree_name);
storage.set_debug(debug_mode);
if debug_mode {
println!("DEBUG: Connected to Redis storage");
}
// Create a DocTree with the specified doctree name
let mut doctree = DocTree::builder()
.with_storage(storage)
.with_doctree_name(doctree_name)
.build()?;
// Load collections from Redis
doctree.load_collections_from_redis()?;
// Get the collection
let collection = doctree.get_collection(collection_name)?;
// Call the synchronous export_collection_to_ipfs_sync function from the doctree crate
let output_path = Path::new(output_path);
doctree.export_collection_to_ipfs(collection_name, output_path)?;
println!("Successfully exported collection '{}' to IPFS and generated metadata CSV at {:?}.", collection_name, output_path.join(format!("{}.csv", collection_name)));
} else if let Some(matches) = matches.subcommand_matches("reset") {
let doctree_name = matches.value_of("doctree").unwrap_or("default");
if debug_mode {
println!("DEBUG: Resetting all collections in doctree '{}'", doctree_name);
}
// Create a storage with the specified doctree name
let storage = RedisStorage::new("redis://localhost:6379")?;
storage.set_doctree_name(doctree_name);
storage.set_debug(debug_mode);
if debug_mode {
println!("DEBUG: Connected to Redis storage");
}
// Create a DocTree with the specified doctree name
let mut doctree = DocTree::builder()
.with_storage(storage)
.with_doctree_name(doctree_name)
.build()?;
println!("Deleting all collections from Redis in doctree '{}'...", doctree_name);
doctree.delete_all_collections()?;
println!("All collections deleted successfully");
} else {
println!("No command specified. Use --help for usage information.");
}
Ok(())
}