Skip to content

Commit fac01dc

Browse files
committed
Add simple json output.
Prints the internal Vec<Diff> as json. We might want to fix some format in the future, since the output is currently quite verbose.
1 parent 967b958 commit fac01dc

File tree

3 files changed

+91
-6
lines changed

3 files changed

+91
-6
lines changed

src/diff.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use pathfinding::{
3333
kuhn_munkres,
3434
matrix::Matrix,
3535
};
36+
#[cfg(feature = "json")] use serde::Serialize;
3637
use size::Size;
3738
use unicode_width::UnicodeWidthStr as _;
3839
use yansi::{
@@ -53,7 +54,7 @@ use crate::{
5354
},
5455
};
5556

56-
fn create_backend<'a>(
57+
pub(crate) fn create_backend<'a>(
5758
force_correctness: bool,
5859
) -> store::CombinedStoreBackend<'a> {
5960
if force_correctness {
@@ -64,6 +65,7 @@ fn create_backend<'a>(
6465
}
6566

6667
#[derive(Debug, Eq, PartialEq)]
68+
#[cfg_attr(feature = "json", derive(Serialize))]
6769
pub struct Diff<T = Vec<Version>> {
6870
pub name: String,
6971
pub old: T,
@@ -90,13 +92,15 @@ where
9092
}
9193

9294
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95+
#[cfg_attr(feature = "json", derive(Serialize))]
9396
pub enum Change {
9497
UpgradeDowngrade,
9598
Upgraded,
9699
Downgraded,
97100
}
98101

99102
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103+
#[cfg_attr(feature = "json", derive(Serialize))]
100104
pub enum DiffStatus {
101105
Changed(Change),
102106
Added,
@@ -146,6 +150,7 @@ impl cmp::Ord for DiffStatus {
146150
/// Documents if the derivation is a system package and if
147151
/// it was added / removed as such.
148152
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
153+
#[cfg_attr(feature = "json", derive(Serialize))]
149154
pub enum DerivationSelectionStatus {
150155
/// The derivation is a system package, status unchanged.
151156
Selected,
@@ -522,7 +527,7 @@ pub fn write_packages_diffln(
522527
///
523528
/// Takes an iterator of store paths and extracts the package names,
524529
/// filtering out any that cannot be parsed. Logs warnings for parse failures.
525-
fn collect_system_names(
530+
pub(crate) fn collect_system_names(
526531
paths: impl Iterator<Item = StorePath>,
527532
context: &str,
528533
) -> HashSet<String> {
@@ -544,7 +549,7 @@ fn collect_system_names(
544549
/// Creates a mapping from package names to their versions in old and new paths.
545550
/// For each package, stores a tuple of (`old_versions`, `new_versions`).
546551
/// Handles parsing errors by logging warnings and skipping problematic entries.
547-
fn collect_path_versions(
552+
pub(crate) fn collect_path_versions(
548553
old: impl Iterator<Item = StorePath>,
549554
new: impl Iterator<Item = StorePath>,
550555
) -> HashMap<String, (Vec<Version>, Vec<Version>)> {

src/json.rs

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,89 @@
11
use std::path::PathBuf;
22

3-
use anyhow::Result;
3+
use anyhow::{
4+
Context as _,
5+
Result,
6+
};
7+
use serde::Serialize;
8+
9+
use crate::{
10+
diff::{
11+
Diff,
12+
add_selection_status,
13+
collect_path_versions,
14+
collect_system_names,
15+
create_backend,
16+
},
17+
generate_diffs_from_paths,
18+
store::StoreBackend as _,
19+
};
420

521
pub fn display_diff(
6-
old_path: &PathBuf,
7-
new_path: &PathBuf,
22+
path_old: &PathBuf,
23+
path_new: &PathBuf,
824
force_correctness: bool,
925
) -> Result<()> {
26+
let mut connection = create_backend(force_correctness);
27+
connection.connect()?;
28+
29+
// Query dependencies for old path
30+
let paths_old = connection.query_dependents(path_old).with_context(|| {
31+
format!("failed to query dependencies of '{}'", path_old.display())
32+
})?;
33+
34+
// Query dependencies for new path
35+
let paths_new = connection.query_dependents(path_new).with_context(|| {
36+
format!("failed to query dependencies of '{}'", path_new.display())
37+
})?;
38+
39+
// Query system derivations for old path
40+
let system_derivations_old = connection
41+
.query_system_derivations(path_old)
42+
.with_context(|| {
43+
format!(
44+
"failed to query system derivations of '{}'",
45+
path_old.display()
46+
)
47+
})?;
48+
49+
// Query system derivations for new path
50+
let system_derivations_new = connection
51+
.query_system_derivations(path_new)
52+
.with_context(|| {
53+
format!(
54+
"failed to query system derivations of '{}'",
55+
path_new.display()
56+
)
57+
})?;
58+
59+
let paths_map = collect_path_versions(paths_old, paths_new);
60+
let sys_old_set = collect_system_names(system_derivations_old, "old");
61+
let sys_new_set = collect_system_names(system_derivations_new, "new");
62+
63+
let mut diffs = generate_diffs_from_paths(paths_map);
64+
add_selection_status(&mut diffs, &sys_old_set, &sys_new_set);
65+
let size_old = connection.query_closure_size(path_old)?.bytes();
66+
let size_new = connection.query_closure_size(path_new)?.bytes();
67+
68+
let json = report_to_json(JsonReport {
69+
diffs,
70+
size_old,
71+
size_new,
72+
})?;
73+
print!("{json}");
1074
Ok(())
1175
}
76+
77+
#[derive(Serialize)]
78+
pub struct JsonReport {
79+
/// package changes
80+
diffs: Vec<Diff>,
81+
/// old closure size (in bytes)
82+
size_old: i64,
83+
/// new closure size (in bytes)
84+
size_new: i64,
85+
}
86+
87+
pub fn report_to_json(diffs: JsonReport) -> Result<String> {
88+
serde_json::to_string(&diffs).map_err(|e| e.into())
89+
}

src/version.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use derive_more::{
1010
Display,
1111
From,
1212
};
13+
#[cfg(feature = "json")] use serde::Serialize;
1314

1415
/// A type representing a version string.
1516
///
@@ -21,6 +22,7 @@ pub const VERSION_SEPARATORS: &[char] =
2122
&['.', '-', '_', '+', '*', '=', '×', ' '];
2223

2324
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25+
#[cfg_attr(feature = "json", derive(Serialize))]
2426
pub struct Version {
2527
pub name: String,
2628
pub amount: usize,

0 commit comments

Comments
 (0)