From e69ebf220da48736b22593c67ffd4f8d7e94eb4f Mon Sep 17 00:00:00 2001 From: huntedbytheirs Date: Wed, 5 Aug 2026 07:34:12 -0400 Subject: [PATCH] feat: add --features and --config flags to kappa add MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kappa add nginx --features "ssl=on,gzip=off" --config "port=8080" adds/updates feature flags and config values in the system config. Comma-separated key=value pairs. Idempotent — only prints 'updated' when something actually changed. --- src/main.cpp | 79 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 16b1cf9..08ca273 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -54,6 +54,8 @@ Subcommands: rollback Show available generations index Build an index.kap from .kap files in a directory add [v] Add a package to system config (optional version) + --features "key=on,key2=off" Set feature flags + --config "key=val,key2=val2" Set config values remove Remove a package from system config Options: @@ -232,6 +234,8 @@ int main(int argc, char* argv[]) { const char* file_arg = nullptr; const char* version_arg = nullptr; + const char* features_arg = nullptr; + const char* config_arg = nullptr; bool dry_run = false; for (int i = arg_start + 1; i < argc; ++i) { if (std::string_view(argv[i]) == "-h" @@ -254,6 +258,14 @@ int main(int argc, char* argv[]) { paths::set_root(argv[++i]); continue; } + if (std::string_view(argv[i]) == "--features" && i + 1 < argc) { + features_arg = argv[++i]; + continue; + } + if (std::string_view(argv[i]) == "--config" && i + 1 < argc) { + config_arg = argv[++i]; + continue; + } if (std::string_view(argv[i]) == "--dry-run") { dry_run = true; continue; @@ -334,6 +346,52 @@ int main(int argc, char* argv[]) { std::cerr << "error: no package name specified\n"; return 1; } + + // Parse --features key=on,key2=off + std::unordered_map features; + if (features_arg != nullptr) { + std::string_view fsv(features_arg); + std::size_t pos = 0; + while (pos < fsv.size()) { + auto comma = fsv.find(',', pos); + auto pair = fsv.substr(pos, comma == std::string_view::npos + ? std::string_view::npos + : comma - pos); + auto eq = pair.find('='); + if (eq != std::string_view::npos) { + auto key = std::string(pair.substr(0, eq)); + auto val = pair.substr(eq + 1); + while (!key.empty() && key.back() == ' ') key.pop_back(); + while (!val.empty() && val.front() == ' ') val.remove_prefix(1); + features[key] = {val == "on" || val == "true" || val == "1", + false, ""}; + } + pos = comma == std::string_view::npos ? fsv.size() : comma + 1; + } + } + + // Parse --config key=val,key2=val2 + std::unordered_map config; + if (config_arg != nullptr) { + std::string_view csv(config_arg); + std::size_t pos = 0; + while (pos < csv.size()) { + auto comma = csv.find(',', pos); + auto pair = csv.substr(pos, comma == std::string_view::npos + ? std::string_view::npos + : comma - pos); + auto eq = pair.find('='); + if (eq != std::string_view::npos) { + auto key = std::string(pair.substr(0, eq)); + auto val = std::string(pair.substr(eq + 1)); + while (!key.empty() && key.back() == ' ') key.pop_back(); + while (!val.empty() && val.front() == ' ') val.erase(0, 1); + config[key] = val; + } + pos = comma == std::string_view::npos ? csv.size() : comma + 1; + } + } + try { auto config_path = std::filesystem::path(paths::system_dir()) / "config.kap"; dsl::SystemConfig cfg; @@ -347,10 +405,21 @@ int main(int argc, char* argv[]) { for (auto& p : cfg.packages) { if (p.name == file_arg) { found = true; + bool changed = false; if (version_arg != nullptr) { p.version = version_arg; - std::cout << "updated " << file_arg - << " → version " << version_arg << "\n"; + changed = true; + } + if (!features.empty()) { + for (auto& [k, v] : features) { p.features[k] = v; changed = true; } + } + if (!config.empty()) { + for (auto& [k, v] : config) { p.config[k] = v; changed = true; } + } + if (changed) { + std::cout << "updated " << file_arg; + if (version_arg != nullptr) std::cout << " → " << version_arg; + std::cout << "\n"; } else { std::cout << file_arg << " already in packages\n"; } @@ -364,11 +433,11 @@ int main(int argc, char* argv[]) { if (version_arg != nullptr) { pref.version = version_arg; } + pref.features = std::move(features); + pref.config = std::move(config); cfg.packages.push_back(std::move(pref)); std::cout << "added " << file_arg; - if (version_arg != nullptr) { - std::cout << " " << version_arg; - } + if (version_arg != nullptr) std::cout << " " << version_arg; std::cout << "\n"; }