Skip to content

Commit

Permalink
change refresh metadata to be more close to libzypp and use it from rust
Browse files Browse the repository at this point in the history
  • Loading branch information
jreidinger committed Nov 20, 2024
1 parent d8d245f commit 49335d8
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 20 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@
main
.vscode
/html/
# compilatation instruction for clangd. As it is generated with full path it does not make sense to have it in git
compile_commands.json
# clangd cache
/.cache
18 changes: 16 additions & 2 deletions c-example/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void download_progress_finish(const char *url, int error, const char *reason, vo
}

int main(int argc, char *argv[]) {
int result = 0;
struct Status status;
set_zypp_progress_callback(zypp_progress, NULL);
set_zypp_download_callbacks(download_progress_start, download_progress_progress, download_progress_problem,
Expand All @@ -39,17 +40,27 @@ int main(int argc, char *argv[]) {
if (argc > 1)
root = argv[1];
printf("List of repos:\n");
const char *prefix = "Loading '/'";
const char *prefix = "Loading '/'"; // TODO: wrong report with changed root
init_target(root, &status, progress, (void *)prefix);
if (status.state != STATE_SUCCEED) {
printf("init ERROR!: %s\n", status.error);
result = 1;
goto norepo;
}
free_status(status);

struct RepositoryList list = list_repositories();
for (unsigned i = 0; i < list.size; ++i) {
struct Repository *repo = list.repos + i;
printf("repo %i: %s\n", i, repo->userName);
printf("refreshing...");
refresh_repository(repo->alias, &status);
if (status.state != STATE_SUCCEED) {
printf("refresh ERROR!: %s\n", status.error);
free_status(status);
goto repoerr;
}
free_status(status);
}
free_repository_list(&list);

Expand All @@ -59,7 +70,10 @@ int main(int argc, char *argv[]) {
if (status.state != STATE_SUCCEED) {
printf("refresh ERROR!: %s\n", status.error);
}
repoerr:
free_repository_list(&list);
norepo:
free_status(status);
free_zypp();
return 0;
return result;
}
5 changes: 2 additions & 3 deletions c-layer/include/lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,9 @@ struct RepositoryList list_repositories();
void free_repository_list(struct RepositoryList *repo_list);

///
/// @param alias alias of repository to refresh
/// @param[out] status (will overwrite existing contents)
/// @param callback
/// @param data
void refresh_repositories(struct Status *status, ZyppProgressCallback callback, void *data);
void refresh_repository(const char* alias, struct Status* status);

// the last call that will free all pointers to zypp holded by agama
void free_zypp();
Expand Down
49 changes: 39 additions & 10 deletions c-layer/lib.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,50 @@
#include "callbacks.h"
#include "callbacks.hxx"

#include <cstddef>
#include <zypp/RepoInfo.h>
#include <zypp/RepoManager.h>
#include <zypp/ZYpp.h>
#include <zypp/ZYppFactory.h>
#include <zypp/base/LogControl.h>
#include <zypp/base/Logger.h>

#include <cstdarg>

extern "C" {
static zypp::ZYpp::Ptr zypp_pointer = NULL;
static zypp::RepoManager *repo_manager = NULL;

void free_zypp() {
zypp_pointer = NULL; // shared ptr assignment operator will free original pointer
zypp_pointer =
NULL; // shared ptr assignment operator will free original pointer
delete (repo_manager);
}

zypp::ZYpp::Ptr zypp_ptr() {
// helper to get allocated formated string. Sadly C does not provide any portable way to do it.
// if we are ok with GNU or glib then it provides it
static char* format_alloc(const char* const format...) {
// `vsnprintf()` changes `va_list`'s state, so using it after that is UB.
// We need the args twice, so it is safer to just get two copies.
va_list args1;
va_list args2;
va_start(args1, format);
va_start(args2, format);

// vsnprintf with len 0 just return needed size and add trailing zero.
size_t needed = 1 + vsnprintf(NULL, 0, format, args1);

char* buffer = (char *) malloc(needed * sizeof(char));

vsnprintf(buffer, needed, format, args2);

va_end(args1);
va_end(args2);

return buffer;
}

static zypp::ZYpp::Ptr zypp_ptr() {
if (zypp_pointer != NULL) {
return zypp_pointer;
}
Expand Down Expand Up @@ -94,21 +122,22 @@ void free_status(struct Status status) {
}
}

void refresh_repositories(struct Status *status, ZyppProgressCallback callback, void *data) {
void refresh_repository(const char* alias, struct Status *status) {
if (repo_manager == NULL) {
status->state = status->STATE_FAILED;
status->error = strdup("Internal Error: Repo manager is not initialized.");
return;
}

auto progress_cb = create_progress_callback(callback, data);

try {
std::list<zypp::RepoInfo> zypp_repos = repo_manager->knownRepositories();
for (auto iter = zypp_repos.begin(); iter != zypp_repos.end(); ++iter) {
printf("refreshing repo %s\n", iter->alias().c_str());
repo_manager->refreshMetadata(*iter, zypp::RepoManager::RawMetadataRefreshPolicy::RefreshForced, progress_cb);
zypp::RepoInfo zypp_repo = repo_manager->getRepo(alias);
if (zypp_repo == zypp::RepoInfo::noRepo) {
status->state = status->STATE_FAILED;
status->error = format_alloc("Cannot refresh repo with alias %s. Repo not found.", alias);
return;
}

repo_manager->refreshMetadata(
zypp_repo, zypp::RepoManager::RawMetadataRefreshPolicy::RefreshForced);
status->state = status->STATE_SUCCEED;
status->error = NULL;
} catch (zypp::Exception &excpt) {
Expand Down
7 changes: 7 additions & 0 deletions rust/zypp-agama-example/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::env;
use zypp_agama::refresh_repository;

fn main() {
println!("Usage: main [ROOT]");
Expand All @@ -19,5 +20,11 @@ fn main() {
let repos = zypp_agama::list_repositories();
for repo in repos {
println!("- Repo {} with url {}", repo.user_name, repo.url);
println!("Refreshing...");
let result = refresh_repository(&repo.alias);
if let Err(error) = result {
println!("Failed to refresh repo {}: {}", repo.user_name, error);
return;
};
}
}
6 changes: 1 addition & 5 deletions rust/zypp-agama-sys/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,6 @@ extern "C" {
);
pub fn list_repositories() -> RepositoryList;
pub fn free_repository_list(repo_list: *mut RepositoryList);
pub fn refresh_repositories(
status: *mut Status,
callback: ZyppProgressCallback,
data: *mut ::std::os::raw::c_void,
);
pub fn refresh_repository(alias: *const ::std::os::raw::c_char, status: *mut Status);
pub fn free_zypp();
}
10 changes: 10 additions & 0 deletions rust/zypp-agama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ pub fn list_repositories() -> Vec<Repository> {
res
}

pub fn refresh_repository(alias: &str) -> Result<(), ZyppError> {
unsafe {
let mut status: Status = Status { state: Status_STATE_STATE_SUCCEED, error: null_mut() };
let status_ptr = &mut status as *mut _ as *mut Status;
let c_alias = CString::new(alias).unwrap();
zypp_agama_sys::refresh_repository(c_alias.as_ptr(), status_ptr);
return status_to_result_void(status);
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down

0 comments on commit 49335d8

Please sign in to comment.