/****************************************************************************** __ ____ __ / / ___ ____ _/ __/_____________ _/ /__ / / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \ / /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/ /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/ (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 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 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 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 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