#include "kappa/service/service.hpp" #include "kappa/util.hpp" #include #include namespace kappa::service { std::string generate_runit_service(const ServiceSpec& spec) { std::ostringstream out; // Shebang out << "#!/bin/sh\n"; // Header out << "# Generated by kappa — do not edit manually\n"; out << std::format("# runit service: {}\n", spec.name); out << std::format("# Type: {}\n", spec.type); // Forking note if (spec.type == "forking") { out << "# NOTE: runit requires foreground execution.\n"; out << "# If the daemon forks, pass --foreground or equivalent" " flag.\n"; } // Oneshot note if (spec.type == "oneshot") { out << "# NOTE: runit has no native oneshot support. This service" " will restart on exit.\n"; } // Redirect stderr to stdout for logging out << "exec 2>&1\n"; // Working directory if (!spec.working_dir.empty()) { out << std::format("cd \"{}\"\n", util::shell_escape(spec.working_dir)); } // Environment variables for (const auto& [key, value] : spec.env) { out << std::format("export {}=\"{}\"\n", key, util::shell_escape(value)); } // Final exec — replace the shell with the daemon if (!spec.user.empty()) { out << std::format("exec chpst -u {} {}\n", util::shell_escape(spec.user), spec.exec); } else { out << "exec " << spec.exec << "\n"; } return out.str(); } } // namespace kappa::service