feat: add kappa add and kappa remove subcommands
- kappa add <pkg> [version] — adds/updates package in system config
packages{} block; creates config if it doesn't exist
- kappa remove <pkg> — removes package from config; idempotent
(no error if package isn't present)
- Supports --root flag for custom KAPPA_ROOT
- User workflow: kappa add make && kappa rebuild
No manual config editing needed.
This commit is contained in:
+108
-3
@@ -53,6 +53,8 @@ Subcommands:
|
||||
list List installed packages
|
||||
rollback Show available generations
|
||||
index <dir> Build an index.kap from .kap files in a directory
|
||||
add <pkg> [v] Add a package to system config (optional version)
|
||||
remove <pkg> Remove a package from system config
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message
|
||||
@@ -218,7 +220,9 @@ int main(int argc, char* argv[]) {
|
||||
|| (subcommand == "list")
|
||||
|| (subcommand == "fetch-package")
|
||||
|| (subcommand == "rollback")
|
||||
|| (subcommand == "index");
|
||||
|| (subcommand == "index")
|
||||
|| (subcommand == "add")
|
||||
|| (subcommand == "remove");
|
||||
|
||||
if (!valid_subcommand) {
|
||||
std::cerr << "error: unknown subcommand '" << subcommand << "'\n\n";
|
||||
@@ -227,6 +231,7 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
const char* file_arg = nullptr;
|
||||
const char* version_arg = nullptr;
|
||||
bool dry_run = false;
|
||||
for (int i = arg_start + 1; i < argc; ++i) {
|
||||
if (std::string_view(argv[i]) == "-h"
|
||||
@@ -254,8 +259,12 @@ int main(int argc, char* argv[]) {
|
||||
continue;
|
||||
}
|
||||
if (!is_flag(argv[i])) {
|
||||
file_arg = argv[i];
|
||||
break;
|
||||
if (file_arg == nullptr) {
|
||||
file_arg = argv[i];
|
||||
} else if (version_arg == nullptr) {
|
||||
version_arg = argv[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,6 +329,102 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (subcommand == "add") {
|
||||
if (file_arg == nullptr) {
|
||||
std::cerr << "error: no package name specified\n";
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
auto config_path = std::filesystem::path(paths::system_dir()) / "config.kap";
|
||||
dsl::SystemConfig cfg;
|
||||
|
||||
if (std::filesystem::exists(config_path)) {
|
||||
auto src = read_file(config_path.c_str());
|
||||
cfg = dsl::parse_system_config(src);
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (auto& p : cfg.packages) {
|
||||
if (p.name == file_arg) {
|
||||
found = true;
|
||||
if (version_arg != nullptr) {
|
||||
p.version = version_arg;
|
||||
std::cout << "updated " << file_arg
|
||||
<< " → version " << version_arg << "\n";
|
||||
} else {
|
||||
std::cout << file_arg << " already in packages\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
dsl::PackageRef pref;
|
||||
pref.name = file_arg;
|
||||
if (version_arg != nullptr) {
|
||||
pref.version = version_arg;
|
||||
}
|
||||
cfg.packages.push_back(std::move(pref));
|
||||
std::cout << "added " << file_arg;
|
||||
if (version_arg != nullptr) {
|
||||
std::cout << " " << version_arg;
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(paths::system_dir(), ec);
|
||||
std::ofstream out(config_path);
|
||||
if (!out) {
|
||||
std::cerr << "error: cannot write " << config_path.string() << "\n";
|
||||
return 1;
|
||||
}
|
||||
tools::format_config(out, cfg);
|
||||
return 0;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "add error: " << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (subcommand == "remove") {
|
||||
if (file_arg == nullptr) {
|
||||
std::cerr << "error: no package name specified\n";
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
auto config_path = std::filesystem::path(paths::system_dir()) / "config.kap";
|
||||
if (!std::filesystem::exists(config_path)) {
|
||||
std::cout << file_arg << " not found (no config)\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto src = read_file(config_path.c_str());
|
||||
auto cfg = dsl::parse_system_config(src);
|
||||
|
||||
auto it = std::remove_if(cfg.packages.begin(), cfg.packages.end(),
|
||||
[&](const dsl::PackageRef& p) { return p.name == file_arg; });
|
||||
|
||||
if (it == cfg.packages.end()) {
|
||||
std::cout << file_arg << " not in packages\n";
|
||||
return 0;
|
||||
}
|
||||
cfg.packages.erase(it, cfg.packages.end());
|
||||
std::cout << "removed " << file_arg << "\n";
|
||||
|
||||
std::ofstream out(config_path);
|
||||
if (!out) {
|
||||
std::cerr << "error: cannot write " << config_path.string() << "\n";
|
||||
return 1;
|
||||
}
|
||||
tools::format_config(out, cfg);
|
||||
return 0;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "remove error: " << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (subcommand == "fetch-package") {
|
||||
if (file_arg == nullptr) {
|
||||
std::cerr << "error: no package name specified\n";
|
||||
|
||||
Reference in New Issue
Block a user