/****************************************************************************** __ ____ __ / / ___ ____ _/ __/_____________ _/ /__ / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ (C)opyright 2025, Leafscale, LLC - https://www.leafscale.com Project: Zygaena Filename: ports.reef Authors: Chris Tusa License: Description: Ports command - port scaffolding and cache management ******************************************************************************/ module commands.ports import sys.args import io.file import io.dir import io.path import core.str import core.config import core.portindex import types import util.color import exitcodes as ec import core.result as res export fn execute(opts: types.GlobalOptions): int end export fn execute(opts: types.GlobalOptions): int let argc = args.count() if argc <= opts.cmd_index + 1 print_usage() return ec.EXIT_USAGE() end if let subcommand = args.get(opts.cmd_index + 1) if subcommand == "new" return ports_new(opts) elif subcommand == "cache" return ports_cache(opts) else color.print_error("Unknown subcommand: " + subcommand) print_usage() return ec.EXIT_USAGE() end if end execute // ============================================================================ // coral ports new // ============================================================================ fn ports_new(opts: types.GlobalOptions): int let argc = args.count() if argc <= opts.cmd_index + 2 color.print_error("Missing argument: category/name") println("Usage: coral ports new ") return ec.EXIT_USAGE() end if let arg = args.get(opts.cmd_index + 2) // Require slash format let slash_idx = str.index_of(arg, "/") if slash_idx <= 0 color.print_error("Invalid format: '" + arg + "'") println("Use category/name format, e.g.: coral ports new hammerhead/my-port") return ec.EXIT_USAGE() end if let category = str.substring(arg, 0, slash_idx) let name = str.substring(arg, slash_idx + 1, str.length(arg) - slash_idx - 1) if str.length(name) == 0 color.print_error("Port name cannot be empty") return ec.EXIT_USAGE() end if // Get ports directory let cfg = config.load() let ports_dir = config.get_ports_dir(cfg) // Create port directory let port_dir = path.join_path(ports_dir, path.join_path(category, name)) if dir.dir_exists(port_dir) color.print_error("Port directory already exists: " + port_dir) return ec.EXIT_PKG_ALREADY_INSTALLED() end if if not res.is_ok(dir.create_dir_all(port_dir)) color.print_error("Failed to create directory: " + port_dir) return ec.EXIT_PERMISSION_DENIED() end if // Generate package.toml let toml_path = path.join_path(port_dir, "package.toml") let toml_content = "[package]\nname = \"" + name + "\"\nversion = \"0.1.0\"\nrelease = 1\ndescription = \"\"\nurl = \"\"\nlicense = \"\"\nmaintainer = \"\"\narch = \"x86_64\"\n\n[dependencies]\nruntime = []\nbuild = []\n\n[[source]]\nfile = \"\"\nurls = []\nchecksum = \"SKIP\"\n\n[build]\nparallel = true\njobs = 0\n" if not res.is_ok(file.writeFile(toml_path, toml_content)) color.print_error("Failed to write package.toml") return ec.EXIT_PERMISSION_DENIED() end if // Generate build.sh let build_path = path.join_path(port_dir, "build.sh") let dollar = "$" let build_content = "#!/bin/sh\n# Build script for " + name + "\nset -e\n\n# cd " + name + "-" + dollar + "{VERSION}\n\nMAKE=gmake\nif [ \"" + dollar + "(uname -s)\" != \"SunOS\" ]; then\n MAKE=make\nfi\n\n# ./configure --prefix=/usr\n# " + dollar + "MAKE " + dollar + "{MAKEFLAGS}\n# " + dollar + "MAKE DESTDIR=\"" + dollar + "{DESTDIR}\" install\n" if not res.is_ok(file.writeFile(build_path, build_content)) color.print_error("Failed to write build.sh") return ec.EXIT_PERMISSION_DENIED() end if color.print_success("Port created: " + category + "/" + name) println("") println(" Directory: " + port_dir) println(" package.toml: " + toml_path) println(" build.sh: " + build_path) println("") color.print_info("Next steps:") println(" 1. Edit package.toml with package details") println(" 2. Add source URLs and checksums") println(" 3. Write the build.sh script") println(" 4. Test with: coral build " + category + "/" + name) return ec.EXIT_SUCCESS() end ports_new // ============================================================================ // coral ports cache [status|rebuild] // ============================================================================ fn ports_cache(opts: types.GlobalOptions): int let argc = args.count() if argc <= opts.cmd_index + 2 // Default to status return cache_status() end if let subcmd = args.get(opts.cmd_index + 2) if subcmd == "status" return cache_status() elif subcmd == "rebuild" return cache_rebuild() else color.print_error("Unknown cache subcommand: " + subcmd) println("Usage: coral ports cache [status|rebuild]") return ec.EXIT_USAGE() end if end ports_cache fn cache_status(): int color.print_action("Ports index status:") println("") if portindex.port_index_exists() let count = portindex.get_port_count() println(" Status: built") println(" Ports indexed: " + int_to_str(count)) else println(" Status: not built") color.print_info("Run 'coral ports cache rebuild' to build the index") end if return ec.EXIT_SUCCESS() end cache_status fn cache_rebuild(): int color.print_action("Rebuilding ports index...") println("") if portindex.rebuild_port_index() let count = portindex.get_port_count() color.print_success("Ports index rebuilt successfully") println(" Ports indexed: " + int_to_str(count)) return ec.EXIT_SUCCESS() else color.print_error("Failed to rebuild ports index") return ec.EXIT_DB_ERROR() end if end cache_rebuild // ============================================================================ // Usage // ============================================================================ proc print_usage() println("Usage: coral ports [args]") println("") println("Port development and cache management.") println("") println("Commands:") println(" new Scaffold a new port") println(" cache [status] Show ports index status") println(" cache rebuild Rebuild ports index") println("") println("Examples:") println(" coral ports new hammerhead/my-port") println(" coral ports cache status") println(" coral ports cache rebuild") 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