#!/usr/bin/env nu # install/gen-projects.nu — validate and regenerate ~/.config/ontoref/projects.ncl. # # Manages LOCAL projects only. Remote projects live in remote-projects.ncl. # # Reads projects.ncl as text, extracts import paths, verifies each .ontoref/project.ncl # exists on disk, removes missing ones (with warning), and rewrites projects.ncl with # only valid imports. Must run before `nickel export config.ncl`. # # Usage: # nu install/gen-projects.nu # validate + regenerate # nu install/gen-projects.nu --add /path/to/project # register new local project # nu install/gen-projects.nu --remove /path/to/project # unregister local project # nu install/gen-projects.nu --dry-run # print result without writing def main [ --add: string, # path to local project root to register --remove: string, # path to local project root to unregister --dry-run, # print result without writing --config-dir: string = "", ] { let cfg_dir = if ($config_dir | is-empty) { $"($env.HOME)/.config/ontoref" } else { $config_dir } let projects_file = $"($cfg_dir)/projects.ncl" if not ($projects_file | path exists) { "[]" | save -f $projects_file } # ── Extract existing import paths as plain text (never call nickel here) ──── # open --raw: .ncl is unknown to Nushell; without --raw it may parse `[]` as # an empty list instead of a string, which would silently lose all existing entries. let content = open --raw $projects_file let existing_paths = ( $content | lines | each { |l| $l | str trim } | where { |l| ($l | str contains "import \"") } | each { |l| $l | parse --regex 'import\s+"(?P[^"]+)"' | get path | first } | flatten ) # ── Handle --remove ────────────────────────────────────────────────────────── let after_remove = if ($remove | is-not-empty) { let abs = ($remove | path expand) let ncl_path = $"($abs)/.ontoref/project.ncl" let filtered = ($existing_paths | where { |p| $p != $ncl_path }) if ($filtered | length) == ($existing_paths | length) { print --stderr $" (ansi yellow)not registered(ansi reset): ($ncl_path)" } else { print --stderr $" (ansi green)removed(ansi reset): ($ncl_path)" } $filtered } else { $existing_paths } # ── Handle --add ───────────────────────────────────────────────────────────── let after_add = if ($add | is-not-empty) { let abs = ($add | path expand) let ncl_path = $"($abs)/.ontoref/project.ncl" if not ($ncl_path | path exists) { error make { msg: $"project.ncl not found: ($ncl_path)\nCopy templates/project.ncl to ($add)/.ontoref/project.ncl and fill in the fields." } } if ($after_remove | any { |p| $p == $ncl_path }) { print --stderr $" (ansi yellow)already registered(ansi reset): ($ncl_path)" $after_remove } else { $after_remove | append $ncl_path } } else { $after_remove } # ── Validate: check local paths still exist ────────────────────────────────── let valid_paths = ( $after_add | each { |p| if not ($p | path exists) { let project_root = ($p | str replace --regex '(/\.ontoref/project\.ncl)$' '') if not ($project_root | path exists) { print --stderr $" (ansi yellow)WARN(ansi reset) removing missing project (root deleted): ($project_root)" } else { print --stderr $" (ansi yellow)WARN(ansi reset) removing invalid project (project.ncl missing): ($p)" } null } else { $p } } | compact ) let removed = ($after_add | length) - ($valid_paths | length) if $removed > 0 { print --stderr $" (ansi yellow)($removed) project(s) removed — path(s) no longer exist(ansi reset)" } # ── Generate projects.ncl ───────────────────────────────────────────────────── let import_lines = ( $valid_paths | each { |p| $" [import \"($p)\"]," } | str join "\n" ) let output = if ($valid_paths | is-empty) { "# AUTO-GENERATED by ontoref project-add / ontoref-daemon-boot. Do not edit by hand.\n# Add a local project: ontoref project-add /path/to/project\n\n[]\n" } else { "# AUTO-GENERATED by ontoref project-add / ontoref-daemon-boot. Do not edit by hand.\n# Add a local project: ontoref project-add /path/to/project\n\nstd.array.flatten [\n" + $import_lines + "\n]\n" } if $dry_run { print --stderr "── projects.ncl (dry-run) ──────────────────────────────" print $output print --stderr "────────────────────────────────────────────────────────" } else { $output | save -f $projects_file let n = ($valid_paths | length) let label = if $n == 1 { "project" } else { "projects" } print --stderr $" (ansi green)OK(ansi reset) ($n) local ($label) written to ($projects_file)" } }