Verified Commit c76add7f authored by Jelle van der Waa's avatar Jelle van der Waa 🚧
Browse files

Handle provided packages of packages in pkgnames

Packages in our repository have makedepends to a "provide" for example
irccat has a makedepend on go-pie which is provided by go. As we do not
want to have provides in our rebuild list we can not simply only add it
as a new package in pkgnames, the algorithm now "resolves" provided
pkgnames to the repository package.
parent 0606ddbe
Pipeline #5345 passed with stages
in 2 minutes and 15 seconds
......@@ -18,13 +18,15 @@ cargo run opencolorio
## Algorithm
Arch-rebuild-order uses the local syncdb to build a hashmap, mapping packages
to their reverse (make) dependencies. It adds the provided pkgnames to the
**to_visit** list and iterates over each entry, pops it to inspect and in turn
adds all found reverse dependencies again to the **to_visit** list. It repeats
this cycle until the entire **to_visit** list is empty.
During this iteration process a pkg node is created in a DiGraph and for all reverse dependencies
of this package additional node are created and added as an edge of the parent pkg node.
to their reverse (make) dependencies. The provided pkgnames are looked up in
the syncdb and a hashmap is built of the package provides and the pkgname
called **provides_map**. The **pkgnames** and **provides** are added to the
**to_visit** list and this then starts the iteration over every entry in the
list. During each iteration, the real package name is resolved if the provided
package comes from provides using the **provides_map**, a graph node is created
for the entry. For all reverse (make) dependencies of the entry, the dependency is added to
the **to_visit** list, a new graph node is created and added as an edge of the
pkg node. This repeats until the **to_visit** list is empty.
## DOT output
......
......@@ -91,18 +91,26 @@ pub fn run(
}
let reverse_deps_map = get_reverse_deps_map(&pacman);
let mut provides = Vec::new();
let mut provides_map = HashMap::new();
for pkg in &pkgnames {
find_package_anywhere(&pkg, &pacman)?;
let repopkg = find_package_anywhere(&pkg, &pacman)?;
for provide in repopkg.provides() {
provides.push(provide.name());
provides_map.insert(provide.name(), repopkg.name());
}
}
let mut graph = DiGraph::<&str, u16>::new();
let mut to_visit = VecDeque::new();
let mut to_build = HashSet::new();
to_visit.extend(pkgnames.iter().map(|x| x.as_str()));
to_visit.extend(provides.iter());
let mut cache_node = HashMap::new();
let mut cache_node: HashMap<&str, petgraph::graph::NodeIndex> = HashMap::new();
while !to_visit.is_empty() {
let pkg = if let Some(pkg) = to_visit.pop_front() {
......@@ -111,7 +119,12 @@ pub fn run(
break;
};
let root = *cache_node.entry(pkg).or_insert_with(|| graph.add_node(pkg));
// Resolve the provided package to the real package as provided packages are not real
// packages in the Arch Linux repository.
let rootpkg = provides_map.get(&pkg).unwrap_or(&pkg);
let root = *cache_node
.entry(rootpkg)
.or_insert_with(|| graph.add_node(rootpkg));
if let Some(rev_deps_for_pkg) = reverse_deps_map.get(pkg) {
if to_build.get(&pkg.to_string()).is_none() {
......@@ -120,7 +133,7 @@ pub fn run(
for rev_dep in rev_deps_for_pkg {
let depnode = *cache_node
.entry(rev_dep)
.entry(&rev_dep.as_str())
.or_insert_with(|| graph.add_node(rev_dep));
if !graph.contains_edge(root, depnode) {
graph.add_edge(root, depnode, 1);
......
......@@ -17,6 +17,7 @@ pub struct Package {
pub version: String,
pub depends: Vec<String>,
pub makedepends: Vec<String>,
pub provides: Vec<String>,
}
impl Package {
......@@ -26,6 +27,7 @@ impl Package {
version: &str,
depends: Vec<String>,
makedepends: Vec<String>,
provides: Vec<String>,
) -> Package {
Package {
name: name.to_string(),
......@@ -33,6 +35,7 @@ impl Package {
version: version.to_string(),
depends,
makedepends,
provides,
}
}
......@@ -63,6 +66,15 @@ impl Package {
desc.push_str("\n");
}
if !self.provides.is_empty() {
desc.push_str("%PROVIDES%\n");
for dep in self.provides.iter() {
desc.push_str(dep);
desc.push_str("\n");
}
desc.push_str("\n");
}
desc
}
......@@ -143,7 +155,7 @@ pub fn invalid_dbpath() -> (Vec<String>, Option<String>) {
#[fixture]
pub fn no_reverse_deps() -> (Vec<Package>, Option<String>, Vec<String>, TempDir) {
let testpkg = Package::new("testpkg1", "testpkg1", "1.0-1", vec![], vec![]);
let testpkg = Package::new("testpkg1", "testpkg1", "1.0-1", vec![], vec![], vec![]);
let packages = vec![testpkg];
let reponame = "test";
......@@ -154,13 +166,14 @@ pub fn no_reverse_deps() -> (Vec<Package>, Option<String>, Vec<String>, TempDir)
#[fixture]
pub fn reverse_deps() -> (Vec<String>, Option<String>, Vec<String>, TempDir) {
let testpkg = Package::new("testpkg1", "testpkg1", "1-1", vec![], vec![]);
let testpkg = Package::new("testpkg1", "testpkg1", "1-1", vec![], vec![], vec![]);
let testpkg2 = Package::new(
"testpkg2",
"testpkg2",
"1-1",
vec![testpkg.name.clone()],
vec![],
vec![],
);
let pkgnames = vec![testpkg.name.clone(), testpkg2.name.clone()];
let packages = vec![testpkg, testpkg2];
......@@ -173,13 +186,14 @@ pub fn reverse_deps() -> (Vec<String>, Option<String>, Vec<String>, TempDir) {
#[fixture]
pub fn multiple_deps() -> (Vec<Package>, Option<String>, Vec<String>, TempDir) {
let testpkg = Package::new("testpkg1", "testpkg1", "1.0-1", vec![], vec![]);
let testpkg = Package::new("testpkg1", "testpkg1", "1.0-1", vec![], vec![], vec![]);
let testpkg2 = Package::new(
"testpkg2",
"testpkg2",
"1.0-1",
vec![testpkg.name.clone()],
vec![],
vec![],
);
let testpkg3 = Package::new(
"testpkg3",
......@@ -187,6 +201,7 @@ pub fn multiple_deps() -> (Vec<Package>, Option<String>, Vec<String>, TempDir) {
"1-1",
vec![testpkg.name.clone(), testpkg2.name.clone()],
vec![],
vec![],
);
let packages = vec![testpkg3, testpkg2, testpkg];
......@@ -198,13 +213,40 @@ pub fn multiple_deps() -> (Vec<Package>, Option<String>, Vec<String>, TempDir) {
#[fixture]
pub fn reverse_make_deps() -> (Vec<Package>, Option<String>, Vec<String>, TempDir) {
let testpkg = Package::new("testpkg1", "testpkg1", "1-1", vec![], vec![]);
let testpkg = Package::new("testpkg1", "testpkg1", "1-1", vec![], vec![], vec![]);
let testpkg2 = Package::new(
"testpkg2",
"testpkg2",
"1-1",
vec![],
vec![testpkg.name.clone()],
vec![],
);
let packages = vec![testpkg, testpkg2];
let reponame = "test";
let (tempdir, dbpath) = init_repodb(reponame.to_string(), packages.clone());
(packages, Some(dbpath), vec![reponame.to_string()], tempdir)
}
#[fixture]
pub fn provides_make_depends() -> (Vec<Package>, Option<String>, Vec<String>, TempDir) {
let testpkg = Package::new(
"testpkg1",
"testpkg1",
"1-1",
vec![],
vec![],
vec!["pkg1".to_string()],
);
let testpkg2 = Package::new(
"testpkg2",
"testpkg2",
"1-1",
vec![],
vec![testpkg.provides[0].clone()],
vec![],
);
let packages = vec![testpkg, testpkg2];
......@@ -216,13 +258,14 @@ pub fn reverse_make_deps() -> (Vec<Package>, Option<String>, Vec<String>, TempDi
#[fixture]
pub fn dependency_depth() -> (Vec<Package>, Option<String>, Vec<String>, TempDir) {
let testpkg = Package::new("testpkg1", "testpkg1", "1-1", vec![], vec![]);
let testpkg = Package::new("testpkg1", "testpkg1", "1-1", vec![], vec![], vec![]);
let testpkg2 = Package::new(
"testpkg2",
"testpkg2",
"1-1",
vec![],
vec![testpkg.name.clone()],
vec![],
);
let testpkg3 = Package::new(
"testpkg3",
......@@ -230,6 +273,7 @@ pub fn dependency_depth() -> (Vec<Package>, Option<String>, Vec<String>, TempDir
"1-1",
vec![],
vec![testpkg2.name.clone()],
vec![],
);
let packages = vec![testpkg, testpkg2, testpkg3];
......@@ -247,6 +291,7 @@ pub fn dependency_cycle() -> (Vec<Package>, Option<String>, Vec<String>, TempDir
"1-1",
vec![String::from("testpkg2")],
vec![],
vec![],
);
let testpkg2 = Package::new(
"testpkg2",
......@@ -254,6 +299,7 @@ pub fn dependency_cycle() -> (Vec<Package>, Option<String>, Vec<String>, TempDir
"1-1",
vec![testpkg.name.clone()],
vec![],
vec![],
);
dbg!(testpkg.clone());
dbg!(testpkg2.clone());
......
......@@ -5,7 +5,7 @@ pub mod fixtures;
use fixtures::{
dependency_cycle, dependency_depth, invalid_dbpath, multiple_deps, no_reverse_deps,
reverse_deps, reverse_make_deps, Package,
provides_make_depends, reverse_deps, reverse_make_deps, Package,
};
#[rstest]
......@@ -67,6 +67,26 @@ fn test_reverse_make_deps(reverse_make_deps: (Vec<Package>, Option<String>, Vec<
assert_eq!(packages, res_pkgs);
}
/// Given a package 'testpkg1' which provides 'pkg1' where 'testpkg2' make depends on 'pkg1',
/// the rebuild order should be 'testpkg1 testpkg2'
#[rstest]
fn test_provides_make_depends(
provides_make_depends: (Vec<Package>, Option<String>, Vec<String>, TempDir),
) {
let packages = provides_make_depends.0;
let pkgname = &packages[0].name;
let res = arch_rebuild_order::run(
vec![pkgname.to_string()],
provides_make_depends.1,
provides_make_depends.2,
None,
)
.unwrap();
let res_pkgs: Vec<&str> = res.trim().split_ascii_whitespace().collect();
assert_eq!(packages, res_pkgs);
}
/// Given a package 'testpkg1' with a reverse dependency of 'testpkg2' and 'testpkg3', the rebuild
/// order should be 'testpkg1 'testpkg2 testpkg3'
#[rstest]
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment