diff --git a/src/main.rs b/src/main.rs index 9e54fd0..fad20b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -97,6 +97,7 @@ fn main() { println!("<<< {}", args.path.to_string_lossy()); println!(">>> {}", args.path2.to_string_lossy()); + // handles to the threads collecting closure size information // We do this as early as possible because nix is slow. let closure_size_handles = if args.closure_size { @@ -115,7 +116,7 @@ fn main() { let package_list_pre = match store::get_packages(&args.path) { Ok(packages) => { debug!("Found {} packages in first closure", packages.len()); - packages + packages.into_iter().map(|(_, path)| path).collect() } Err(e) => { error!( @@ -135,7 +136,7 @@ fn main() { let package_list_post = match store::get_packages(&args.path2) { Ok(packages) => { debug!("Found {} packages in second closure", packages.len()); - packages + packages.into_iter().map(|(_, path)| path).collect() } Err(e) => { error!( @@ -184,6 +185,7 @@ fn main() { // Difference gives us added and removed packages let added: HashSet<&str> = &post_keys - &pre_keys; + let removed: HashSet<&str> = &pre_keys - &post_keys; // Get the intersection of the package names for version changes let changed: HashSet<&str> = &pre_keys & &post_keys; diff --git a/src/store.rs b/src/store.rs index 5c16b18..e396755 100644 --- a/src/store.rs +++ b/src/store.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::error::AppError; use rusqlite::Connection; @@ -14,7 +16,7 @@ WITH RECURSIVE SELECT reference FROM Refs JOIN graph ON referrer = p ) -SELECT path from graph +SELECT id, path from graph JOIN ValidPaths ON id = p; "; @@ -32,18 +34,37 @@ SELECT SUM(narSize) as sum from graph JOIN ValidPaths ON p = id; "; +const QUERY_DEPENDENCY_GRAPH: &str = " +WITH RECURSIVE + graph(p, c) AS ( + SELECT id as par, reference as chd + FROM ValidPaths + JOIN Refs ON referrer = id + WHERE path = ? + UNION + SELECT referrer as par, reference as chd FROM Refs + JOIN graph ON referrer = c + ) +SELECT p, c from graph; +"; + /// executes a query on the nix db directly /// to gather all derivations that the derivation given by the path /// depends on /// +/// The ids of the derivations in the database are returned as well, since these +/// can be used to later convert nodes (represented by the the ids) of the +/// dependency graph to actual paths +/// /// in the future, we might wan't to switch to async -pub fn get_packages(path: &std::path::Path) -> Result> { +pub fn get_packages(path: &std::path::Path) -> Result> { let p: String = path.canonicalize()?.to_string_lossy().into_owned(); let conn = Connection::open("/nix/var/nix/db/db.sqlite")?; let mut stmt = conn.prepare(QUERY_PKGS)?; - let queried_pkgs: std::result::Result, _> = - stmt.query_map([p], |row| row.get(0))?.collect(); + let queried_pkgs: std::result::Result, _> = + stmt.query_map([p], |row| Ok((row.get(0)?, row.get(1)?)))? + .collect(); Ok(queried_pkgs?) } @@ -61,3 +82,30 @@ pub fn get_closure_size(path: &std::path::Path) -> Result { let queried_sum = stmt.query_row([p], |row| row.get(0))?; Ok(queried_sum) } + + +/// returns the complete dependency graph of +/// of the derivation as an adjacency list. The nodes are +/// represented by the DB ids +/// +/// We might want to collect the paths in the graph directly as +/// well in the future, depending on how much we use them +/// in the operations on the graph +/// +/// The mapping from id to graph can be obtained by using [get_packages] +pub fn get_dependency_graph(path: &std::path::Path) -> Result>> { + let p: String = path.canonicalize()?.to_string_lossy().into_owned(); + let conn = Connection::open("/nix/var/nix/db/db.sqlite")?; + + let mut stmt = conn.prepare(QUERY_DEPENDENCY_GRAPH)?; + let mut adj = HashMap::>::new(); + let queried_sum = stmt.query_map( + [p], + |row| Ok::<(i64, i64), _>((row.get(0)?, row.get(1)?)))?; + for row in queried_sum { + let (from, to) = row?; + adj.entry(from).or_default().push(to); + } + + Ok(adj) +}