|
|
@ -165,25 +165,47 @@ int install_tool(int argc, char* argv[]) {
|
|
|
|
std::filesystem::path configDir = std::filesystem::path(home) / ".config/getpkg";
|
|
|
|
std::filesystem::path configDir = std::filesystem::path(home) / ".config/getpkg";
|
|
|
|
std::filesystem::path binDir = std::filesystem::path(home) / ".getpkg" / toolName;
|
|
|
|
std::filesystem::path binDir = std::filesystem::path(home) / ".getpkg" / toolName;
|
|
|
|
std::filesystem::path archivePath = tempDir.path() / (toolName + ".tgz");
|
|
|
|
std::filesystem::path archivePath = tempDir.path() / (toolName + ".tgz");
|
|
|
|
std::filesystem::path toolInfoPath = configDir / (toolName + ".json");
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize ServerManager and get server list
|
|
|
|
|
|
|
|
ServerManager serverManager;
|
|
|
|
|
|
|
|
if (!serverManager.loadConfiguration()) {
|
|
|
|
|
|
|
|
std::cerr << "Failed to load server configuration" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> servers = serverManager.getServers();
|
|
|
|
|
|
|
|
if (servers.empty()) {
|
|
|
|
|
|
|
|
std::cerr << "No servers configured" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize PackageMetadataManager
|
|
|
|
|
|
|
|
PackageMetadataManager packageManager(configDir);
|
|
|
|
|
|
|
|
if (!packageManager.ensurePackagesDirectory()) {
|
|
|
|
|
|
|
|
std::cerr << "Failed to create packages directory" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Check if tool needs update or install
|
|
|
|
// Check if tool needs update or install
|
|
|
|
if (std::filesystem::exists(toolInfoPath)) {
|
|
|
|
bool isUpdate = false;
|
|
|
|
|
|
|
|
PackageMetadata existingMetadata;
|
|
|
|
|
|
|
|
if (packageManager.packageExists(toolName)) {
|
|
|
|
// Tool exists, check if update needed
|
|
|
|
// Tool exists, check if update needed
|
|
|
|
std::ifstream tfile(toolInfoPath);
|
|
|
|
existingMetadata = packageManager.loadPackageMetadata(toolName);
|
|
|
|
json toolInfo;
|
|
|
|
if (!existingMetadata.isValid()) {
|
|
|
|
tfile >> toolInfo;
|
|
|
|
std::cerr << "Warning: Invalid existing package metadata for " << toolName << std::endl;
|
|
|
|
tfile.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string localHash = toolInfo.value("hash", "");
|
|
|
|
std::string localHash = existingMetadata.hash;
|
|
|
|
std::string localArch = toolInfo.value("arch", arch);
|
|
|
|
std::string localArch = existingMetadata.arch.empty() ? arch : existingMetadata.arch;
|
|
|
|
|
|
|
|
|
|
|
|
// Get remote hash to compare - use the same arch that was originally installed
|
|
|
|
// Get remote hash to compare - use multi-server GetbinClient
|
|
|
|
GetbinClient getbin;
|
|
|
|
GetbinClient getbin(servers);
|
|
|
|
std::string remoteHash;
|
|
|
|
std::string remoteHash;
|
|
|
|
if (getbin.getHash(toolName, localArch, remoteHash) && !remoteHash.empty()) {
|
|
|
|
if (getbin.getHash(toolName, localArch, remoteHash) && !remoteHash.empty()) {
|
|
|
|
if (localHash != remoteHash) {
|
|
|
|
if (localHash != remoteHash) {
|
|
|
|
std::cout << "Updating " << toolName << "..." << std::endl;
|
|
|
|
std::cout << "Updating " << toolName << "..." << std::endl;
|
|
|
|
|
|
|
|
isUpdate = true;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
std::cout << toolName << " is already up to date." << std::endl;
|
|
|
|
std::cout << toolName << " is already up to date." << std::endl;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
@ -191,6 +213,7 @@ int install_tool(int argc, char* argv[]) {
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// If we can't get remote hash, assume update is needed
|
|
|
|
// If we can't get remote hash, assume update is needed
|
|
|
|
std::cout << "Updating " << toolName << "..." << std::endl;
|
|
|
|
std::cout << "Updating " << toolName << "..." << std::endl;
|
|
|
|
|
|
|
|
isUpdate = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
std::cout << "Installing " << toolName << "..." << std::endl;
|
|
|
|
std::cout << "Installing " << toolName << "..." << std::endl;
|
|
|
@ -210,9 +233,10 @@ int install_tool(int argc, char* argv[]) {
|
|
|
|
if (std::filesystem::exists(binDir))
|
|
|
|
if (std::filesystem::exists(binDir))
|
|
|
|
std::filesystem::remove_all(binDir);
|
|
|
|
std::filesystem::remove_all(binDir);
|
|
|
|
|
|
|
|
|
|
|
|
// Download tool - try arch-specific version first, then universal fallback
|
|
|
|
// Download tool using multi-server GetbinClient - try arch-specific version first, then universal fallback
|
|
|
|
GetbinClient getbin2;
|
|
|
|
GetbinClient getbin2(servers);
|
|
|
|
std::string downloadArch = arch;
|
|
|
|
std::string downloadArch = arch;
|
|
|
|
|
|
|
|
std::string sourceServer;
|
|
|
|
|
|
|
|
|
|
|
|
// Progress callback for downloads
|
|
|
|
// Progress callback for downloads
|
|
|
|
auto progressCallback = [&toolName](size_t downloaded, size_t total) -> bool {
|
|
|
|
auto progressCallback = [&toolName](size_t downloaded, size_t total) -> bool {
|
|
|
@ -237,6 +261,12 @@ int install_tool(int argc, char* argv[]) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clearAndPrint("Downloading " + toolName + "... done\n");
|
|
|
|
clearAndPrint("Downloading " + toolName + "... done\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Find which server provided the package
|
|
|
|
|
|
|
|
if (!getbin2.findPackageServer(toolName, downloadArch, sourceServer)) {
|
|
|
|
|
|
|
|
// Fallback to first server if we can't determine the source
|
|
|
|
|
|
|
|
sourceServer = servers[0];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Unpack tool
|
|
|
|
// Unpack tool
|
|
|
|
std::cout << "Unpacking..." << std::flush;
|
|
|
|
std::cout << "Unpacking..." << std::flush;
|
|
|
|
if (!common::unpack_tgz(archivePath.string(), binDir.string())) {
|
|
|
|
if (!common::unpack_tgz(archivePath.string(), binDir.string())) {
|
|
|
@ -272,16 +302,11 @@ int install_tool(int argc, char* argv[]) {
|
|
|
|
std::cerr << "Warning: Failed to get version for " << toolName << std::endl;
|
|
|
|
std::cerr << "Warning: Failed to get version for " << toolName << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Save tool info
|
|
|
|
// Create and save enhanced package metadata
|
|
|
|
json toolInfo = {
|
|
|
|
PackageMetadata metadata(toolName, version, hash, downloadArch, sourceServer);
|
|
|
|
{"name", toolName},
|
|
|
|
if (!packageManager.savePackageMetadata(metadata)) {
|
|
|
|
{"version", version},
|
|
|
|
std::cerr << "Warning: Failed to save package metadata for " << toolName << std::endl;
|
|
|
|
{"hash", hash},
|
|
|
|
}
|
|
|
|
{"arch", downloadArch}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
std::ofstream toolInfoFile(toolInfoPath);
|
|
|
|
|
|
|
|
toolInfoFile << toolInfo.dump(2);
|
|
|
|
|
|
|
|
toolInfoFile.close();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Run setup script if exists
|
|
|
|
// Run setup script if exists
|
|
|
|
std::filesystem::path setupScriptPath = binDir / "setup_script.sh";
|
|
|
|
std::filesystem::path setupScriptPath = binDir / "setup_script.sh";
|
|
|
@ -297,11 +322,27 @@ int install_tool(int argc, char* argv[]) {
|
|
|
|
|
|
|
|
|
|
|
|
int publish_tool(int argc, char* argv[]) {
|
|
|
|
int publish_tool(int argc, char* argv[]) {
|
|
|
|
if (argc < 4) {
|
|
|
|
if (argc < 4) {
|
|
|
|
std::cerr << "Usage: getpkg publish <tool_name:ARCH> <folder>" << std::endl;
|
|
|
|
std::cerr << "Usage: getpkg publish [--server <url>] <tool_name:ARCH> <folder>" << std::endl;
|
|
|
|
|
|
|
|
std::cerr << " getpkg publish <tool_name:ARCH> <folder>" << std::endl;
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::string labeltag = argv[2];
|
|
|
|
|
|
|
|
std::string folder = argv[3];
|
|
|
|
// Parse arguments for --server option
|
|
|
|
|
|
|
|
std::string targetServer;
|
|
|
|
|
|
|
|
std::string labeltag;
|
|
|
|
|
|
|
|
std::string folder;
|
|
|
|
|
|
|
|
int argIndex = 2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (argc >= 5 && std::string(argv[2]) == "--server") {
|
|
|
|
|
|
|
|
targetServer = argv[3];
|
|
|
|
|
|
|
|
labeltag = argv[4];
|
|
|
|
|
|
|
|
folder = argv[5];
|
|
|
|
|
|
|
|
argIndex = 5;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
labeltag = argv[2];
|
|
|
|
|
|
|
|
folder = argv[3];
|
|
|
|
|
|
|
|
argIndex = 3;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If no ARCH is provided (no colon in labeltag), append ":universal" for cross-platform tools
|
|
|
|
// If no ARCH is provided (no colon in labeltag), append ":universal" for cross-platform tools
|
|
|
|
if (labeltag.find(':') == std::string::npos) {
|
|
|
|
if (labeltag.find(':') == std::string::npos) {
|
|
|
@ -316,6 +357,49 @@ int publish_tool(int argc, char* argv[]) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize ServerManager
|
|
|
|
|
|
|
|
ServerManager serverManager;
|
|
|
|
|
|
|
|
if (!serverManager.loadConfiguration()) {
|
|
|
|
|
|
|
|
std::cerr << "Failed to load server configuration" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Determine target server
|
|
|
|
|
|
|
|
std::string publishServer;
|
|
|
|
|
|
|
|
if (!targetServer.empty()) {
|
|
|
|
|
|
|
|
// User specified a server, validate it exists in configuration
|
|
|
|
|
|
|
|
std::vector<std::string> servers = serverManager.getServers();
|
|
|
|
|
|
|
|
if (std::find(servers.begin(), servers.end(), targetServer) == servers.end()) {
|
|
|
|
|
|
|
|
std::cerr << "Error: Server '" << targetServer << "' is not configured" << std::endl;
|
|
|
|
|
|
|
|
std::cerr << "Use 'getpkg server add " << targetServer << "' to add it first" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
publishServer = targetServer;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Use default publish server (first server with write token)
|
|
|
|
|
|
|
|
publishServer = serverManager.getDefaultPublishServer();
|
|
|
|
|
|
|
|
if (publishServer.empty()) {
|
|
|
|
|
|
|
|
std::cerr << "Error: No servers with write tokens configured" << std::endl;
|
|
|
|
|
|
|
|
std::cerr << "Use 'getpkg server add <url>' and provide a write token" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get write token for the target server
|
|
|
|
|
|
|
|
std::string token = serverManager.getWriteToken(publishServer);
|
|
|
|
|
|
|
|
if (token.empty()) {
|
|
|
|
|
|
|
|
// Check environment variable as fallback
|
|
|
|
|
|
|
|
const char* envToken = std::getenv("SOS_WRITE_TOKEN");
|
|
|
|
|
|
|
|
if (envToken && std::strlen(envToken) > 0) {
|
|
|
|
|
|
|
|
token = envToken;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
std::cerr << "Error: No write token found for server '" << publishServer << "'" << std::endl;
|
|
|
|
|
|
|
|
std::cerr << "Set SOS_WRITE_TOKEN environment variable or configure token for this server" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string home = get_home();
|
|
|
|
std::string home = get_home();
|
|
|
|
std::filesystem::path archivePath = std::filesystem::path(home) / ".tmp" / (labeltag + ".tgz");
|
|
|
|
std::filesystem::path archivePath = std::filesystem::path(home) / ".tmp" / (labeltag + ".tgz");
|
|
|
|
std::filesystem::create_directories(archivePath.parent_path());
|
|
|
|
std::filesystem::create_directories(archivePath.parent_path());
|
|
|
@ -324,24 +408,10 @@ int publish_tool(int argc, char* argv[]) {
|
|
|
|
std::cerr << "Failed to create archive." << std::endl;
|
|
|
|
std::cerr << "Failed to create archive." << std::endl;
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::string token;
|
|
|
|
|
|
|
|
const char* envToken = std::getenv("SOS_WRITE_TOKEN");
|
|
|
|
// Initialize GetbinClient with server list
|
|
|
|
if (envToken && std::strlen(envToken) > 0) {
|
|
|
|
std::vector<std::string> servers = serverManager.getServers();
|
|
|
|
token = envToken;
|
|
|
|
GetbinClient getbin(servers);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
std::filesystem::path tokenPath = std::filesystem::path(home) / ".config/getpkg.xyz/write_token.txt";
|
|
|
|
|
|
|
|
if (std::filesystem::exists(tokenPath)) {
|
|
|
|
|
|
|
|
std::ifstream tfile(tokenPath);
|
|
|
|
|
|
|
|
std::getline(tfile, token);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
std::cout << "Enter getpkg.xyz write token: ";
|
|
|
|
|
|
|
|
std::getline(std::cin, token);
|
|
|
|
|
|
|
|
std::filesystem::create_directories(tokenPath.parent_path());
|
|
|
|
|
|
|
|
std::ofstream tfile(tokenPath);
|
|
|
|
|
|
|
|
tfile << token << std::endl;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
GetbinClient getbin;
|
|
|
|
|
|
|
|
std::string url, hash;
|
|
|
|
std::string url, hash;
|
|
|
|
|
|
|
|
|
|
|
|
// Progress callback for upload
|
|
|
|
// Progress callback for upload
|
|
|
@ -355,13 +425,14 @@ int publish_tool(int argc, char* argv[]) {
|
|
|
|
return true; // Continue upload
|
|
|
|
return true; // Continue upload
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Publishing to " << publishServer << "..." << std::endl;
|
|
|
|
std::cout << "Uploading..." << std::flush;
|
|
|
|
std::cout << "Uploading..." << std::flush;
|
|
|
|
if (!getbin.upload(archivePath.string(), url, hash, token, uploadProgressCallback)) {
|
|
|
|
if (!getbin.upload(publishServer, archivePath.string(), url, hash, token, uploadProgressCallback)) {
|
|
|
|
std::cerr << "\rFailed to upload archive." << std::endl;
|
|
|
|
std::cerr << "\rFailed to upload archive to " << publishServer << std::endl;
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clearAndPrint("Uploading... done\n");
|
|
|
|
clearAndPrint("Uploading... done\n");
|
|
|
|
std::cout << "Published! URL: " << url << "\nHash: " << hash << std::endl;
|
|
|
|
std::cout << "Published to " << publishServer << "! URL: " << url << "\nHash: " << hash << std::endl;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -369,6 +440,25 @@ int update_tool(int argc, char* argv[]) {
|
|
|
|
std::string home = get_home();
|
|
|
|
std::string home = get_home();
|
|
|
|
std::filesystem::path configDir = std::filesystem::path(home) / ".config/getpkg";
|
|
|
|
std::filesystem::path configDir = std::filesystem::path(home) / ".config/getpkg";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize ServerManager and PackageMetadataManager
|
|
|
|
|
|
|
|
ServerManager serverManager;
|
|
|
|
|
|
|
|
if (!serverManager.loadConfiguration()) {
|
|
|
|
|
|
|
|
std::cerr << "Failed to load server configuration" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> servers = serverManager.getServers();
|
|
|
|
|
|
|
|
if (servers.empty()) {
|
|
|
|
|
|
|
|
std::cerr << "No servers configured" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PackageMetadataManager packageManager(configDir);
|
|
|
|
|
|
|
|
if (!packageManager.ensurePackagesDirectory()) {
|
|
|
|
|
|
|
|
std::cerr << "Failed to create packages directory" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Structure to hold tool information
|
|
|
|
// Structure to hold tool information
|
|
|
|
struct ToolInfo {
|
|
|
|
struct ToolInfo {
|
|
|
|
std::string name;
|
|
|
|
std::string name;
|
|
|
@ -376,29 +466,43 @@ int update_tool(int argc, char* argv[]) {
|
|
|
|
std::string remoteHash;
|
|
|
|
std::string remoteHash;
|
|
|
|
std::string arch;
|
|
|
|
std::string arch;
|
|
|
|
std::string version;
|
|
|
|
std::string version;
|
|
|
|
|
|
|
|
std::string sourceServer;
|
|
|
|
bool needsUpdate = false;
|
|
|
|
bool needsUpdate = false;
|
|
|
|
std::string status = "Up to date";
|
|
|
|
std::string status = "Up to date";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<ToolInfo> tools;
|
|
|
|
std::vector<ToolInfo> tools;
|
|
|
|
|
|
|
|
|
|
|
|
// Collect all installed tools
|
|
|
|
// Collect all installed tools using PackageMetadataManager
|
|
|
|
if (std::filesystem::exists(configDir)) {
|
|
|
|
std::vector<std::string> installedPackages = packageManager.listInstalledPackages();
|
|
|
|
for (const auto& entry : std::filesystem::directory_iterator(configDir)) {
|
|
|
|
for (const std::string& toolName : installedPackages) {
|
|
|
|
if (entry.path().extension() == ".json") {
|
|
|
|
|
|
|
|
std::string tname = entry.path().stem();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ToolInfo tool;
|
|
|
|
ToolInfo tool;
|
|
|
|
tool.name = tname;
|
|
|
|
tool.name = toolName;
|
|
|
|
|
|
|
|
|
|
|
|
// Read local tool info
|
|
|
|
// Load package metadata
|
|
|
|
std::ifstream tfile(entry.path());
|
|
|
|
PackageMetadata metadata = packageManager.loadPackageMetadata(toolName);
|
|
|
|
|
|
|
|
if (metadata.isValid()) {
|
|
|
|
|
|
|
|
tool.localHash = metadata.hash;
|
|
|
|
|
|
|
|
tool.arch = metadata.arch.empty() ? get_arch() : metadata.arch;
|
|
|
|
|
|
|
|
tool.version = metadata.version;
|
|
|
|
|
|
|
|
tool.sourceServer = metadata.sourceServer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tool.version.empty() || tool.version == "-") {
|
|
|
|
|
|
|
|
tool.version = "installed";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Fallback to legacy format if new format fails
|
|
|
|
|
|
|
|
std::filesystem::path legacyPath = configDir / (toolName + ".json");
|
|
|
|
|
|
|
|
if (std::filesystem::exists(legacyPath)) {
|
|
|
|
|
|
|
|
std::ifstream tfile(legacyPath);
|
|
|
|
if (tfile.good()) {
|
|
|
|
if (tfile.good()) {
|
|
|
|
json toolInfo;
|
|
|
|
json toolInfo;
|
|
|
|
tfile >> toolInfo;
|
|
|
|
tfile >> toolInfo;
|
|
|
|
tool.localHash = toolInfo.value("hash", "");
|
|
|
|
tool.localHash = toolInfo.value("hash", "");
|
|
|
|
tool.arch = toolInfo.value("arch", get_arch());
|
|
|
|
tool.arch = toolInfo.value("arch", get_arch());
|
|
|
|
tool.version = toolInfo.value("version", "-");
|
|
|
|
tool.version = toolInfo.value("version", "-");
|
|
|
|
|
|
|
|
tool.sourceServer = "getpkg.xyz"; // Default for legacy
|
|
|
|
|
|
|
|
|
|
|
|
if (!tool.version.empty() && tool.version.back() == '\n') {
|
|
|
|
if (!tool.version.empty() && tool.version.back() == '\n') {
|
|
|
|
tool.version.pop_back();
|
|
|
|
tool.version.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -406,11 +510,11 @@ int update_tool(int argc, char* argv[]) {
|
|
|
|
tool.version = "installed";
|
|
|
|
tool.version = "installed";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tools.push_back(tool);
|
|
|
|
tools.push_back(tool);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tools.empty()) {
|
|
|
|
if (tools.empty()) {
|
|
|
|
std::cout << "No tools installed." << std::endl;
|
|
|
|
std::cout << "No tools installed." << std::endl;
|
|
|
@ -420,14 +524,14 @@ int update_tool(int argc, char* argv[]) {
|
|
|
|
// Step 1: Check for updates (with progress)
|
|
|
|
// Step 1: Check for updates (with progress)
|
|
|
|
std::cout << "Checking " << tools.size() << " tools for updates..." << std::endl;
|
|
|
|
std::cout << "Checking " << tools.size() << " tools for updates..." << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
GetbinClient getbin;
|
|
|
|
GetbinClient getbin(servers);
|
|
|
|
for (size_t i = 0; i < tools.size(); ++i) {
|
|
|
|
for (size_t i = 0; i < tools.size(); ++i) {
|
|
|
|
auto& tool = tools[i];
|
|
|
|
auto& tool = tools[i];
|
|
|
|
|
|
|
|
|
|
|
|
// Show progress
|
|
|
|
// Show progress
|
|
|
|
std::cout << "\r[" << (i + 1) << "/" << tools.size() << "] Checking " << tool.name << "..." << std::flush;
|
|
|
|
std::cout << "\r[" << (i + 1) << "/" << tools.size() << "] Checking " << tool.name << "..." << std::flush;
|
|
|
|
|
|
|
|
|
|
|
|
// Check remote hash
|
|
|
|
// Check remote hash - use multi-server fallback
|
|
|
|
std::string remoteHash;
|
|
|
|
std::string remoteHash;
|
|
|
|
if (getbin.getHash(tool.name, tool.arch, remoteHash) && !remoteHash.empty()) {
|
|
|
|
if (getbin.getHash(tool.name, tool.arch, remoteHash) && !remoteHash.empty()) {
|
|
|
|
tool.remoteHash = remoteHash;
|
|
|
|
tool.remoteHash = remoteHash;
|
|
|
@ -499,16 +603,10 @@ int update_tool(int argc, char* argv[]) {
|
|
|
|
tool.status = "Updated";
|
|
|
|
tool.status = "Updated";
|
|
|
|
clearAndPrint("Updated\n");
|
|
|
|
clearAndPrint("Updated\n");
|
|
|
|
|
|
|
|
|
|
|
|
// Re-read version after update
|
|
|
|
// Re-read version after update using PackageMetadataManager
|
|
|
|
std::filesystem::path toolInfoPath = configDir / (tool.name + ".json");
|
|
|
|
PackageMetadata updatedMetadata = packageManager.loadPackageMetadata(tool.name);
|
|
|
|
if (std::filesystem::exists(toolInfoPath)) {
|
|
|
|
if (updatedMetadata.isValid()) {
|
|
|
|
std::ifstream tfile(toolInfoPath);
|
|
|
|
tool.version = updatedMetadata.version;
|
|
|
|
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 == "-") {
|
|
|
|
if (tool.version.empty() || tool.version == "-") {
|
|
|
|
tool.version = "installed";
|
|
|
|
tool.version = "installed";
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -622,38 +720,73 @@ int hash_command(int argc, char* argv[]) {
|
|
|
|
|
|
|
|
|
|
|
|
int unpublish_tool(int argc, char* argv[]) {
|
|
|
|
int unpublish_tool(int argc, char* argv[]) {
|
|
|
|
if (argc < 3) {
|
|
|
|
if (argc < 3) {
|
|
|
|
std::cerr << "Usage: getpkg unpublish <tool_name[:ARCH]>" << std::endl;
|
|
|
|
std::cerr << "Usage: getpkg unpublish [--server <url>] <tool_name[:ARCH]>" << std::endl;
|
|
|
|
|
|
|
|
std::cerr << " getpkg unpublish [--server <url>] <hash>" << std::endl;
|
|
|
|
|
|
|
|
std::cerr << " getpkg unpublish <tool_name[:ARCH]>" << std::endl;
|
|
|
|
std::cerr << " getpkg unpublish <hash>" << std::endl;
|
|
|
|
std::cerr << " getpkg unpublish <hash>" << std::endl;
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::string target = argv[2];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get token
|
|
|
|
// Parse arguments for --server option
|
|
|
|
std::string token;
|
|
|
|
std::string targetServer;
|
|
|
|
|
|
|
|
std::string target;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (argc >= 4 && std::string(argv[2]) == "--server") {
|
|
|
|
|
|
|
|
if (argc < 5) {
|
|
|
|
|
|
|
|
std::cerr << "Usage: getpkg unpublish --server <url> <tool_name[:ARCH]|hash>" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
targetServer = argv[3];
|
|
|
|
|
|
|
|
target = argv[4];
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
target = argv[2];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize ServerManager
|
|
|
|
|
|
|
|
ServerManager serverManager;
|
|
|
|
|
|
|
|
if (!serverManager.loadConfiguration()) {
|
|
|
|
|
|
|
|
std::cerr << "Failed to load server configuration" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Determine target server
|
|
|
|
|
|
|
|
std::string unpublishServer;
|
|
|
|
|
|
|
|
if (!targetServer.empty()) {
|
|
|
|
|
|
|
|
// User specified a server, validate it exists in configuration
|
|
|
|
|
|
|
|
std::vector<std::string> servers = serverManager.getServers();
|
|
|
|
|
|
|
|
if (std::find(servers.begin(), servers.end(), targetServer) == servers.end()) {
|
|
|
|
|
|
|
|
std::cerr << "Error: Server '" << targetServer << "' is not configured" << std::endl;
|
|
|
|
|
|
|
|
std::cerr << "Use 'getpkg server add " << targetServer << "' to add it first" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
unpublishServer = targetServer;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Use default publish server (first server with write token)
|
|
|
|
|
|
|
|
unpublishServer = serverManager.getDefaultPublishServer();
|
|
|
|
|
|
|
|
if (unpublishServer.empty()) {
|
|
|
|
|
|
|
|
std::cerr << "Error: No servers with write tokens configured" << std::endl;
|
|
|
|
|
|
|
|
std::cerr << "Use 'getpkg server add <url>' and provide a write token" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get write token for the target server
|
|
|
|
|
|
|
|
std::string token = serverManager.getWriteToken(unpublishServer);
|
|
|
|
|
|
|
|
if (token.empty()) {
|
|
|
|
|
|
|
|
// Check environment variable as fallback
|
|
|
|
const char* envToken = std::getenv("SOS_WRITE_TOKEN");
|
|
|
|
const char* envToken = std::getenv("SOS_WRITE_TOKEN");
|
|
|
|
if (envToken && std::strlen(envToken) > 0) {
|
|
|
|
if (envToken && std::strlen(envToken) > 0) {
|
|
|
|
token = envToken;
|
|
|
|
token = envToken;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
std::string home = get_home();
|
|
|
|
std::cerr << "Error: No write token found for server '" << unpublishServer << "'" << std::endl;
|
|
|
|
std::filesystem::path tokenPath = std::filesystem::path(home) / ".config/getpkg.xyz/write_token.txt";
|
|
|
|
std::cerr << "Set SOS_WRITE_TOKEN environment variable or configure token for this server" << std::endl;
|
|
|
|
if (std::filesystem::exists(tokenPath)) {
|
|
|
|
|
|
|
|
std::ifstream tfile(tokenPath);
|
|
|
|
|
|
|
|
std::getline(tfile, token);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
std::cout << "Enter getpkg.xyz write token: ";
|
|
|
|
|
|
|
|
std::getline(std::cin, token);
|
|
|
|
|
|
|
|
std::filesystem::create_directories(tokenPath.parent_path());
|
|
|
|
|
|
|
|
std::ofstream tfile(tokenPath);
|
|
|
|
|
|
|
|
tfile << token << std::endl;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (token.empty()) {
|
|
|
|
|
|
|
|
std::cerr << "Error: No write token provided" << std::endl;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GetbinClient getbin;
|
|
|
|
// Initialize GetbinClient with server list
|
|
|
|
|
|
|
|
std::vector<std::string> servers = serverManager.getServers();
|
|
|
|
|
|
|
|
GetbinClient getbin(servers);
|
|
|
|
std::string hash = target;
|
|
|
|
std::string hash = target;
|
|
|
|
|
|
|
|
|
|
|
|
// Check if target looks like a hash (all digits) or a tool name
|
|
|
|
// Check if target looks like a hash (all digits) or a tool name
|
|
|
@ -678,8 +811,8 @@ int unpublish_tool(int argc, char* argv[]) {
|
|
|
|
|
|
|
|
|
|
|
|
// If a specific architecture was requested, only unpublish that one
|
|
|
|
// If a specific architecture was requested, only unpublish that one
|
|
|
|
if (!specificArch.empty()) {
|
|
|
|
if (!specificArch.empty()) {
|
|
|
|
if (!getbin.getHash(toolName, specificArch, hash)) {
|
|
|
|
if (!getbin.getHash(unpublishServer, toolName, specificArch, hash)) {
|
|
|
|
std::cerr << "Failed to get hash for " << target << std::endl;
|
|
|
|
std::cerr << "Failed to get hash for " << target << " on server " << unpublishServer << std::endl;
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -703,14 +836,14 @@ int unpublish_tool(int argc, char* argv[]) {
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Found hash " << hash << " for " << target << std::endl;
|
|
|
|
std::cout << "Found hash " << hash << " for " << target << " on " << unpublishServer << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
// Delete the specific architecture
|
|
|
|
// Delete the specific architecture
|
|
|
|
if (getbin.deleteObject(hash, token)) {
|
|
|
|
if (getbin.deleteObject(hash, token)) {
|
|
|
|
std::cout << "Successfully unpublished " << target << " (hash: " << hash << ")" << std::endl;
|
|
|
|
std::cout << "Successfully unpublished " << target << " from " << unpublishServer << " (hash: " << hash << ")" << std::endl;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
std::cerr << "Failed to unpublish " << target << std::endl;
|
|
|
|
std::cerr << "Failed to unpublish " << target << " from " << unpublishServer << std::endl;
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -1105,14 +1238,15 @@ void show_help() {
|
|
|
|
std::cout << " uninstall <tool_name> Remove an installed tool" << std::endl;
|
|
|
|
std::cout << " uninstall <tool_name> Remove an installed tool" << std::endl;
|
|
|
|
std::cout << " Removes tool files, PATH entries, and autocomplete" << std::endl;
|
|
|
|
std::cout << " Removes tool files, PATH entries, and autocomplete" << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << " publish <tool_name[:ARCH]> <folder> Upload a tool to getpkg.xyz" << std::endl;
|
|
|
|
std::cout << " publish [--server <url>] <tool_name[:ARCH]> <folder>" << std::endl;
|
|
|
|
|
|
|
|
std::cout << " Upload a tool to a package server" << std::endl;
|
|
|
|
std::cout << " ARCH is optional (defaults to 'universal')" << std::endl;
|
|
|
|
std::cout << " ARCH is optional (defaults to 'universal')" << std::endl;
|
|
|
|
std::cout << " Requires SOS_WRITE_TOKEN environment variable" << std::endl;
|
|
|
|
std::cout << " Uses default publish server if --server not specified" << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << " unpublish <tool_name> Remove ALL architectures of a tool" << std::endl;
|
|
|
|
std::cout << " unpublish [--server <url>] <tool_name> Remove ALL architectures of a tool" << std::endl;
|
|
|
|
std::cout << " unpublish <tool_name:ARCH> Remove specific architecture only" << std::endl;
|
|
|
|
std::cout << " unpublish [--server <url>] <tool_name:ARCH> Remove specific architecture only" << std::endl;
|
|
|
|
std::cout << " unpublish <hash> Remove a tool by hash" << std::endl;
|
|
|
|
std::cout << " unpublish [--server <url>] <hash> Remove a tool by hash" << std::endl;
|
|
|
|
std::cout << " Requires SOS_WRITE_TOKEN environment variable" << std::endl;
|
|
|
|
std::cout << " Uses default publish server if --server not specified" << std::endl;
|
|
|
|
std::cout << " Without :ARCH, removes x86_64, aarch64, and universal versions" << std::endl;
|
|
|
|
std::cout << " Without :ARCH, removes x86_64, aarch64, and universal versions" << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
std::cout << " update Update getpkg and all installed tools" << std::endl;
|
|
|
|
std::cout << " update Update getpkg and all installed tools" << std::endl;
|
|
|
@ -1147,8 +1281,10 @@ void show_help() {
|
|
|
|
std::cout << " getpkg install myapp Install myapp" << std::endl;
|
|
|
|
std::cout << " getpkg install myapp Install myapp" << std::endl;
|
|
|
|
std::cout << " getpkg publish myapp:x86_64 ./build Publish architecture-specific build" << std::endl;
|
|
|
|
std::cout << " getpkg publish myapp:x86_64 ./build Publish architecture-specific build" << std::endl;
|
|
|
|
std::cout << " getpkg publish myapp ./build Publish universal build" << std::endl;
|
|
|
|
std::cout << " getpkg publish myapp ./build Publish universal build" << std::endl;
|
|
|
|
|
|
|
|
std::cout << " getpkg publish --server example.com myapp ./build Publish to specific server" << std::endl;
|
|
|
|
std::cout << " getpkg unpublish myapp Remove ALL architectures of myapp" << std::endl;
|
|
|
|
std::cout << " getpkg unpublish myapp Remove ALL architectures of myapp" << std::endl;
|
|
|
|
std::cout << " getpkg unpublish myapp:x86_64 Remove only x86_64 version" << std::endl;
|
|
|
|
std::cout << " getpkg unpublish myapp:x86_64 Remove only x86_64 version" << std::endl;
|
|
|
|
|
|
|
|
std::cout << " getpkg unpublish --server example.com myapp Remove from specific server" << std::endl;
|
|
|
|
std::cout << " getpkg uninstall myapp Remove myapp from system" << std::endl;
|
|
|
|
std::cout << " getpkg uninstall myapp Remove myapp from system" << std::endl;
|
|
|
|
std::cout << " getpkg update Update everything" << 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 add packages.example.com Add a custom package server" << std::endl;
|
|
|
|