diff --git a/examples/webtools/.gitignore b/examples/web/.gitignore similarity index 100% rename from examples/webtools/.gitignore rename to examples/web/.gitignore diff --git a/examples/webtools/cfg/docusaurus_example_config.heroscript b/examples/web/cfg/docusaurus_example_config.heroscript similarity index 100% rename from examples/webtools/cfg/docusaurus_example_config.heroscript rename to examples/web/cfg/docusaurus_example_config.heroscript diff --git a/examples/web/doctreeclient_example.vsh b/examples/web/doctreeclient_example.vsh new file mode 100755 index 00000000..c5865ae9 --- /dev/null +++ b/examples/web/doctreeclient_example.vsh @@ -0,0 +1,125 @@ +#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run + +import freeflowuniverse.herolib.web.doctreeclient +import freeflowuniverse.herolib.data.doctree +import os + +println('DocTreeClient Example') +println('=====================') + +// Step 1: First, populate Redis with doctree data +println('\n1. Setting up doctree data in Redis...') + + +tree.scan( + git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/collections' + git_pull: false +)! + +tree.export( + destination: '/tmp/mdexport' + reset: true + exclude_errors: false +)! + +println('Doctree data populated in Redis') + +// Step 2: Create a DocTreeClient instance +println('\n2. Creating DocTreeClient...') +mut client := doctreeclient.new()! +println('DocTreeClient created successfully') + +// Step 3: List all collections +println('\n3. Listing collections:') +collections := client.list_collections()! +println('Found ${collections.len} collections: ${collections}') + +if collections.len == 0 { + println('No collections found. Example cannot continue.') + return +} + +// Step 4: Use the example_docs collection +collection_name := 'example_docs' +println('\n4. Using collection: ${collection_name}') + +// Step 5: List pages in the collection +println('\n5. Listing pages:') +pages := client.list_pages(collection_name)! +println('Found ${pages.len} pages: ${pages}') + +// Step 6: Get content of a page +if pages.len > 0 { + page_name := 'introduction' + println('\n6. Getting content of page: ${page_name}') + + // Check if page exists + exists := client.page_exists(collection_name, page_name) + println('Page exists: ${exists}') + + // Get page path + page_path := client.get_page_path(collection_name, page_name)! + println('Page path: ${page_path}') + + // Get page content + content := client.get_page_content(collection_name, page_name)! + println('Page content:') + println('---') + println(content) + println('---') +} + +// Step 7: List images in the collection +println('\n7. Listing images:') +images := client.list_images(collection_name)! +println('Found ${images.len} images: ${images}') + +// Step 8: Get image path +if images.len > 0 { + image_name := images[0] + println('\n8. Getting path of image: ${image_name}') + + // Check if image exists + exists := client.image_exists(collection_name, image_name) + println('Image exists: ${exists}') + + // Get image path + image_path := client.get_image_path(collection_name, image_name)! + println('Image path: ${image_path}') +} + +// Step 9: List files in the collection +println('\n9. Listing files:') +files := client.list_files(collection_name)! +println('Found ${files.len} files: ${files}') + +// Step 10: Get file path +if files.len > 0 { + file_name := files[0] + println('\n10. Getting path of file: ${file_name}') + + // Check if file exists + exists := client.file_exists(collection_name, file_name) + println('File exists: ${exists}') + + // Get file path + file_path := client.get_file_path(collection_name, file_name)! + println('File path: ${file_path}') +} + +// Step 11: Error handling example +println('\n11. Error handling example:') +println('Trying to access a non-existent page...') + +non_existent_page := 'non_existent_page' +content := client.get_page_content(collection_name, non_existent_page) or { + println('Error caught: ${err}') + 'Error content' +} + +// Step 12: Clean up +println('\n12. Cleaning up...') +os.rmdir_all(example_dir) or { println('Failed to remove example directory: ${err}') } +os.rmdir_all(export_dir) or { println('Failed to remove export directory: ${err}') } + +println('\nExample completed successfully!') diff --git a/examples/webtools/docusaurus_example.vsh b/examples/web/docusaurus_example.vsh similarity index 100% rename from examples/webtools/docusaurus_example.vsh rename to examples/web/docusaurus_example.vsh diff --git a/examples/webtools/docusaurus_example_cli.sh b/examples/web/docusaurus_example_cli.sh similarity index 100% rename from examples/webtools/docusaurus_example_cli.sh rename to examples/web/docusaurus_example_cli.sh diff --git a/examples/webtools/docusaurus_example_complete.vsh b/examples/web/docusaurus_example_complete.vsh similarity index 100% rename from examples/webtools/docusaurus_example_complete.vsh rename to examples/web/docusaurus_example_complete.vsh diff --git a/examples/webtools/markdown_renderer/markdown_parser.vsh b/examples/web/markdown_renderer/markdown_parser.vsh similarity index 100% rename from examples/webtools/markdown_renderer/markdown_parser.vsh rename to examples/web/markdown_renderer/markdown_parser.vsh diff --git a/examples/webtools/markdown_renderer/markdown_render.vsh b/examples/web/markdown_renderer/markdown_render.vsh similarity index 100% rename from examples/webtools/markdown_renderer/markdown_render.vsh rename to examples/web/markdown_renderer/markdown_render.vsh diff --git a/examples/webtools/mdbook_markdown/.gitignore b/examples/web/mdbook_markdown/.gitignore similarity index 100% rename from examples/webtools/mdbook_markdown/.gitignore rename to examples/web/mdbook_markdown/.gitignore diff --git a/examples/webtools/mdbook_markdown/content/cybercity.md b/examples/web/mdbook_markdown/content/cybercity.md similarity index 100% rename from examples/webtools/mdbook_markdown/content/cybercity.md rename to examples/web/mdbook_markdown/content/cybercity.md diff --git a/examples/webtools/mdbook_markdown/content/doc.md b/examples/web/mdbook_markdown/content/doc.md similarity index 100% rename from examples/webtools/mdbook_markdown/content/doc.md rename to examples/web/mdbook_markdown/content/doc.md diff --git a/examples/webtools/mdbook_markdown/content/launch.md b/examples/web/mdbook_markdown/content/launch.md similarity index 100% rename from examples/webtools/mdbook_markdown/content/launch.md rename to examples/web/mdbook_markdown/content/launch.md diff --git a/examples/webtools/mdbook_markdown/content/links.md b/examples/web/mdbook_markdown/content/links.md similarity index 100% rename from examples/webtools/mdbook_markdown/content/links.md rename to examples/web/mdbook_markdown/content/links.md diff --git a/examples/webtools/mdbook_markdown/content/macros.md b/examples/web/mdbook_markdown/content/macros.md similarity index 100% rename from examples/webtools/mdbook_markdown/content/macros.md rename to examples/web/mdbook_markdown/content/macros.md diff --git a/examples/webtools/mdbook_markdown/content/test.md b/examples/web/mdbook_markdown/content/test.md similarity index 100% rename from examples/webtools/mdbook_markdown/content/test.md rename to examples/web/mdbook_markdown/content/test.md diff --git a/examples/webtools/mdbook_markdown/content/test_para.md b/examples/web/mdbook_markdown/content/test_para.md similarity index 100% rename from examples/webtools/mdbook_markdown/content/test_para.md rename to examples/web/mdbook_markdown/content/test_para.md diff --git a/examples/webtools/mdbook_markdown/doctree_export.vsh b/examples/web/mdbook_markdown/doctree_export.vsh similarity index 95% rename from examples/webtools/mdbook_markdown/doctree_export.vsh rename to examples/web/mdbook_markdown/doctree_export.vsh index 068363b6..387d6f87 100755 --- a/examples/webtools/mdbook_markdown/doctree_export.vsh +++ b/examples/web/mdbook_markdown/doctree_export.vsh @@ -10,6 +10,7 @@ mut tree := doctree.new(name: 'test')! // git_reset bool // git_root string // git_pull bool + tree.scan( git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/collections' git_pull: false @@ -18,6 +19,6 @@ tree.scan( tree.export( destination: '/tmp/mdexport' reset: true - // keep_structure: true exclude_errors: false )! + diff --git a/examples/webtools/mdbook_markdown/markdown_example.vsh b/examples/web/mdbook_markdown/markdown_example.vsh similarity index 100% rename from examples/webtools/mdbook_markdown/markdown_example.vsh rename to examples/web/mdbook_markdown/markdown_example.vsh diff --git a/examples/webtools/siteconfig.vsh b/examples/web/siteconfig.vsh similarity index 100% rename from examples/webtools/siteconfig.vsh rename to examples/web/siteconfig.vsh diff --git a/examples/webtools/siteconfigexample/config.heroscript b/examples/web/siteconfigexample/config.heroscript similarity index 100% rename from examples/webtools/siteconfigexample/config.heroscript rename to examples/web/siteconfigexample/config.heroscript diff --git a/examples/webtools/siteconfigexample/site.heroscript b/examples/web/siteconfigexample/site.heroscript similarity index 100% rename from examples/webtools/siteconfigexample/site.heroscript rename to examples/web/siteconfigexample/site.heroscript diff --git a/examples/webtools/starllight_example.vsh b/examples/web/starllight_example.vsh similarity index 100% rename from examples/webtools/starllight_example.vsh rename to examples/web/starllight_example.vsh diff --git a/lib/data/doctree/collection/export.v b/lib/data/doctree/collection/export.v index 8636480c..bc1b5aeb 100644 --- a/lib/data/doctree/collection/export.v +++ b/lib/data/doctree/collection/export.v @@ -27,7 +27,7 @@ pub fn (mut c Collection) export(args CollectionExportArgs) ! { mut context := base.context()! mut redis := context.redis()! - redis.hset('collections:path', '${c.name}', dir_src.path)! + redis.hset('doctree:path', '${c.name}', dir_src.path)! c.errors << export_pages(c.name, c.path.path, c.pages.values(), dir_src: dir_src diff --git a/lib/web/doctreeclient/README.md b/lib/web/doctreeclient/README.md new file mode 100644 index 00000000..c551c785 --- /dev/null +++ b/lib/web/doctreeclient/README.md @@ -0,0 +1,186 @@ +# DocTreeClient + +DocTreeClient provides a simple API for accessing document collections that have been processed and stored by the `doctree` module. It allows you to: + +- List available collections +- List pages, files, and images within collections +- Check if specific pages, files, or images exist +- Get file paths for pages, files, and images +- Retrieve content of pages + +The client works with Redis as a backend storage system, where document collections are indexed and their metadata is stored. + +## Usage + +### Creating a Client + +```v +import freeflowuniverse.herolib.web.doctreeclient + +// Create a new DocTreeClient instance +mut client := doctreeclient.new()! +``` + +### Working with Collections + +```v +// List all available collections +collections := client.list_collections()! +println('Available collections: ${collections}') + +// Check if a collection exists by trying to list its pages +if client.page_exists('my_collection', 'some_page') { + println('Collection and page exist') +} +``` + +### Working with Pages + +```v +// List all pages in a collection +pages := client.list_pages('my_collection')! +println('Pages in collection: ${pages}') + +// Check if a specific page exists +if client.page_exists('my_collection', 'introduction') { + println('Page exists') +} + +// Get the file path for a page +page_path := client.get_page_path('my_collection', 'introduction')! +println('Page path: ${page_path}') + +// Get the content of a page +content := client.get_page_content('my_collection', 'introduction')! +println('Page content: ${content}') +``` + +### Working with Files + +```v +// List all files in a collection +files := client.list_files('my_collection')! +println('Files in collection: ${files}') + +// Check if a specific file exists +if client.file_exists('my_collection', 'document.pdf') { + println('File exists') +} + +// Get the file path +file_path := client.get_file_path('my_collection', 'document.pdf')! +println('File path: ${file_path}') +``` + +### Working with Images + +```v +// List all images in a collection +images := client.list_images('my_collection')! +println('Images in collection: ${images}') + +// Check if a specific image exists +if client.image_exists('my_collection', 'diagram.png') { + println('Image exists') +} + +// Get the image path +image_path := client.get_image_path('my_collection', 'diagram.png')! +println('Image path: ${image_path}') +``` + +## Complete Example + +Here's a complete example that demonstrates how to use DocTreeClient with a document collection: + +```v +module main + +import freeflowuniverse.herolib.web.doctreeclient +import freeflowuniverse.herolib.data.doctree + +fn main() { + // First, populate Redis with doctree data + mut tree := doctree.new(name: 'example_docs')! + + // Scan a git repository containing documentation + tree.scan( + git_url: 'https://github.com/example/docs' + git_pull: true + )! + + // Export the doctree to Redis and local filesystem + tree.export( + destination: '/tmp/docs_export' + reset: true + )! + + // Create a DocTreeClient instance + mut client := doctreeclient.new()! + + // List all collections + collections := client.list_collections()! + println('Available collections: ${collections}') + + // Use the first collection + if collections.len > 0 { + collection_name := collections[0] + + // List pages in the collection + pages := client.list_pages(collection_name)! + println('Pages in collection: ${pages}') + + // Get content of the first page + if pages.len > 0 { + page_name := pages[0] + content := client.get_page_content(collection_name, page_name)! + println('Content of ${page_name}:') + println(content) + } + + // List and display images + images := client.list_images(collection_name)! + println('Images in collection: ${images}') + + // List and display other files + files := client.list_files(collection_name)! + println('Files in collection: ${files}') + } +} +``` + +## Error Handling + +DocTreeClient provides specific error types for different failure scenarios: + +```v +pub enum DocTreeError { + collection_not_found + page_not_found + file_not_found + image_not_found +} +``` + +You can handle these errors using V's error handling mechanisms: + +```v +// Example of error handling +page_content := client.get_page_content('my_collection', 'non_existent_page') or { + if err.msg.contains('page_not_found') { + println('The page does not exist') + return + } + println('An error occurred: ${err}') + return +} +``` + +## How It Works + +DocTreeClient works with Redis as its backend storage: + +1. The `doctree` module processes document collections and stores metadata in Redis +2. Collection paths are stored in the 'doctree:meta' hash +3. Page, file, and image paths within a collection are stored in 'doctree:{collection_name}' hashes +4. DocTreeClient provides methods to access this data and retrieve the actual content from the filesystem diff --git a/lib/web/doctreeclient/doctree_test.v b/lib/web/doctreeclient/doctree_test.v index c744f47e..b8c89cc3 100644 --- a/lib/web/doctreeclient/doctree_test.v +++ b/lib/web/doctreeclient/doctree_test.v @@ -25,7 +25,7 @@ fn test_doctree_client() ! { println('Doctree data populated in Redis') // Create a DocTreeClient instance - mut client := new('/tmp/mdexport')! + mut client := new()! // Test listing collections println('\nListing collections:') @@ -34,7 +34,7 @@ fn test_doctree_client() ! { if collections.len == 0 { println('No collections found. Test cannot continue.') - return + panic("No collections found") } // Use the first collection for testing @@ -62,7 +62,6 @@ fn test_doctree_client() ! { // Test getting page content content := client.get_page_content(collection_name, page_name)! println('Page content length: ${content.len} characters') - println('First 100 characters: ${content[..min(100, content.len)]}...') } else { println('No pages found for testing') } @@ -133,11 +132,6 @@ fn test_doctree_client() ! { println('Non-existent page exists: ${exists2} (should be false)') println('\nTest completed successfully!') -} -fn main() { - test_doctree_client() or { - eprintln('Error: ${err}') - exit(1) - } -} \ No newline at end of file + if true{panic("ss")} +} diff --git a/lib/web/doctreeclient/factory.v b/lib/web/doctreeclient/factory.v index bc6926e7..0ccb7789 100644 --- a/lib/web/doctreeclient/factory.v +++ b/lib/web/doctreeclient/factory.v @@ -1,9 +1,7 @@ module doctreeclient import freeflowuniverse.herolib.core.base -// new creates a new DocTreeClient instance -// path: The base path where doctree collections are exported (not used internally but kept for API consistency) -pub fn new(path string) !&DocTreeClient { +pub fn new() !&DocTreeClient { mut context := base.context()! mut redis := context.redis()!