Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/agama-software/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub mod software_selection;
pub mod state;

pub use packages::{Resolvable, ResolvableType};
pub use registration::{Registration, RegistrationBuilder};
pub use registration::Registration;

/// Abstract the software-related configuration from the underlying system.
///
Expand Down
9 changes: 0 additions & 9 deletions rust/agama-software/src/model/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ use agama_utils::{
actor::Handler,
api::software::{AddonInfo, AddonRegistration, RegistrationInfo},
arch::Arch,
helpers::copy_dir_all,
};
use camino::Utf8PathBuf;
use openssl::x509::X509;
Expand Down Expand Up @@ -210,14 +209,6 @@ impl Registration {
.push(suseconnect_agama::DEFAULT_CONFIG_FILE.into());
self.copy_files(install_dir)?;

// FIXME: Copy services files. Temporarily solution because, most probably,
// it should be handled by libzypp itself.
if let Err(error) = copy_dir_all(
self.root_dir.join("etc/zypp/services.d"),
install_dir.join("etc/zypp/services.d"),
) {
tracing::error!("Failed to copy the libzypp services files: {error}");
};
Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion rust/agama-software/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use agama_utils::{
actor::{self, Actor, Handler, MessageHandler},
api::{
event::{self, Event},
software::{Config, ProductConfig, Proposal, Repository, SystemInfo},
software::{Config, Proposal, Repository, SystemInfo},
Issue, Scope,
},
issue,
Expand Down
30 changes: 30 additions & 0 deletions rust/agama-software/src/zypp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use agama_utils::{
software::{Pattern, SelectedBy, SoftwareProposal, SystemInfo},
Issue, Scope,
},
helpers::copy_dir_all,
products::ProductSpec,
progress, question,
};
Expand Down Expand Up @@ -83,6 +84,9 @@ pub enum ZyppServerError {

#[error("SSL error: {0}")]
SSL(#[from] openssl::error::ErrorStack),

#[error("Failed to copy to target system: {0}")]
IO(#[from] std::io::Error),
}

pub type ZyppServerResult<R> = Result<R, ZyppServerError>;
Expand Down Expand Up @@ -260,6 +264,8 @@ impl ZyppServer {
let repositories = zypp
.list_repositories()?
.into_iter()
// filter out service managed repositories
.filter(|repo| repo.service.is_none())
.map(|repo| state::Repository {
name: repo.user_name,
alias: repo.alias,
Expand Down Expand Up @@ -504,11 +510,35 @@ impl ZyppServer {
.map_err(|_| ZyppDispatchError::ResponseChannelClosed)?;
return Ok(());
}
if let Err(error) = self.copy_files() {
tracing::warn!("Failed to copy zypp files: {error}");
tx.send(Err(error.into()))
.map_err(|_| ZyppDispatchError::ResponseChannelClosed)?;
return Ok(());
}

// if we fail to send ok, lets just ignore it
let _ = tx.send(Ok(()));
Ok(())
}

const ZYPP_DIRS: [&str; 4] = [
"etc/zypp/services.d",
"etc/zypp/repos.d",
"etc/zypp/credentials.d",
"var/cache/zypp",
];
fn copy_files(&self) -> ZyppServerResult<()> {
for path in Self::ZYPP_DIRS {
let source_path = self.root_dir.join(path);
let target_path = self.install_dir.join(path);
if source_path.exists() {
copy_dir_all(&source_path, &target_path)?;
}
}
Ok(())
}

fn modify_full_repo(&self, zypp: &zypp_agama::Zypp) -> ZyppServerResult<()> {
let repos = zypp.list_repositories()?;
// if url is invalid, then do not disable it and do not touch it
Expand Down
1 change: 1 addition & 0 deletions rust/agama-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition.workspace = true
agama-locale-data = { path = "../agama-locale-data" }
agama-transfer = { path = "../agama-transfer" }
async-trait = "0.1.89"
camino = "1.2.1"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.140"
serde_with = "3.14.0"
Expand Down
44 changes: 33 additions & 11 deletions rust/agama-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,42 @@ pub fn gettext_noop(text: &str) -> &str {
}

pub mod helpers {
use std::{fs, io, path::Path};
use camino::Utf8Path;
use fs_err as fs;

/// Copy the files in the `src` directory to `dst`.
/// Recursively copies a directory.
///
/// It does not perform a recursive copy.
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
fs::create_dir_all(&dst)?;

for entry in fs::read_dir(src)? {
/// It copies the content of the `source` directory to the `target` directory.
/// It preserves the directory structure and the files content.
///
/// Symlinks are recreated pointing to the same target as the original one.
pub fn copy_dir_all(source: &Utf8Path, target: &Utf8Path) -> Result<(), std::io::Error> {
fs::create_dir_all(&target)?;
for entry in source.read_dir_utf8()? {
let entry = entry?;
let file_type = entry.file_type()?;

if file_type.is_file() {
std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
let ty = fs::symlink_metadata(entry.path())?;
let dst = target.join(entry.file_name());
if ty.is_dir() {
copy_dir_all(entry.path(), &dst)?;
} else if ty.is_symlink() {
// we need special handling of symlinks as libzypp do
// some tricks with danglinks symlinks and we should not
// break it
let link_dest = entry.path().read_link_utf8()?;
tracing::info!(
"Recreating symlink from {} to {} pointing to {}",
entry.path().to_string(),
dst.to_string(),
link_dest.to_string(),
);
fs_err::os::unix::fs::symlink(link_dest, &dst)?;
} else {
tracing::info!(
"Copying from {} to {}",
entry.path().to_string(),
dst.to_string()
);
fs::copy(entry.path(), &dst)?;
}
}

Expand Down
8 changes: 8 additions & 0 deletions rust/zypp-agama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct Repository {
pub url: String,
pub alias: String,
pub user_name: String,
pub service: Option<String>,
}

impl Repository {
Expand Down Expand Up @@ -242,11 +243,18 @@ impl Zypp {
let size_usize: usize = repos.size.try_into().unwrap();
for i in 0..size_usize {
let c_repo = *(repos.repos.add(i));
let service = string_from_ptr(c_repo.serviceName);
let service_opt = if service.is_empty() {
None
} else {
Some(service)
};
let r_repo = Repository {
enabled: c_repo.enabled,
url: string_from_ptr(c_repo.url),
alias: string_from_ptr(c_repo.alias),
user_name: string_from_ptr(c_repo.userName),
service: service_opt,
};
repos_v.push(r_repo);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct Repository {
char *url; ///< owned
char *alias; ///< owned
char *userName; ///< owned
char *serviceName; ///< owned
};

struct RepositoryList {
Expand Down
2 changes: 2 additions & 0 deletions rust/zypp-agama/zypp-agama-sys/c-layer/lib.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ void free_repository(struct Repository *repo) {
free(repo->url);
free(repo->alias);
free(repo->userName);
free(repo->serviceName);
}

void free_repository_list(struct RepositoryList *list) noexcept {
Expand Down Expand Up @@ -653,6 +654,7 @@ struct RepositoryList list_repositories(struct Zypp *zypp,
new_repo->url = strdup(iter->url().asString().c_str());
new_repo->alias = strdup(iter->alias().c_str());
new_repo->userName = strdup(iter->asUserString().c_str());
new_repo->serviceName = strdup(iter->service().c_str());
}

struct RepositoryList result = {static_cast<unsigned>(size), repos};
Expand Down
6 changes: 5 additions & 1 deletion rust/zypp-agama/zypp-agama-sys/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,16 +547,20 @@ pub struct Repository {
pub alias: *mut ::std::os::raw::c_char,
#[doc = "< owned"]
pub userName: *mut ::std::os::raw::c_char,
#[doc = "< owned"]
pub serviceName: *mut ::std::os::raw::c_char,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
["Size of Repository"][::std::mem::size_of::<Repository>() - 32usize];
["Size of Repository"][::std::mem::size_of::<Repository>() - 40usize];
["Alignment of Repository"][::std::mem::align_of::<Repository>() - 8usize];
["Offset of field: Repository::enabled"][::std::mem::offset_of!(Repository, enabled) - 0usize];
["Offset of field: Repository::url"][::std::mem::offset_of!(Repository, url) - 8usize];
["Offset of field: Repository::alias"][::std::mem::offset_of!(Repository, alias) - 16usize];
["Offset of field: Repository::userName"]
[::std::mem::offset_of!(Repository, userName) - 24usize];
["Offset of field: Repository::serviceName"]
[::std::mem::offset_of!(Repository, serviceName) - 32usize];
};
#[repr(C)]
#[derive(Debug, Copy, Clone)]
Expand Down
Loading