/****************************************************************************** __ ____ __ / / ___ ____ _/ __/_____________ _/ /__ / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ (C)opyright 2025, Leafscale, LLC - https://www.leafscale.com Project: Zygaena Filename: db.reef Authors: Chris Tusa License: Description: Database command - manage package database indexes ******************************************************************************/ module commands.db import sys.args import io.file import io.dir import core.str import core.config import core.pkgdb import core.portindex import types import util.color import exitcodes as ec export fn execute(opts: types.GlobalOptions): int end export fn execute(opts: types.GlobalOptions): int let argc = args.count() // Subcommand should be at cmd_index + 1 if argc <= opts.cmd_index + 1 print_usage() return ec.EXIT_USAGE() end if // Load configuration and apply command-line overrides let base_cfg = config.load() let cfg = config.apply_overrides(base_cfg, opts.root, opts.prefix) let root_path = config.get_root(cfg) // Show root if set (verbose mode) if opts.verbose and str.length(root_path) > 0 color.print_info("Using root: " + root_path) end if let subcommand = args.get(opts.cmd_index + 1) if subcommand == "init" return db_init(root_path) elif subcommand == "rebuild" return db_rebuild(root_path) elif subcommand == "status" return db_status(root_path) elif subcommand == "dump" return db_dump(root_path) else color.print_error("Unknown subcommand: " + subcommand) print_usage() return ec.EXIT_USAGE() end if end execute fn db_init(root_path: string): int if str.length(root_path) > 0 color.print_action("Initializing package database in " + root_path + "...") else color.print_action("Initializing package database...") end if println("") // Check if database already exists (use rooted version if root is set) let exists = check_indexes_exist(root_path) if exists color.print_warning("Database indexes already exist") color.print_info("Use 'coral db rebuild' to regenerate indexes") return ec.EXIT_SUCCESS() end if // Initialize the database directory (use rooted version if root is set) if not init_pkgdb(root_path) color.print_error("Failed to create database directory") return ec.EXIT_DB_ERROR() end if // Build initial indexes (use rooted version if root is set) if not rebuild_pkgdb(root_path) color.print_error("Failed to build initial indexes") return ec.EXIT_DB_ERROR() end if // Build ports index portindex.rebuild_port_index() let stats = get_pkgdb_stats(root_path) let port_count = portindex.get_port_count() color.print_success("Database initialized successfully") println(" Packages indexed: " + int_to_str(stats.package_count)) println(" Files indexed: " + int_to_str(stats.file_count)) println(" Ports indexed: " + int_to_str(port_count)) return ec.EXIT_SUCCESS() end db_init fn db_rebuild(root_path: string): int if str.length(root_path) > 0 color.print_action("Rebuilding package database indexes in " + root_path + "...") else color.print_action("Rebuilding package database indexes...") end if println("") // Check if db directory exists (use rooted version if root is set) if not init_pkgdb(root_path) color.print_error("Failed to access database directory") color.print_info("Run 'coral db init' first") return ec.EXIT_DB_ERROR() end if // Rebuild indexes from source of truth (use rooted version if root is set) if not rebuild_pkgdb(root_path) color.print_error("Failed to rebuild indexes") return ec.EXIT_DB_ERROR() end if // Rebuild ports index portindex.rebuild_port_index() let stats = get_pkgdb_stats(root_path) let port_count = portindex.get_port_count() color.print_success("Database indexes rebuilt successfully") println(" Packages indexed: " + int_to_str(stats.package_count)) println(" Files indexed: " + int_to_str(stats.file_count)) println(" Ports indexed: " + int_to_str(port_count)) return ec.EXIT_SUCCESS() end db_rebuild fn db_dump(root_path: string): int color.print_action("Dumping files index contents...") println("") mut paths: [string] = new [string](256) mut owners: [string] = new [string](256) let count = pkgdb.dump_files_index_rooted(root_path, paths, owners, 256) if count == 0 color.print_warning("No files in index or index not loaded") return ec.EXIT_DB_ERROR() end if println("Files in index: " + int_to_str(count)) println("") mut i = 0 while i < count println(" [" + int_to_str(i) + "] '" + paths[i] + "' -> '" + owners[i] + "'") i = i + 1 end while return ec.EXIT_SUCCESS() end db_dump fn db_status(root_path: string): int if str.length(root_path) > 0 color.print_action("Package database status for " + root_path + ":") else color.print_action("Package database status:") end if println("") let stats = get_pkgdb_stats(root_path) if not check_indexes_exist(root_path) color.print_warning("Database indexes not found") color.print_info("Run 'coral db init' to create indexes") println("") if str.length(root_path) > 0 println(" Source of truth: " + root_path + "/var/lib/coral/installed/") else println(" Source of truth: /var/lib/coral/installed/") end if println(" Packages installed: " + int_to_str(stats.package_count)) return ec.EXIT_DB_INDEX_STALE() end if if str.length(root_path) > 0 println(" Index location: " + root_path + types.get_index_dir()) else println(" Index location: " + types.get_index_dir()) end if println(" Packages indexed: " + int_to_str(stats.package_count)) println(" Files indexed: " + int_to_str(stats.file_count)) if stats.packages_db_size > 0 println(" packages.db size: " + format_size(stats.packages_db_size)) end if if stats.files_db_size > 0 println(" files.db size: " + format_size(stats.files_db_size)) end if // Ports index status if portindex.port_index_exists() let port_count = portindex.get_port_count() println(" Ports indexed: " + int_to_str(port_count)) else println(" Ports index: not built") end if return ec.EXIT_SUCCESS() end db_status // Helper functions for rooted pkgdb operations fn check_indexes_exist(root_path: string): bool if str.length(root_path) > 0 return pkgdb.indexes_exist_rooted(root_path) end if return pkgdb.indexes_exist() end check_indexes_exist fn init_pkgdb(root_path: string): bool if str.length(root_path) > 0 return pkgdb.init_db_rooted(root_path) end if return pkgdb.init_db() end init_pkgdb fn rebuild_pkgdb(root_path: string): bool if str.length(root_path) > 0 return pkgdb.rebuild_indexes_rooted(root_path) end if return pkgdb.rebuild_indexes() end rebuild_pkgdb fn get_pkgdb_stats(root_path: string): pkgdb.IndexStats if str.length(root_path) > 0 return pkgdb.get_index_stats_rooted(root_path) end if return pkgdb.get_index_stats() end get_pkgdb_stats fn format_size(bytes: int): string if bytes < 1024 return int_to_str(bytes) + " B" elif bytes < 1024 * 1024 return int_to_str(bytes / 1024) + " KB" elif bytes < 1024 * 1024 * 1024 return int_to_str(bytes / (1024 * 1024)) + " MB" else return int_to_str(bytes / (1024 * 1024 * 1024)) + " GB" end if end format_size proc print_usage() println("Usage: coral db ") println("") println("Manage package database indexes.") println("") println("Commands:") println(" init Initialize database (run once during system setup)") println(" rebuild Rebuild indexes from installed packages") println(" status Show database status and statistics") println("") println("The package database provides fast lookups for installed packages") println("and file ownership. The source of truth is always the installed/") println("directory; indexes can be safely rebuilt at any time.") println("") println("Examples:") println(" coral db init") println(" coral db rebuild") println(" coral db status") end print_usage // Helper: convert int to string fn int_to_str(n: int): string if n == 0 return "0" end if mut negative = false mut value = n if n < 0 negative = true value = 0 - n end if mut result = "" while value > 0 let digit = value % 10 result = str.concat(str.substring("0123456789", digit, 1), result) value = value / 10 end while if negative result = str.concat("-", result) end if return result end int_to_str end module