diff --git a/getpkg/src/main.cpp b/getpkg/src/main.cpp index 03dd541..1e2a469 100644 --- a/getpkg/src/main.cpp +++ b/getpkg/src/main.cpp @@ -326,75 +326,163 @@ int update_tool(int argc, char* argv[]) { std::string home = get_home(); std::filesystem::path configDir = std::filesystem::path(home) / ".config/getpkg"; - // Collect all installed tools - std::vector> updateResults; // name, status, version - - // Capture stdout to process install_tool output - auto processToolUpdate = [&](const std::string& toolName) -> std::tuple { - // Redirect stdout and stderr to capture output - std::stringstream buffer; - std::stringstream errBuffer; - std::streambuf* oldOut = std::cout.rdbuf(buffer.rdbuf()); - std::streambuf* oldErr = std::cerr.rdbuf(errBuffer.rdbuf()); - - char* toolArgv[] = {argv[0], (char*)"install", (char*)toolName.c_str()}; - int result = install_tool(3, toolArgv); - - // Restore stdout and stderr - std::cout.rdbuf(oldOut); - std::cerr.rdbuf(oldErr); - - std::string output = buffer.str(); - std::string status = "Failed"; - std::string version = "-"; - - if (result == 0) { - if (output.find("is already up to date") != std::string::npos) { - status = "Up to date"; - } else if (output.find("Installed " + toolName + " successfully") != std::string::npos) { - // Check if it was an update or fresh install - if (output.find("Updating " + toolName) != std::string::npos) { - status = "Updated"; - } else { - status = "Installed"; - } - } - - // Try to get version from config - std::filesystem::path toolInfoPath = configDir / (toolName + ".json"); - if (std::filesystem::exists(toolInfoPath)) { - std::ifstream tfile(toolInfoPath); - json toolInfo; - tfile >> toolInfo; - version = toolInfo.value("version", "-"); - if (!version.empty() && version.back() == '\n') version.pop_back(); - // If version is empty, try to show something useful - if (version.empty() || version == "-") { - version = "installed"; - } - } - } - - return std::make_tuple(status, version); + // Structure to hold tool information + struct ToolInfo { + std::string name; + std::string localHash; + std::string remoteHash; + std::string arch; + std::string version; + bool needsUpdate = false; + std::string status = "Up to date"; }; - // First update getpkg itself - auto [getpkgStatus, getpkgVersion] = processToolUpdate("getpkg"); - updateResults.push_back(std::make_tuple("getpkg", getpkgStatus, getpkgVersion)); + std::vector tools; - // Then update all other installed tools + // Collect all installed tools if (std::filesystem::exists(configDir)) { for (const auto& entry : std::filesystem::directory_iterator(configDir)) { if (entry.path().extension() == ".json") { std::string tname = entry.path().stem(); - if (tname != "getpkg") { // Skip getpkg since we already did it - auto [status, version] = processToolUpdate(tname); - updateResults.push_back(std::make_tuple(tname, status, version)); + + ToolInfo tool; + tool.name = tname; + + // Read local tool info + std::ifstream tfile(entry.path()); + if (tfile.good()) { + json toolInfo; + tfile >> toolInfo; + tool.localHash = toolInfo.value("hash", ""); + tool.arch = toolInfo.value("arch", get_arch()); + tool.version = toolInfo.value("version", "-"); + if (!tool.version.empty() && tool.version.back() == '\n') { + tool.version.pop_back(); + } + if (tool.version.empty() || tool.version == "-") { + tool.version = "installed"; + } + } + + tools.push_back(tool); + } + } + } + + if (tools.empty()) { + std::cout << "No tools installed." << std::endl; + return 0; + } + + // Step 1: Check for updates (with progress) + std::cout << "Checking " << tools.size() << " tools for updates..." << std::endl; + + GetbinClient getbin; + for (size_t i = 0; i < tools.size(); ++i) { + auto& tool = tools[i]; + + // Show progress + std::cout << "\r[" << (i + 1) << "/" << tools.size() << "] Checking " << tool.name << "..." << std::flush; + + // Check remote hash + std::string remoteHash; + if (getbin.getHash(tool.name, tool.arch, remoteHash) && !remoteHash.empty()) { + tool.remoteHash = remoteHash; + if (tool.localHash != remoteHash) { + tool.needsUpdate = true; + tool.status = "Needs update"; + } + } else { + tool.status = "Check failed"; + } + } + std::cout << "\r" << std::string(50, ' ') << "\r" << std::flush; // Clear progress line + + // Step 2: Update tools that need updating + std::vector> updateResults; + + // First update getpkg if it needs updating + auto getpkgIt = std::find_if(tools.begin(), tools.end(), + [](const ToolInfo& t) { return t.name == "getpkg"; }); + + if (getpkgIt != tools.end() && getpkgIt->needsUpdate) { + std::cout << "Updating getpkg..." << std::flush; + + // Use install_tool for actual update + std::stringstream buffer, errBuffer; + std::streambuf* oldOut = std::cout.rdbuf(buffer.rdbuf()); + std::streambuf* oldErr = std::cerr.rdbuf(errBuffer.rdbuf()); + + char* toolArgv[] = {argv[0], (char*)"install", (char*)"getpkg"}; + int result = install_tool(3, toolArgv); + + std::cout.rdbuf(oldOut); + std::cerr.rdbuf(oldErr); + + if (result == 0) { + getpkgIt->status = "Updated"; + std::cout << " Updated" << std::endl; + } else { + getpkgIt->status = "Failed"; + std::cout << " Failed" << std::endl; + } + } + + // Update other tools + int toolsToUpdate = std::count_if(tools.begin(), tools.end(), + [](const ToolInfo& t) { return t.needsUpdate && t.name != "getpkg"; }); + + if (toolsToUpdate > 0) { + std::cout << "Updating " << toolsToUpdate << " tools..." << std::endl; + + int updatedCount = 0; + for (auto& tool : tools) { + if (tool.needsUpdate && tool.name != "getpkg") { + updatedCount++; + std::cout << "[" << updatedCount << "/" << toolsToUpdate << "] Updating " << tool.name << "..." << std::flush; + + // Use install_tool for actual update + std::stringstream buffer, errBuffer; + std::streambuf* oldOut = std::cout.rdbuf(buffer.rdbuf()); + std::streambuf* oldErr = std::cerr.rdbuf(errBuffer.rdbuf()); + + char* toolArgv[] = {argv[0], (char*)"install", (char*)tool.name.c_str()}; + int result = install_tool(3, toolArgv); + + std::cout.rdbuf(oldOut); + std::cerr.rdbuf(oldErr); + + if (result == 0) { + tool.status = "Updated"; + std::cout << " Updated" << std::endl; + + // Re-read version after update + std::filesystem::path toolInfoPath = configDir / (tool.name + ".json"); + if (std::filesystem::exists(toolInfoPath)) { + std::ifstream tfile(toolInfoPath); + json toolInfo; + tfile >> toolInfo; + tool.version = toolInfo.value("version", tool.version); + if (!tool.version.empty() && tool.version.back() == '\n') { + tool.version.pop_back(); + } + if (tool.version.empty() || tool.version == "-") { + tool.version = "installed"; + } + } + } else { + tool.status = "Failed"; + std::cout << " Failed" << std::endl; } } } } + // Prepare results for display + for (const auto& tool : tools) { + updateResults.push_back(std::make_tuple(tool.name, tool.status, tool.version)); + } + // Display results in a table std::cout << std::endl; std::cout << "+" << std::string(25, '-') << "+" << std::string(15, '-') << "+" << std::string(20, '-') << "+" << std::endl;