/****************************************************************************** __ ____ __ / / ___ ____ _/ __/_____________ _/ /__ / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ (C)opyright 2025, Leafscale, LLC - https://www.leafscale.com Project: Zygaena Filename: depends.reef Authors: Chris Tusa License: Description: Depends command - show package dependency tree ******************************************************************************/ module commands.depends import sys.args import core.str import core.port import core.portindex import core.database import core.resolver import types import util.color import exitcodes as ec export fn execute(): int end export fn execute(): int let argc = args.count() if argc < 3 print_usage() return ec.EXIT_USAGE() end if let pkg_name = args.get(2) // Check for --reverse flag (show what depends on this package) if args.has_flag("reverse") or args.has_flag("r") show_reverse_deps(pkg_name) return ec.EXIT_SUCCESS() end if // Show forward dependencies show_deps(pkg_name) return ec.EXIT_SUCCESS() end execute proc show_deps(name: string) // Find the port let result = port.find(name) if not result.success color.print_error("Port not found: " + name) return end if let p = result.port color.print_action("Dependencies for " + name + ":") println("") // Show runtime dependencies if p.deps.runtime_count == 0 color.print_info("No runtime dependencies") else color.print_info("Runtime dependencies:") show_dep_tree(name, 0) end if println("") // Show build dependencies if p.deps.build_count > 0 color.print_info("Build dependencies:") mut i = 0 while i < p.deps.build_count print(" ") let dep = p.deps.build[i] print(dep) if database.is_installed(dep) println(" [installed]") else println("") end if i = i + 1 end while end if end show_deps proc show_dep_tree(name: string, depth: int) if depth > 10 return end if let result = port.find(name) if not result.success return end if let p = result.port mut i = 0 while i < p.deps.runtime_count let dep = p.deps.runtime[i] // Print with indentation print_indent(depth) print(dep) if database.is_installed(dep) println(" [installed]") else println("") end if // Recurse show_dep_tree(dep, depth + 1) i = i + 1 end while end show_dep_tree proc show_reverse_deps(name: string) color.print_action("Packages that depend on " + name + ":") println("") mut found = 0 // Try ports index first (fast path) if portindex.port_index_exists() mut results: [portindex.PortIndexEntry] = new [portindex.PortIndexEntry](512) let result_count = portindex.find_reverse_deps(name, results, 512) mut i = 0 while i < result_count let entry = results[i] print(" ") print(entry.category) print("/") print(entry.name) if database.is_installed(entry.name) println(" [installed]") else println("") end if found = found + 1 i = i + 1 end while else // Fall back to filesystem scan mut cats: [string] = new [string](32) let cat_count = port.get_categories(cats, 32) mut i = 0 while i < cat_count let category = cats[i] mut ports: [string] = new [string](256) let port_count = port.list_category(category, ports, 256) mut j = 0 while j < port_count let port_name = ports[j] if depends_on(port_name, name) print(" ") print(category) print("/") print(port_name) if database.is_installed(port_name) println(" [installed]") else println("") end if found = found + 1 end if j = j + 1 end while i = i + 1 end while end if if found == 0 color.print_info("No packages depend on " + name) else println("") color.print_info("Total: " + int_to_str(found) + " package(s)") end if end show_reverse_deps fn depends_on(pkg_name: string, dep_name: string): bool let result = port.find(pkg_name) if not result.success return false end if let p = result.port // Check runtime deps mut i = 0 while i < p.deps.runtime_count if p.deps.runtime[i] == dep_name return true end if i = i + 1 end while // Check build deps i = 0 while i < p.deps.build_count if p.deps.build[i] == dep_name return true end if i = i + 1 end while return false end depends_on proc print_indent(depth: int) mut i = 0 while i < depth print(" ") i = i + 1 end while print(" ") // Base indent end print_indent proc print_usage() println("Usage: coral depends [options]") println("") println("Show dependency tree for a package.") println("") println("Arguments:") println(" Name of package to show dependencies for") println("") println("Options:") println(" -r, --reverse Show packages that depend on this package") println("") println("Examples:") println(" coral depends vim") println(" coral depends vim --reverse") 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