From 938f4ac323f60978410f51ea5763e3845b3bd7f4 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 20 Jul 2025 17:19:17 +1200 Subject: [PATCH] docs: Update 2 files --- .kiro/specs/multi-server-support/tasks.md | 20 ++- getpkg/src/main.cpp | 202 ++++++++++++++++++++++ 2 files changed, 219 insertions(+), 3 deletions(-) diff --git a/.kiro/specs/multi-server-support/tasks.md b/.kiro/specs/multi-server-support/tasks.md index 839b321..a6b7599 100644 --- a/.kiro/specs/multi-server-support/tasks.md +++ b/.kiro/specs/multi-server-support/tasks.md @@ -58,7 +58,13 @@ Based on analysis of the current codebase, the multi-server support feature need - Add migration error handling and rollback capabilities - _Requirements: 4.4, 4.5, 6.1, 6.2, 6.3, 6.5_ -- [ ] 5. Ensure backward compatibility +- [x] 5. Ensure backward compatibility + + + + + + - Implement default server configuration (getpkg.xyz) when no config exists - Maintain existing CLI behavior for users without custom server configuration - Preserve existing token storage location compatibility @@ -67,14 +73,22 @@ Based on analysis of the current codebase, the multi-server support feature need ## CLI Integration Tasks -- [ ] 6. Add server management commands to main.cpp +- [x] 6. Add server management commands to main.cpp + + + + + - Implement `getpkg server add ` command - Implement `getpkg server remove ` command - Implement `getpkg server list` command - Add server URL validation and user feedback - _Requirements: 1.1, 1.2, 1.3_ -- [ ] 7. Update existing commands for multi-server support +- [-] 7. Update existing commands for multi-server support + + + - Modify install command to use ServerManager and multi-server GetbinClient - Update publish command to support --server option and default server selection - Update unpublish command to support --server option and default server selection diff --git a/getpkg/src/main.cpp b/getpkg/src/main.cpp index 3e2649f..b1c60e1 100644 --- a/getpkg/src/main.cpp +++ b/getpkg/src/main.cpp @@ -58,6 +58,7 @@ #include "DropshellScriptManager.hpp" #include "GetbinClient.hpp" #include "MigrationManager.hpp" +#include "ServerManager.hpp" #include "archive_tgz.hpp" #include "hash.hpp" #include @@ -1128,6 +1129,15 @@ void show_help() { std::cout << " clean Clean up orphaned configs and symlinks" << std::endl; std::cout << " Removes unused config files and dangling symlinks" << std::endl; std::cout << std::endl; + std::cout << " server add Add a new package server" << std::endl; + std::cout << " Adds a server to the configuration for package discovery" << std::endl; + std::cout << std::endl; + std::cout << " server remove Remove a package server" << std::endl; + std::cout << " Removes a server from the configuration" << std::endl; + std::cout << std::endl; + std::cout << " server list List all configured servers" << std::endl; + std::cout << " Shows all servers with their status and write token info" << std::endl; + std::cout << std::endl; std::cout << " version Show getpkg version" << std::endl; std::cout << std::endl; std::cout << " help Show this help message" << std::endl; @@ -1141,6 +1151,9 @@ void show_help() { std::cout << " getpkg unpublish myapp:x86_64 Remove only x86_64 version" << std::endl; std::cout << " getpkg uninstall myapp Remove myapp from system" << std::endl; std::cout << " getpkg update Update everything" << std::endl; + std::cout << " getpkg server add packages.example.com Add a custom package server" << std::endl; + std::cout << " getpkg server remove packages.example.com Remove a package server" << std::endl; + std::cout << " getpkg server list List all configured servers" << std::endl; std::cout << std::endl; std::cout << "ENVIRONMENT:" << std::endl; std::cout << " SOS_WRITE_TOKEN Auth token for publishing tools" << std::endl; @@ -1151,6 +1164,163 @@ void show_help() { std::cout << " ~/.local/bin/getpkg/ Installed tool binaries" << std::endl; } +int server_command(int argc, char* argv[]) { + if (argc < 3) { + std::cerr << "Usage: getpkg server [args...]" << std::endl; + std::cerr << " getpkg server add Add a new server" << std::endl; + std::cerr << " getpkg server remove Remove a server" << std::endl; + std::cerr << " getpkg server list List all configured servers" << std::endl; + return 1; + } + + std::string subcommand = argv[2]; + ServerManager serverManager; + + // Load existing configuration + if (!serverManager.loadConfiguration()) { + std::cerr << "Failed to load server configuration" << std::endl; + return 1; + } + + if (subcommand == "add") { + if (argc < 4) { + std::cerr << "Usage: getpkg server add " << std::endl; + return 1; + } + + std::string serverUrl = argv[3]; + + // Validate server URL format + if (serverUrl.empty()) { + std::cerr << "Error: Server URL cannot be empty" << std::endl; + return 1; + } + + // Remove protocol if provided (we'll add it internally) + if (serverUrl.find("http://") == 0) { + serverUrl = serverUrl.substr(7); + } else if (serverUrl.find("https://") == 0) { + serverUrl = serverUrl.substr(8); + } + + // Remove trailing slash if present + if (!serverUrl.empty() && serverUrl.back() == '/') { + serverUrl.pop_back(); + } + + std::cout << "Adding server: " << serverUrl << std::endl; + + if (serverManager.addServer(serverUrl)) { + std::cout << "Successfully added server: " << serverUrl << std::endl; + + // Ask if user wants to add a write token + std::cout << "Would you like to add a write token for this server? (y/N): "; + std::string response; + std::getline(std::cin, response); + + if (response == "y" || response == "Y" || response == "yes" || response == "Yes") { + std::cout << "Enter write token for " << serverUrl << ": "; + std::string token; + std::getline(std::cin, token); + + if (!token.empty()) { + if (serverManager.setWriteToken(serverUrl, token)) { + std::cout << "Write token added successfully" << std::endl; + } else { + std::cerr << "Failed to save write token" << std::endl; + } + } + } + + return 0; + } else { + std::cerr << "Failed to add server: " << serverUrl << std::endl; + return 1; + } + + } else if (subcommand == "remove") { + if (argc < 4) { + std::cerr << "Usage: getpkg server remove " << std::endl; + return 1; + } + + std::string serverUrl = argv[3]; + + // Remove protocol if provided + if (serverUrl.find("http://") == 0) { + serverUrl = serverUrl.substr(7); + } else if (serverUrl.find("https://") == 0) { + serverUrl = serverUrl.substr(8); + } + + // Remove trailing slash if present + if (!serverUrl.empty() && serverUrl.back() == '/') { + serverUrl.pop_back(); + } + + std::cout << "Removing server: " << serverUrl << std::endl; + + if (serverManager.removeServer(serverUrl)) { + std::cout << "Successfully removed server: " << serverUrl << std::endl; + return 0; + } else { + std::cerr << "Failed to remove server: " << serverUrl << std::endl; + return 1; + } + + } else if (subcommand == "list") { + std::vector servers = serverManager.getServers(); + + if (servers.empty()) { + std::cout << "No servers configured" << std::endl; + return 0; + } + + std::cout << std::endl; + std::cout << "Configured servers:" << std::endl; + std::cout << "+" << std::string(30, '-') << "+" << std::string(12, '-') << "+" << std::string(15, '-') << "+" << std::endl; + std::cout << "|" << std::setw(30) << std::left << " Server URL" + << "|" << std::setw(12) << std::left << " Default" + << "|" << std::setw(15) << std::left << " Write Token" + << "|" << std::endl; + std::cout << "+" << std::string(30, '-') << "+" << std::string(12, '-') << "+" << std::string(15, '-') << "+" << std::endl; + + std::string defaultServer = serverManager.getDefaultServer(); + + for (const auto& server : servers) { + bool isDefault = (server == defaultServer); + bool hasToken = serverManager.hasWriteToken(server); + + std::string displayUrl = server; + if (displayUrl.length() > 29) { + displayUrl = displayUrl.substr(0, 26) + "..."; + } + + std::cout << "|" << std::setw(30) << std::left << (" " + displayUrl) + << "|" << std::setw(12) << std::left << (isDefault ? " Yes" : " No") + << "|" << std::setw(15) << std::left << (hasToken ? " Yes" : " No") + << "|" << std::endl; + } + + std::cout << "+" << std::string(30, '-') << "+" << std::string(12, '-') << "+" << std::string(15, '-') << "+" << std::endl; + std::cout << std::endl; + std::cout << "Total servers: " << servers.size() << std::endl; + + // Show default publish server if different from default + std::string defaultPublishServer = serverManager.getDefaultPublishServer(); + if (defaultPublishServer != defaultServer) { + std::cout << "Default publish server: " << defaultPublishServer << std::endl; + } + + return 0; + + } else { + std::cerr << "Unknown server subcommand: " << subcommand << std::endl; + std::cerr << "Use 'getpkg server' for usage information." << std::endl; + return 1; + } +} + int autocomplete_command(int argc, char* argv[]) { std::vector args(argv + 2, argv + argc); @@ -1166,6 +1336,7 @@ int autocomplete_command(int argc, char* argv[]) { std::cout << "hash\n"; std::cout << "list\n"; std::cout << "clean\n"; + std::cout << "server\n"; std::cout << "help\n"; return 0; } @@ -1180,6 +1351,35 @@ int autocomplete_command(int argc, char* argv[]) { } else if (subcommand == "uninstall") { // For uninstall, list installed tools std::filesystem::path configDir = std::filesystem::path(std::getenv("HOME")) / ".config" / "getpkg"; + if (std::filesystem::exists(configDir)) { + for (const auto& entry : std::filesystem::directory_iterator(configDir)) { + if (entry.path().extension() == ".json") { + std::cout << entry.path().stem().string() << "\n"; + } + } + } + return 0; + } else if (subcommand == "server") { + // Handle server subcommand autocompletion + if (args.size() == 1) { + // Show server subcommands + std::cout << "add\n"; + std::cout << "remove\n"; + std::cout << "list\n"; + } else if (args.size() == 2 && args[1] == "remove") { + // For server remove, list configured servers + ServerManager serverManager; + if (serverManager.loadConfiguration()) { + std::vector servers = serverManager.getServers(); + for (const auto& server : servers) { + std::cout << server << "\n"; + } + } + } + return 0; + } else if (subcommand == "unpublish") { + // For unpublish, we could suggest installed tools + std::filesystem::path configDir = std::filesystem::path(std::getenv("HOME")) / ".config" / "getpkg"; if (std::filesystem::exists(configDir)) { for (const auto& entry : std::filesystem::directory_iterator(configDir)) { if (entry.path().extension() == ".json") { @@ -1327,6 +1527,8 @@ int main(int argc, char* argv[]) { return list_packages(argc, argv); } else if (command == "clean") { return clean_tool(argc, argv); + } else if (command == "server") { + return server_command(argc, argv); } else if (command == "help") { show_help(); } else {