From 46ce903d4dd365d9c544f8fe55e3b27689da5c0d Mon Sep 17 00:00:00 2001 From: despiegk Date: Sun, 26 Oct 2025 22:24:18 +0400 Subject: [PATCH] ... --- .../atlas/heroscript_example_auth_web.hero | 11 ++- lib/data/atlas/atlas.v | 19 +---- lib/data/atlas/collection.v | 31 +++++++- lib/data/atlas/collection_error.v | 10 ++- lib/data/atlas/export.v | 4 +- lib/data/atlas/getters.v | 20 +++++ lib/data/atlas/link.v | 73 ++++++++++++------- lib/data/atlas/play.v | 15 +++- 8 files changed, 126 insertions(+), 57 deletions(-) diff --git a/examples/data/atlas/heroscript_example_auth_web.hero b/examples/data/atlas/heroscript_example_auth_web.hero index c704f65f..e38182f1 100755 --- a/examples/data/atlas/heroscript_example_auth_web.hero +++ b/examples/data/atlas/heroscript_example_auth_web.hero @@ -1,9 +1,12 @@ #!/usr/bin/env hero -!!atlas.scan - git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/collections/mycelium_economics' +!!atlas.scan + git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/collections/mycelium_economics' -!!atlas.scan - git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/collections/authentic_web' +!!atlas.scan + git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/collections/authentic_web' + +// !!atlas.scan +// git_url: 'https://git.ourworld.tf/geomind/docs_geomind/src/branch/main/collections/usecases' !!atlas.export destination: '/tmp/atlas_export' diff --git a/lib/data/atlas/atlas.v b/lib/data/atlas/atlas.v index 275615a8..62ce9e27 100644 --- a/lib/data/atlas/atlas.v +++ b/lib/data/atlas/atlas.v @@ -38,7 +38,7 @@ fn (mut self Atlas) add_collection(mut path pathlib.Path) !Collection { error_cache: map[string]bool{} } - c.init()! + c.init_pre()! self.collections[name] = &c @@ -56,16 +56,9 @@ pub fn (a Atlas) get_collection(name string) !&Collection { } // Validate all links in all collections -pub fn (mut a Atlas) validate_links() ! { +pub fn (mut a Atlas) init_post() ! { for _, mut col in a.collections { - col.validate_links()! - } -} - -// Fix all links in all collections -pub fn (mut a Atlas) fix_links() ! { - for _, mut col in a.collections { - col.fix_links()! + col.init_post()! } } @@ -97,12 +90,6 @@ pub fn (a Atlas) groups_get(session Session) []&Group { return matching } - -pub fn (mut a Atlas) validate() ! { - a.validate_links()! - a.fix_links()! -} - //////////////////SCAN // Scan a path for collections diff --git a/lib/data/atlas/collection.v b/lib/data/atlas/collection.v index 7b709f54..4bb45580 100644 --- a/lib/data/atlas/collection.v +++ b/lib/data/atlas/collection.v @@ -1,7 +1,7 @@ module atlas import incubaid.herolib.core.pathlib -import incubaid.herolib.core.texttools +// import incubaid.herolib.core.texttools import incubaid.herolib.develop.gittools import incubaid.herolib.data.paramsparser { Params } import incubaid.herolib.ui.console @@ -34,12 +34,18 @@ pub fn (mut c Collection) path() !pathlib.Path { return pathlib.get_dir(path: c.path, create: false)! } -fn (mut c Collection) init() ! { +fn (mut c Collection) init_pre() ! { mut p := mut c.path()! c.scan(mut p)! c.scan_acl()! } +fn (mut c Collection) init_post() ! { + c.validate_links()! + c.init_git_info()! +} + + //////////////////////////////////////////////////////////////////////////////////////////////////////// // Add a page to the collection @@ -62,7 +68,7 @@ fn (mut c Collection) add_page(mut path pathlib.Path) ! { // Add an image to the collection fn (mut c Collection) add_file(mut p pathlib.Path) ! { - name := p.name_fix_no_ext() + name := p.name_fix_keepext() if name in c.files { return error('Page ${name} already exists in collection ${c.name}') } @@ -115,6 +121,15 @@ pub fn (c Collection) file_get(name string) !&File { return f } +pub fn (c Collection) file_or_image_get(name string) !&File { + mut f := c.files[name] or { return FileNotFound{ + collection: c.name + file: name + } } + return f +} + + // Check if page exists pub fn (c Collection) page_exists(name string) bool { return name in c.pages @@ -132,6 +147,14 @@ pub fn (c Collection) file_exists(name string) bool { return f.ftype == .file } +pub fn (c Collection) file_or_image_exists(name string) bool { + f := c.files[name] or { return false } + return true +} + + + + @[params] pub struct CollectionErrorArgs { pub mut: @@ -220,7 +243,7 @@ pub fn (c Collection) print_errors() { pub fn (mut c Collection) validate_links() ! { for _, mut page in c.pages { content := page.content(include: true)! - page.find_links(content)! // will walk over links see if errors and add errors + page.links=page.find_links(content)! // will walk over links see if errors and add errors } } diff --git a/lib/data/atlas/collection_error.v b/lib/data/atlas/collection_error.v index cdff3cd6..f347d1a5 100644 --- a/lib/data/atlas/collection_error.v +++ b/lib/data/atlas/collection_error.v @@ -8,6 +8,7 @@ pub enum CollectionErrorCategory { missing_include include_syntax_error invalid_page_reference + invalid_file_reference file_not_found invalid_collection general_error @@ -26,13 +27,13 @@ pub mut: // Hash is based on category + page_key (or file if page_key is empty) pub fn (e CollectionError) hash() string { mut hash_input := '${e.category}' - + if e.page_key != '' { hash_input += ':${e.page_key}' } else if e.file != '' { hash_input += ':${e.file}' } - + return md5.hexhash(hash_input) } @@ -44,7 +45,7 @@ pub fn (e CollectionError) str() string { } else if e.file != '' { location = ' [${e.file}]' } - + return '[${e.category}]${location}: ${e.message}' } @@ -55,9 +56,10 @@ pub fn (e CollectionError) category_str() string { .missing_include { 'Missing Include' } .include_syntax_error { 'Include Syntax Error' } .invalid_page_reference { 'Invalid Page Reference' } + .invalid_file_reference { 'Invalid File Reference' } .file_not_found { 'File Not Found' } .invalid_collection { 'Invalid Collection' } .general_error { 'General Error' } .acl_denied { 'ACL Access Denied' } } -} \ No newline at end of file +} diff --git a/lib/data/atlas/export.v b/lib/data/atlas/export.v index 6c7f93b0..6835be2f 100644 --- a/lib/data/atlas/export.v +++ b/lib/data/atlas/export.v @@ -23,7 +23,7 @@ pub fn (mut a Atlas) export(args ExportArgs) ! { } // Validate links before export - a.validate_links()! + // a.validate_links()! for _, mut col in a.collections { col.export( @@ -61,7 +61,7 @@ pub fn (mut c Collection) export(args CollectionExportArgs) ! { col_dir_meta.empty()! } - c.init_git_info()! + if c.has_errors() { c.print_errors() diff --git a/lib/data/atlas/getters.v b/lib/data/atlas/getters.v index 240f520c..262841d9 100644 --- a/lib/data/atlas/getters.v +++ b/lib/data/atlas/getters.v @@ -33,6 +33,16 @@ pub fn (a Atlas) file_get(key string) !&File { return col.file_get(parts[1])! } +// Get a file (can be image) from any collection using format "collection:file" +pub fn (a Atlas) file_or_image_get(key string) !&File { + parts := key.split(':') + if parts.len != 2 { + return error('Invalid file key format. Use "collection:file"') + } + col := a.get_collection(parts[0])! + return col.file_or_image_get(parts[1])! +} + // Check if page exists pub fn (a Atlas) page_exists(key string) bool { parts := key.split(':') @@ -66,6 +76,16 @@ pub fn (a Atlas) file_exists(key string) bool { return col.file_exists(parts[1]) } +pub fn (a Atlas) file_or_image_exists(key string) bool { + parts := key.split(':') + if parts.len != 2 { + return false + } + col := a.get_collection(parts[0]) or { return false } + return col.file_or_image_exists(parts[1]) +} + + // List all pages in Atlas pub fn (a Atlas) list_pages() map[string][]string { mut result := map[string][]string{} diff --git a/lib/data/atlas/link.v b/lib/data/atlas/link.v index baa11605..42e6a0f7 100644 --- a/lib/data/atlas/link.v +++ b/lib/data/atlas/link.v @@ -11,24 +11,23 @@ pub mut: target string // Original link target (the source text) line int // Line number where link was found target_collection_name string - target_page_name string + target_item_name string status LinkStatus + is_file_link bool // is the link pointing to a file page &Page @[skip; str: skip] // Reference to page where this link is found } pub enum LinkStatus { init external - page_found - page_not_found - file_found - file_not_found + found + not_found anchor error } fn (mut self Link) key() string { - return '${self.target_collection_name}:${self.target_page_name}' + return '${self.target_collection_name}:${self.target_item_name}' } // is the link in the same collection as the page containing the link @@ -57,6 +56,8 @@ fn (mut p Page) find_links(content string) ![]Link { for line_idx, line in lines { mut pos := 0 for { + mut image_open := line.index_after('!', pos) or { break } + // Find next [ open_bracket := line.index_after('[', pos) or { break } @@ -69,6 +70,10 @@ fn (mut p Page) find_links(content string) ![]Link { continue } + if image_open + 1 != open_bracket { + image_open = -1 + } + // Find matching ) open_paren := close_bracket + 1 close_paren := line.index_after(')', open_paren) or { break } @@ -77,12 +82,15 @@ fn (mut p Page) find_links(content string) ![]Link { text := line[open_bracket + 1..close_bracket] target := line[open_paren + 1..close_paren] + islink_file_link := (image_open != -1) + mut link := Link{ - src: line[open_bracket..close_paren + 1] - text: text - target: target.trim_space() - line: line_idx + 1 - page: &p + src: line[open_bracket..close_paren + 1] + text: text + target: target.trim_space() + line: line_idx + 1 + is_file_link: islink_file_link + page: &p } p.parse_link_target(mut link) @@ -96,7 +104,7 @@ fn (mut p Page) find_links(content string) ![]Link { // Parse link target to extract collection and page fn (mut p Page) parse_link_target(mut link Link) { - target := link.target + mut target := link.target // Skip external links if target.starts_with('http://') || target.starts_with('https://') @@ -111,28 +119,43 @@ fn (mut p Page) parse_link_target(mut link Link) { return } + if target.contains('/') { + parts9 := target.split('/') + if parts9.len >= 1 { + target = parts9[1] + } + } + // Format: $collection:$pagename or $collection:$pagename.md if target.contains(':') { parts := target.split(':') if parts.len >= 2 { link.target_collection_name = texttools.name_fix(parts[0]) - link.target_page_name = normalize_page_name(parts[1]) + link.target_item_name = normalize_page_name(parts[1]) } } else { - link.target_page_name = normalize_page_name(target).trim_space() + link.target_item_name = normalize_page_name(target).trim_space() link.target_collection_name = p.collection.name } - if !p.collection.atlas.page_exists(link.key()) { + if link.is_file_link == false && !p.collection.atlas.page_exists(link.key()) { p.collection.error( category: .invalid_page_reference page_key: p.key() message: 'Broken link to `${link.key()}` at line ${link.line}: `${link.src}`' - show_console: false + show_console: true ) - link.status = .page_not_found + link.status = .not_found + } else if link.is_file_link && !p.collection.atlas.file_or_image_exists(link.key()) { + p.collection.error( + category: .invalid_file_reference + page_key: p.key() + message: 'Broken file link to `${link.key()}` at line ${link.line}: `${link.src}`' + show_console: true + ) + link.status = .not_found } else { - link.status = .page_found + link.status = .found } } @@ -148,7 +171,7 @@ fn (mut p Page) content_with_fixed_links() !string { // Process links in reverse order to maintain positions for mut link in p.links.reverse() { // if page not existing no point in fixing - if link.status != .page_found { + if link.status != .found { continue } // if not local then no point in fixing @@ -183,7 +206,7 @@ fn (mut p Page) process_cross_collection_links(mut export_dir pathlib.Path) !str // Process links in reverse order to maintain string positions for mut link in links.reverse() { - if link.status != .page_found { + if link.status != .found { continue } mut target_page := link.target_page()! @@ -206,11 +229,11 @@ fn (mut p Page) process_cross_collection_links(mut export_dir pathlib.Path) !str panic('need to do for files too') } - for mut link in links.reverse() { - if link.status != . { - continue - } - } + // for mut link in links.reverse() { + // if link.status != . { + // continue + // } + // } return c } diff --git a/lib/data/atlas/play.v b/lib/data/atlas/play.v index 6b74de86..b672ebdc 100644 --- a/lib/data/atlas/play.v +++ b/lib/data/atlas/play.v @@ -12,11 +12,13 @@ pub fn play(mut plbook PlayBook) ! { mut atlases := map[string]&Atlas{} + mut name := "" + // Process scan actions - scan directories for collections mut scan_actions := plbook.find(filter: 'atlas.scan')! for mut action in scan_actions { mut p := action.params - name := p.get_default('name', 'main')! + name = p.get_default('name', 'main')! ignore := p.get_list_default('ignore', [])! console.print_item("Scanning Atlas '${name}' with ignore patterns: ${ignore}\n${p}") // Get or create atlas @@ -48,13 +50,22 @@ pub fn play(mut plbook PlayBook) ! { set(atlas_instance) } + mut atlas_instance_post := atlases[name] or { + return error("Atlas '${name}' not found. Use !!atlas.scan first.") + } + + + atlas_instance_post.init_post()! + + println(atlas_instance_post) + // Process export actions - export collections to destination mut export_actions := plbook.find(filter: 'atlas.export')! // Process explicit export actions for mut action in export_actions { mut p := action.params - name := p.get_default('name', 'main')! + name = p.get_default('name', 'main')! destination := p.get('destination')! reset := p.get_default_true('reset') include := p.get_default_true('include')