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.
This commit is contained in:
+74
-5
@@ -54,6 +54,8 @@ Subcommands:
|
|||||||
rollback Show available generations
|
rollback Show available generations
|
||||||
index <dir> Build an index.kap from .kap files in a directory
|
index <dir> Build an index.kap from .kap files in a directory
|
||||||
add <pkg> [v] Add a package to system config (optional version)
|
add <pkg> [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 <pkg> Remove a package from system config
|
remove <pkg> Remove a package from system config
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@@ -232,6 +234,8 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
const char* file_arg = nullptr;
|
const char* file_arg = nullptr;
|
||||||
const char* version_arg = nullptr;
|
const char* version_arg = nullptr;
|
||||||
|
const char* features_arg = nullptr;
|
||||||
|
const char* config_arg = nullptr;
|
||||||
bool dry_run = false;
|
bool dry_run = false;
|
||||||
for (int i = arg_start + 1; i < argc; ++i) {
|
for (int i = arg_start + 1; i < argc; ++i) {
|
||||||
if (std::string_view(argv[i]) == "-h"
|
if (std::string_view(argv[i]) == "-h"
|
||||||
@@ -254,6 +258,14 @@ int main(int argc, char* argv[]) {
|
|||||||
paths::set_root(argv[++i]);
|
paths::set_root(argv[++i]);
|
||||||
continue;
|
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") {
|
if (std::string_view(argv[i]) == "--dry-run") {
|
||||||
dry_run = true;
|
dry_run = true;
|
||||||
continue;
|
continue;
|
||||||
@@ -334,6 +346,52 @@ int main(int argc, char* argv[]) {
|
|||||||
std::cerr << "error: no package name specified\n";
|
std::cerr << "error: no package name specified\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse --features key=on,key2=off
|
||||||
|
std::unordered_map<std::string, dsl::FeatureDef> 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<std::string, std::string> 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 {
|
try {
|
||||||
auto config_path = std::filesystem::path(paths::system_dir()) / "config.kap";
|
auto config_path = std::filesystem::path(paths::system_dir()) / "config.kap";
|
||||||
dsl::SystemConfig cfg;
|
dsl::SystemConfig cfg;
|
||||||
@@ -347,10 +405,21 @@ int main(int argc, char* argv[]) {
|
|||||||
for (auto& p : cfg.packages) {
|
for (auto& p : cfg.packages) {
|
||||||
if (p.name == file_arg) {
|
if (p.name == file_arg) {
|
||||||
found = true;
|
found = true;
|
||||||
|
bool changed = false;
|
||||||
if (version_arg != nullptr) {
|
if (version_arg != nullptr) {
|
||||||
p.version = version_arg;
|
p.version = version_arg;
|
||||||
std::cout << "updated " << file_arg
|
changed = true;
|
||||||
<< " → version " << version_arg << "\n";
|
}
|
||||||
|
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 {
|
} else {
|
||||||
std::cout << file_arg << " already in packages\n";
|
std::cout << file_arg << " already in packages\n";
|
||||||
}
|
}
|
||||||
@@ -364,11 +433,11 @@ int main(int argc, char* argv[]) {
|
|||||||
if (version_arg != nullptr) {
|
if (version_arg != nullptr) {
|
||||||
pref.version = version_arg;
|
pref.version = version_arg;
|
||||||
}
|
}
|
||||||
|
pref.features = std::move(features);
|
||||||
|
pref.config = std::move(config);
|
||||||
cfg.packages.push_back(std::move(pref));
|
cfg.packages.push_back(std::move(pref));
|
||||||
std::cout << "added " << file_arg;
|
std::cout << "added " << file_arg;
|
||||||
if (version_arg != nullptr) {
|
if (version_arg != nullptr) std::cout << " " << version_arg;
|
||||||
std::cout << " " << version_arg;
|
|
||||||
}
|
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user