From 00251895a39912d740c2c5f0c37d9b9b32947ad4 Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Tue, 1 Aug 2017 13:08:51 -0400 Subject: [PATCH] [API CHANGE] Add a new "pkg_install_verify" action to sysadm/pkg Add an "action" = "pkg_install_verify" option to the sysadm/pkg API call. REQUIRED: "pkg_origins" - string or array of pkg origins "repo" - remote repository that the package will be installed from. ---------- REST Request (example): ------------------------------- PUT /sysadm/pkg { "repo" : "trueos-major", "action" : "pkg_install_verify", "pkg_origins" : [ "www/qupzilla-qt5-webkit" ] } WebSocket Request: ------------------------------- { "name" : "pkg", "namespace" : "sysadm", "id" : "fooid", "args" : { "action" : "pkg_install_verify", "pkg_origins" : [ "www/qupzilla-qt5-webkit" ], "repo" : "trueos-major" } } Response: ------------------------------- { "args": { "pkg_install_verify": { "conflicts": [], "install": { "qupzilla-qt5-webkit": { "comment": "Web browser based on WebKit engine and Qt Framework", "flatsize": "13380132", "name": "qupzilla-qt5-webkit", "origin": "www/qupzilla-qt5-webkit", "pkgsize": "2574460", "version": "1.8.9_3" } } } }, "id": "fooid", "name": "response", "namespace": "sysadm" } --- src/server/WebBackend.cpp | 24 ++++--- src/server/library/sysadm-pkg.cpp | 107 +++++++++++++++++++++++++++++- src/server/library/sysadm-pkg.h | 2 + 3 files changed, 121 insertions(+), 12 deletions(-) diff --git a/src/server/WebBackend.cpp b/src/server/WebBackend.cpp index e59d59c..98a4f10 100644 --- a/src/server/WebBackend.cpp +++ b/src/server/WebBackend.cpp @@ -865,20 +865,20 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPkgRequest(const QJsonValue if(in_args.toObject().value("pkg_origins").isString()){ pkgs << in_args.toObject().value("pkg_origins").toString(); } else if(in_args.toObject().value("pkg_origins").isArray()){ pkgs = JsonArrayToStringList(in_args.toObject().value("pkg_origins").toArray()); } } - + //Parse the action and perform accordingly if(act=="pkg_info"){ //OPTIONAL: "pkg_origins" OR "category" //OPTIONAL: "repo" //OPTIONAL: "result" = "full" or "simple" (Default: "simple") - bool fullresults = false; + bool fullresults = false; if(in_args.toObject().contains("result")){ fullresults = (in_args.toObject().value("result").toString()=="full"); } - + //Now run the info fetch routine QJsonObject info = sysadm::PKG::pkg_info(pkgs, repo, cat, fullresults); if(!info.isEmpty()){ out->insert("pkg_info",info); } else{ return RestOutputStruct::NOCONTENT; } - + }else if(act=="pkg_search" && in_args.toObject().contains("search_term")){ //REQUIRED: "search_term" (string to search for) //OPTIONAL: "repo" @@ -899,22 +899,26 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPkgRequest(const QJsonValue }else{ return RestOutputStruct::NOCONTENT; } - + }else if(act=="list_categories"){ //OPTIONAL: "repo" QJsonArray cats = sysadm::PKG::list_categories(repo); if(!cats.isEmpty()){ out->insert("list_categories", cats); } else{ return RestOutputStruct::NOCONTENT; } - + }else if(act=="list_repos"){ QJsonArray repos = sysadm::PKG::list_repos(); if(!repos.isEmpty()){ out->insert("list_repos", repos); } else{ return RestOutputStruct::NOCONTENT; } - + }else if(act=="pkg_install" && !pkgs.isEmpty() ){ //REQUIRED: "pkg_origins" //OPTIONAL: "repo" (pkg will determine the best repo to use if not supplied) out->insert("pkg_install", sysadm::PKG::pkg_install(pkgs,repo)); + + }else if(act=="pkg_install_verify"){ + //REQUIRED: "pkg_origins", "repo" + out->insert("pkg_install_verify", sysadm::PKG::evaluateInstall(pkgs,repo) ); }else if(act=="pkg_remove" && !pkgs.isEmpty() ){ //REQUIRED: "pkg_origins" //OPTIONAL: "recursive"="true" or "false" (default: "true") @@ -923,10 +927,10 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPkgRequest(const QJsonValue out->insert("pkg_remove", sysadm::PKG::pkg_remove(pkgs, recursive)); }else if(act=="pkg_lock" && !pkgs.isEmpty() ){ //REQUIRED: "pkg_origins" - out->insert("pkg_lock", sysadm::PKG::pkg_lock(pkgs)); + out->insert("pkg_lock", sysadm::PKG::pkg_lock(pkgs)); }else if(act=="pkg_unlock" && !pkgs.isEmpty() ){ //REQUIRED: "pkg_origins" - out->insert("pkg_unlock", sysadm::PKG::pkg_unlock(pkgs)); + out->insert("pkg_unlock", sysadm::PKG::pkg_unlock(pkgs)); }else if(act=="pkg_update"){ //OPTIONAL: "force" = ["true"/"false"] (default: "false") bool force = false; @@ -944,7 +948,7 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPkgRequest(const QJsonValue //unknown action return RestOutputStruct::BADREQUEST; } - + return RestOutputStruct::OK; } diff --git a/src/server/library/sysadm-pkg.cpp b/src/server/library/sysadm-pkg.cpp index 7c3f7d9..1333518 100644 --- a/src/server/library/sysadm-pkg.cpp +++ b/src/server/library/sysadm-pkg.cpp @@ -14,6 +14,20 @@ using namespace sysadm; // ================== // INLINE FUNCTIONS // ================== +inline QStringList ids_from_origins(QStringList origins, QSqlDatabase DB){ + QSqlQuery q("SELECT id FROM packages WHERE origin IN ('"+origins.join("', '")+"')",DB); + QStringList out; + while(q.next()){ out << q.value("id").toString(); } + return out; +} + +inline QStringList ids_from_names(QStringList names, QSqlDatabase DB){ + QSqlQuery q("SELECT id FROM packages WHERE name IN ('"+names.join("', '")+"')",DB); + QStringList out; + while(q.next()){ out << q.value("id").toString(); } + return out; +} + //Get annotation variable/values inline void annotations_from_ids(QStringList var_ids, QStringList val_ids, QJsonObject *out, QSqlDatabase DB){ //Note: Both input lists *must* be the same length (one variable for one value) @@ -47,7 +61,7 @@ inline QStringList origins_from_package_ids(QStringList ids, QSqlDatabase DB){ while(q.next()){ out << q.value("origin").toString(); } return out; } -//Generic ID's -> Names function (known databases: users, groups, licenses, shlibs, categories ) +//Generic ID's -> Names function (known databases: users, groups, licenses, shlibs, categories, packages ) inline QStringList names_from_ids(QStringList ids, QString db, QSqlDatabase DB){ QSqlQuery q("SELECT name FROM "+db+" WHERE id IN ('"+ids.join("', '")+"')",DB); QStringList out; @@ -68,6 +82,26 @@ inline QStringList requires_from_ids(QStringList ids, QSqlDatabase DB){ while(q.next()){ out << q.value("require").toString(); } return out; } + +//conflict ID's from package ID's +inline QStringList conflicts_from_ids(QStringList ids, QSqlDatabase DB){ + QSqlQuery q("SELECT conflict_id FROM pkg_conflicts WHERE package_id IN ('"+ids.join("', '")+"')", DB); + QStringList out; + while(q.next()){ out << q.value("conflict_id").toString(); } + qDebug() << "Last Conflict detection Error:" << q.lastError().text(); + return out; +} + +//dependencies from package ID's +inline QStringList depends_from_ids(QStringList ids, QSqlDatabase DB){ + //Note: This returns package names, not ID's + QSqlQuery q("SELECT name FROM deps WHERE package_id IN ('"+ids.join("', '")+"')", DB); + QStringList out; + while(q.next()){ out << q.value("name").toString(); } + return out; +} + + inline QString getRepoFile(QString repo){ if(repo=="local"){ return "/var/db/pkg/local.sqlite"; } else{ return ("/var/db/pkg/repo-"+repo+".sqlite"); } @@ -204,7 +238,7 @@ QJsonObject PKG::pkg_info(QStringList origins, QString repo, QString category, b QSqlQuery q15("SELECT require_id FROM pkg_requires WHERE package_id = '"+id+"'", DB); tmpList.clear(); while(q15.next()){ tmpList << q15.value("require_id").toString(); } - if(!tmpList.isEmpty()){ info.insert("requires", QJsonArray::fromStringList(requires_from_ids(tmpList, DB)) ); } + if(!tmpList.isEmpty()){ info.insert("requires", QJsonArray::fromStringList(requires_from_ids(tmpList, DB)) ); }\ //Now insert this information into the main object retObj.insert(origin,info); } //end loop over pkg matches @@ -350,6 +384,75 @@ QJsonArray PKG::list_repos(bool updated){ return QJsonArray::fromStringList(found); } +QJsonObject PKG::evaluateInstall(QStringList origins, QString repo){ + qDebug() << "Verify Install:" << origins << repo; + QJsonObject out; + if(repo=="local" || origins.isEmpty()){ return out; } //nothing to do + QString dbconn = openDB(repo); + QString ldbconn = openDB("local"); + if(!dbconn.isEmpty()){ + QSqlDatabase DB = QSqlDatabase::database(dbconn); + QSqlDatabase LDB = QSqlDatabase::database(ldbconn); + if(!DB.isOpen() || !LDB.isOpen()){ return out; } //could not open DB (file missing?) + + //First get the list of all packages which need to be installed (ID's) from the remote database + QStringList toInstall_id; + QStringList tmp = names_from_ids( ids_from_origins(origins, DB), "packages", DB); + //qDebug() << " - Initial names:" << tmp; + while(!tmp.isEmpty()){ + QStringList ids = ids_from_names(tmp, DB); + for(int i=0; i