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";
}