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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,21 @@ cmake

## **Integration tests**

Integration tests runs inside docker images tagged `local/cnf-ci-zypper`, `local/cnf-ci-dnf`, and `local/cnf-ci-dnf5`. these are built as a part of Github Action and can be built locally with:
Integration tests run inside docker images tagged `local/cnf-ci-zypper`, `local/cnf-ci-dnf`, and `local/cnf-ci-dnf5`; these are built as a part of a Github Action and can be built locally with:

```.sh
for pm in zypper dnf dnf5; do
docker build -t local/cnf-ci-$pm:latest -f test/$pm.dockerfile test
done
```

The testing itself is wrapped in [bats](https://github.com/bats-core/bats-core) and in order to make it run, one needs to initialize the git submodules (`git submodule update --init`). Then tests can be executed using a following command
The testing itself is wrapped in [bats](https://github.com/bats-core/bats-core) and in order to make it run, one needs to initialize the git submodules (`git submodule update --init`). Then tests can be executed using following command

```.sh
./test/bats/bin/bats ./test/
```
> ```.log
> test.bats
> ✓ zypper root: installed /usr/bin/rpm
> ✓ zypper root: installed /usr/sbin/sysctl
> ✓ zypper root: not installed xnake
Expand Down
6 changes: 6 additions & 0 deletions cnf.1
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ Try installing with:
bash(1), zsh(1), fish(1), libsolv(3)
.SH BUGS
No support for localization other than UTF-8.
.PP
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surprisingly noone ever complained about neither in this variant, neither in an original Python implementation. But good too have this fixed.

It is assumed that the following configuration variables have not been changed from their openSUSE defaults:
for zypper (usually set in /etc/zypp/zypp.conf): reposdir, cachedir, and solvfilesdir
for dnf/dnf5 (usually set in /etc/dnf/dnf.conf): reposdir and system_cachedir


.SH "AUTHOR"
.PP
\fBMichal Vyskocil\fR <\&mvyskocil@opensuse\&.org\&>
Expand Down
56 changes: 26 additions & 30 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,10 @@ use std::vec::Vec;
mod ini;
mod pool;

const ZYPPER_REPO_GLOB: &str = "/etc/zypp/repos.d/*.repo";
// Default value of the reposdir configuration directory
const DNF4_REPOS_GLOBS: [&str; 3] = [
"/etc/dnf/repos.d/*.repo",
"/etc/yum.repos.d/*.repo",
"/etc/distro.repos.d/*.repo"
];
// Default value of the reposdir configuration directory
// (Note that /etc/dnf/repos.d is patched in by the openSUSE dnf5 package)
const DNF5_REPOS_GLOBS: [&str; 4] = [
"/etc/dnf/repos.d/*.repo",
"/etc/yum.repos.d/*.repo",
"/etc/distro.repos.d/*.repo",
"/usr/share/dnf5/repos.d/*.repo",
];

#[derive(Clone, Copy)]
pub enum PackageManager {
Zypper,
Dnf4,
Dnf,
Dnf5,
}
pub struct SolvInput {
Expand Down Expand Up @@ -77,16 +61,16 @@ fn main() {
}

let pm = if Path::exists(Path::new("/usr/bin/dnf5")) {
// Use DNF5 if it's installed from the openSUSE repo (since zypper is the default, someone is only likely to have dnf5 installed if they want to use it)
// Use dnf5 if it's installed from the openSUSE repo (since zypper is the default, someone is only likely to have dnf5 installed if they want to use it)
PackageManager::Dnf5
} else if Path::exists(Path::new("/usr/bin/dnf")) {
// Use DNF4 if it's installed, but dnf5 isn't
// Use an old dnf if it's installed, but dnf5 isn't
// (in case a dnf5 user symlinks /usr/bin/dnf to /usr/bin/dnf5, this goes after the dnf5 check)
PackageManager::Dnf4
PackageManager::Dnf
} else if Path::exists(Path::new("/usr/bin/zypper")) {
PackageManager::Zypper
} else {
println!("Neither /usr/bin/dnf5, /usr/bin/dnf, norr /usr/bin/zypper could be found.");
println!("Neither /usr/bin/dnf5, /usr/bin/dnf, nor /usr/bin/zypper could be found.");
exit(127);
};

Expand Down Expand Up @@ -153,18 +137,29 @@ fn search_in_repos<'a>(
);
match pm {
PackageManager::Zypper => println!(" sudo zypper install {}\n", suggested_package),
PackageManager::Dnf4 => println!(" sudo dnf install {}\n", suggested_package),
PackageManager::Dnf => println!(" sudo dnf install {}\n", suggested_package),
PackageManager::Dnf5 => println!(" sudo dnf5 install {}\n", suggested_package),
}
Ok(())
}

fn load_repos<'a>(pm: PackageManager) -> Result<Vec<SolvInput>, ErrorKind<'a>> {
let mut repos: Vec<SolvInput> = Vec::new();
// These use the default values of the reposdir configuration options for the various package managers
let globs = match pm {
PackageManager::Zypper => &[ZYPPER_REPO_GLOB] as &[&str],
PackageManager::Dnf4 => &DNF4_REPOS_GLOBS as &[&str],
PackageManager::Dnf5 => &DNF5_REPOS_GLOBS as &[&str],
PackageManager::Zypper => &["/etc/zypp/repos.d/*.repo"] as &[&str],
PackageManager::Dnf => &[
"/etc/dnf/repos.d/*.repo",
"/etc/yum.repos.d/*.repo",
"/etc/distro.repos.d/*.repo",
] as &[&str],
PackageManager::Dnf5 => &[
// This first one is patched in by the openSUSE dnf5 package, and is not mentioned in the documentation
"/etc/dnf/repos.d/*.repo",
"/etc/yum.repos.d/*.repo",
"/etc/distro.repos.d/*.repo",
"/usr/share/dnf5/repos.d/*.repo",
] as &[&str],
};
for glob in globs {
for repo in glob::glob(glob)? {
Expand All @@ -175,18 +170,19 @@ fn load_repos<'a>(pm: PackageManager) -> Result<Vec<SolvInput>, ErrorKind<'a>> {
let info = ini::repo_enabled(reader)?;
if info.enabled {
let solv_glob = match pm {
// This uses the default solvfilesdir configuration option for libzypp,
// (solvfilesdir defaults to $cachedir/solv, and cachedir defaults to /var/cache/zypp)
PackageManager::Zypper => {
format!("/var/cache/zypp/solv/{}/solv", info.name.replace('/', "_"))
}
// This uses the default system_cachedir configuration option for dnf
// Non superusers however use cachedir option (which defaults to /var/tmp/dnf-<username>-<random suffix>)
// I'm choosing the system one as dnf is more likely to be run with sudo
PackageManager::Dnf4 => format!(
"/var/cache/dnf/{}.solv",
info.name.replace('/', "_")
),
PackageManager::Dnf => {
format!("/var/cache/dnf/{}.solv", info.name.replace('/', "_"))
}

// As with dnf4, this uses the default system_cachedir value
// As with the old dnf, this uses the default system_cachedir value
// (The default non-superuser cachedir is ~/.cache/libdnf5)
PackageManager::Dnf5 => format!(
"/var/cache/libdnf5/{}-*/solv/*.solv",
Expand Down
Loading