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
68 changes: 3 additions & 65 deletions Cargo.lock

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

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ diff = "0.1.13"
itertools = "0.14.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = [ "env-filter" ] }
ouroboros = "0.18.5"
pathfinding = "4.14.0"
regex = "1.11.1"
rusqlite = { features = [ "bundled" ], version = "0.39.0" }
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ Options:
[possible values: auto, always, never]

--force-correctness
Fall back to a backend that is focused solely on absolutely guaranteeing correct results at the cost of memory usage and query speed.
Fall back to a backend chain that skips SQLite immutable mode.

This is relevant if the output of dix is to be used for more critical applications and not just as human-readable overview.

In the vast, vast majority of cases, the default backend should be sufficient.
The default backend falls back to opening Nix's SQLite database with `?immutable=1` if the normal connection fails. That is faster than Nix commands, but can be inaccurate if the database is being written to at the same time.

--output <OUTPUT>
Select the output format to use
Expand Down
33 changes: 14 additions & 19 deletions src/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,6 @@ use crate::{
},
};

pub(crate) fn create_backend<'a>(
force_correctness: bool,
) -> store::CombinedStoreBackend<'a> {
if force_correctness {
store::CombinedStoreBackend::default_eager()
} else {
store::CombinedStoreBackend::default_lazy()
}
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "json", derive(Serialize))]
pub struct Diff<T = Vec<Version>> {
Expand Down Expand Up @@ -213,7 +203,8 @@ pub fn write_package_diff(
force_correctness = force_correctness,
"starting package diff computation"
);
let mut connection = create_backend(force_correctness);
let mut connection =
store::CombinedStoreBackend::for_correctness(force_correctness);
connection.connect()?;

tracing::debug!("querying dependencies for old path");
Expand Down Expand Up @@ -417,18 +408,20 @@ fn count_versions(versions: Vec<Version>) -> HashMap<Version, usize> {
/// Returns an error if it fails writing to the `writer`
pub fn write_packages_diff(
writer: &mut impl fmt::Write,
paths_old: impl Iterator<Item = StorePath>,
paths_new: impl Iterator<Item = StorePath>,
system_paths_old: impl Iterator<Item = StorePath>,
system_paths_new: impl Iterator<Item = StorePath>,
paths_old: impl IntoIterator<Item = StorePath>,
paths_new: impl IntoIterator<Item = StorePath>,
system_paths_old: impl IntoIterator<Item = StorePath>,
system_paths_new: impl IntoIterator<Item = StorePath>,
) -> Result<usize, fmt::Error> {
let paths_map = collect_path_versions(paths_old, paths_new);

let sys_old_set: HashSet<String> = system_paths_old
.into_iter()
.filter_map(|p| p.parse_name_and_version().ok().map(|(n, _)| n.into()))
.collect();

let sys_new_set: HashSet<String> = system_paths_new
.into_iter()
.filter_map(|p| p.parse_name_and_version().ok().map(|(n, _)| n.into()))
.collect();

Expand All @@ -446,10 +439,11 @@ pub fn write_packages_diff(
/// Takes an iterator of store paths and extracts the package names,
/// filtering out any that cannot be parsed. Logs warnings for parse failures.
pub(crate) fn collect_system_names(
paths: impl Iterator<Item = StorePath>,
paths: impl IntoIterator<Item = StorePath>,
context: &str,
) -> HashSet<String> {
paths
.into_iter()
.filter_map(|path| {
match path.parse_name_and_version() {
Ok((name, _)) => Some(name.into()),
Expand All @@ -468,8 +462,8 @@ pub(crate) fn collect_system_names(
/// For each package, stores a tuple of (`old_versions`, `new_versions`).
/// Handles parsing errors by logging warnings and skipping problematic entries.
pub(crate) fn collect_path_versions(
old: impl Iterator<Item = StorePath>,
new: impl Iterator<Item = StorePath>,
old: impl IntoIterator<Item = StorePath>,
new: impl IntoIterator<Item = StorePath>,
) -> HashMap<String, (Vec<Version>, Vec<Version>)> {
let mut paths: HashMap<String, (Vec<Version>, Vec<Version>)> = HashMap::new();
let mut old_count = 0usize;
Expand Down Expand Up @@ -891,7 +885,8 @@ pub fn spawn_size_diff(
tracing::debug!("calculating closure sizes in background");

thread::spawn(move || {
let mut connection = create_backend(force_correctness);
let mut connection =
store::CombinedStoreBackend::for_correctness(force_correctness);
connection.connect()?;

let result = (
Expand Down
16 changes: 9 additions & 7 deletions src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,29 @@ use crate::{
add_selection_status,
collect_path_versions,
collect_system_names,
create_backend,
},
generate_diffs_from_paths,
store::StoreBackend,
store::{
CombinedStoreBackend,
StoreBackend,
},
};

pub fn display_diff(
path_old: &PathBuf,
path_new: &PathBuf,
force_correctness: bool,
) -> Result<()> {
let mut connection = create_backend(force_correctness);
let mut connection = CombinedStoreBackend::for_correctness(force_correctness);
connection.connect()?;
generate_diff(&mut std::io::stdout(), path_old, path_new, &connection)
}

fn generate_diff<'a>(
fn generate_diff(
out: &mut dyn Write,
path_old: &PathBuf,
path_new: &PathBuf,
backend: &impl StoreBackend<'a>,
backend: &impl StoreBackend,
) -> Result<()> {
// Query dependencies for old path
let paths_old = backend.query_dependents(path_old).with_context(|| {
Expand Down Expand Up @@ -106,7 +108,7 @@ mod tests {

use super::*;
use crate::store::{
LazyDBConnection,
DbConnection,
test_utils::{
self,
// TestDbBuilder,
Expand All @@ -118,7 +120,7 @@ mod tests {
let db_builder =
test_utils::create_system_test_db().expect("failed to create test db");
let db_path = db_builder.db_path().to_string_lossy().to_string();
let mut db = LazyDBConnection::new(&db_path);
let mut db = DbConnection::new(&db_path);
db.connect().unwrap();
let system_old =
db_builder.resolve_fixture_path(&fixtures::system_path("nixos-25.11"));
Expand Down
9 changes: 5 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@ struct Cli {
)]
color: clap::ColorChoice,

/// Fall back to a backend that is focused solely on absolutely guaranteeing
/// correct results at the cost of memory usage and query speed.
/// Fall back to a backend chain that skips SQLite immutable mode.
///
/// This is relevant if the output of dix is to be used for more
/// critical applications and not just as human-readable overview.
///
/// In the vast, vast majority of cases, the default backend should be
/// sufficient.
/// The default backend falls back to opening Nix's SQLite database with
/// `?immutable=1` if the normal connection fails. That is faster than Nix
/// commands, but can be inaccurate if the database is being written to at
/// the same time.
#[arg(long, default_value_t = false, global = true)]
force_correctness: bool,

Expand Down
Loading
Loading