DistroqueryAPI: add file_providers API call and resolve file requirements in packages

This commit is contained in:
Silvan Calarco 2024-08-11 20:09:33 +02:00
parent e27c278b13
commit c5b4c1ace4
3 changed files with 113 additions and 9 deletions

View File

@ -337,6 +337,20 @@ json DistroqueryAPI::getProvidersForRequirement(string repository, string requir
}
j = getProvidersForRequirementFromDb(db, ct, requirement, flags, version, onlyarch);
// Add resolved file requirements
if (requirement[0] == '/') {
json fileProviders = getFileProviders(repository, requirement, onlyarch);
if (fileProviders.contains("providers")) {
if (!j.contains("providers")) {
j["providers"] = json::array();
}
for (auto provider:fileProviders["providers"]) {
j["providers"].push_back(provider);
}
}
}
sqlite3_close(db);
return j;
}
@ -423,6 +437,82 @@ json DistroqueryAPI::getPackageSourceDetails(string repository, string package)
return j;
}
json DistroqueryAPI::getFileProviders(string repository, string path, string arch) {
json j;
string sql;
sqlite3_stmt *stmt, *stmt2;
struct configTag* ct = findRepositoryByTag(repository.c_str());
if (ct == NULL) {
j["error"] = "repository with tag '" + repository + "' does not exist";
return j;
}
if (ct->repodata_url == NULL) {
j["error"] = "repository with tag '" + repository + "' is not supported by this API";
return j;
}
int i = 0;
string dbname;
json providers = json::array();
while (ct->repository[i]) {
dbname = string(ct->repository[i]->repository_dir) + ct->repository[i]->tag + "-" + arch + "-files.db";
auto db = openRepositoryDatabase(ct->repository[i], arch, "-files");
if (!db) {
j["error"] = "error opening database for repository " + string(ct->repository[i]->tag) + " and arch " + arch;
return j;
}
size_t pos = 0;
string s = path + "/";
long parent = -1;
while ((pos = s.find("/")) != std::string::npos) {
string name;
string token = s.substr(0, pos);
if (token != "") {
sql = "SELECT id,parent FROM files WHERE name='" + token + "' AND parent=" + to_string(parent);
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(stmt) == SQLITE_ROW) {
long id = sqlite3_column_int(stmt,sqlite3_find_column_id(stmt, NULL, "id"));
parent = id;
} else {
// not found
break;
}
} else {
j["error"] = "error preparing query '" + sql + "': " + sqlite3_errmsg(db);
return j;
}
}
s.erase(0, pos + 1);
if (s.length() == 0) {
// found
sql = "SELECT name FROM packages_files_rel WHERE id_file=" + to_string(parent);
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt2, NULL) == SQLITE_OK) {
if (sqlite3_step(stmt2) == SQLITE_ROW) {
json provider;
provider["repository"] = string(ct->repository[i]->tag);
provider["name"] = reinterpret_cast<const char*>(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "name")));
provider["flags"] = "";
provider["version"] = "";
providers.push_back(provider);
}
} else {
j["error"] = "error preparing query '" + sql + "': " + sqlite3_errmsg(db);
return j;
}
}
}
sqlite3_close(db);
i++;
}
j["providers"] = providers;
return j;
}
string DistroqueryAPI::resolvePackageFilePathById(sqlite3 *db, long id) {
string sql;
sqlite3_stmt *stmt;
@ -718,6 +808,12 @@ void DistroqueryAPI::getApiResponse(string path_info) {
if (v.size() > 0) {
path = v[0];
// Fix URL decoding due to '%' returned encoded as '%25'
size_t pos = path.find("%25");
while (pos != string::npos) {
path.replace(pos, 3, "%");
pos = path.find("%25", pos + 1);
}
path_split = split(path, "/");
}
@ -774,22 +870,30 @@ void DistroqueryAPI::getApiResponse(string path_info) {
// API service: package
if (path_split.size() < 3 || path_split.size() > 4)
sendErrorResponse("expected 3 or 4 arguments for " + path_split[0]);
json details;
json response;
string package = urlDecode(path_split[2]);
if (path_split.size() == 3) {
details = getPackageSourceDetails(path_split[1], package);
response = getPackageSourceDetails(path_split[1], package);
} else {
details = getPackageDetails(path_split[1], package, path_split[3]);
response = getPackageDetails(path_split[1], package, path_split[3]);
}
cout << details.dump();
cout << response.dump();
} else if (path_split[0] == "package_files") {
// API service: package_files
if (path_split.size() != 4)
sendErrorResponse("expected 4 arguments for " + path_split[0]);
json details;
json response;
string package = urlDecode(path_split[2]);
details = getPackageFiles(path_split[1], package, path_split[3]);
cout << details.dump();
response = getPackageFiles(path_split[1], package, path_split[3]);
cout << response.dump();
} else if (path_split[0] == "file_providers") {
// API service: package_files
if (path_split.size() != 4)
sendErrorResponse("expected 4 arguments for " + path_split[0]);
json response;
string filepath = urlDecode(path_split[2]);
response = getFileProviders(path_split[1], filepath, path_split[3]);
cout << response.dump();
} else if (path_split[0] == "providers") {
// API service: providers
if (path_split.size() != 3 && path_split.size() != 5)

View File

@ -50,6 +50,7 @@ class DistroqueryAPI {
json getPackageSourceDetails(string repository, string package);
string resolvePackageFilePathById(sqlite3 *db, long id);
json getBuiltPackagesFromSourceID(configTag* ct, long id);
json getFileProviders(string repository, string path, string arch);
json getPackageFiles(string repository, string package, string arch);
json getPackageDetails(string repository, string package, string arch);
json getRepositoryProblems(string repository);

View File

@ -146,10 +146,9 @@ int sqlite3_find_column_id(sqlite3_stmt *stmt, const char* table, const char* na
string urlDecode(string str) {
string ret;
char ch;
int i, len = str.length();
unsigned int ii;
for (i=0; i < len; i++){
for (int i=0; i < str.length(); i++){
if (str[i] != '%') {
if (str[i] == '+')
ret += ' ';