tangled
alpha
login
or
join now
tgirl.cloud
/
lix-diff
0
fork
atom
this repo has no description
0
fork
atom
overview
issues
pulls
pipelines
feat: sort by size
closes #13
isabelroses.com
3 months ago
42f10e90
778bab9d
+151
-46
6 changed files
expand all
collapse all
unified
split
Cargo.lock
Cargo.toml
src
diff.rs
main.rs
package.rs
parser.rs
+19
Cargo.lock
···
238
"nu-ansi-term",
239
"serde",
240
"serde_json",
0
241
]
242
243
[[package]]
···
380
]
381
382
[[package]]
0
0
0
0
0
0
0
0
0
383
name = "strsim"
384
version = "0.11.1"
385
source = "registry+https://github.com/rust-lang/crates.io-index"
···
463
version = "0.1.1"
464
source = "registry+https://github.com/rust-lang/crates.io-index"
465
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
0
0
0
0
0
0
0
0
0
466
467
[[package]]
468
name = "windows-link"
···
238
"nu-ansi-term",
239
"serde",
240
"serde_json",
241
+
"strip-ansi-escapes",
242
]
243
244
[[package]]
···
381
]
382
383
[[package]]
384
+
name = "strip-ansi-escapes"
385
+
version = "0.2.1"
386
+
source = "registry+https://github.com/rust-lang/crates.io-index"
387
+
checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025"
388
+
dependencies = [
389
+
"vte",
390
+
]
391
+
392
+
[[package]]
393
name = "strsim"
394
version = "0.11.1"
395
source = "registry+https://github.com/rust-lang/crates.io-index"
···
473
version = "0.1.1"
474
source = "registry+https://github.com/rust-lang/crates.io-index"
475
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
476
+
477
+
[[package]]
478
+
name = "vte"
479
+
version = "0.14.1"
480
+
source = "registry+https://github.com/rust-lang/crates.io-index"
481
+
checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077"
482
+
dependencies = [
483
+
"memchr",
484
+
]
485
486
[[package]]
487
name = "windows-link"
+1
Cargo.toml
···
14
nu-ansi-term = "0.50.1"
15
serde = { version = "1.0.223", features = ["derive"] }
16
serde_json = "1.0.145"
0
17
18
[lints.clippy]
19
all = "warn"
···
14
nu-ansi-term = "0.50.1"
15
serde = { version = "1.0.223", features = ["derive"] }
16
serde_json = "1.0.145"
17
+
strip-ansi-escapes = "0.2.1"
18
19
[lints.clippy]
20
all = "warn"
+102
-42
src/diff.rs
···
1
-
use humansize::{format_size, DECIMAL};
2
use nu_ansi_term::Color::{self, Green, Red, Yellow};
3
use std::collections::BTreeMap;
4
5
use super::{
6
-
package::{DiffType, Package},
7
parser::DiffRoot,
8
};
0
0
0
0
0
0
9
10
#[derive(Debug)]
11
pub struct PackageListDiff {
12
-
pub added: BTreeMap<String, Package>,
13
-
pub removed: BTreeMap<String, Package>,
14
-
pub changed: BTreeMap<String, Package>,
15
-
size_delta: i64,
0
16
longest_name: usize,
0
0
0
17
}
18
19
-
impl From<DiffRoot> for PackageListDiff {
20
-
fn from(diff: DiffRoot) -> Self {
21
-
let mut out = PackageListDiff {
0
22
added: BTreeMap::new(),
23
removed: BTreeMap::new(),
24
changed: BTreeMap::new(),
25
-
size_delta: 0,
26
longest_name: 0,
27
-
};
0
0
0
28
29
-
for (name, diff_package) in diff.packages {
30
-
let package = Package::from(diff_package);
0
0
0
0
0
0
31
32
-
out.size_delta += package.size_delta;
33
-
out.longest_name = out.longest_name.max(name.len());
34
35
-
match package.diff_type {
36
-
DiffType::Added => {
37
-
out.added.insert(name, package);
38
-
}
39
-
DiffType::Removed => {
40
-
out.removed.insert(name, package);
41
-
}
42
-
DiffType::Changed => {
43
-
out.changed.insert(name, package);
44
-
}
45
-
DiffType::Unknown => {
46
-
// This should never happen, but just in case
47
-
eprintln!("Unknown diff type for package: {name}");
48
-
}
49
-
}
50
}
51
52
-
out
53
}
54
}
55
56
-
impl std::fmt::Display for PackageListDiff {
57
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58
-
if self.added.is_empty() && self.removed.is_empty() && self.changed.is_empty() {
59
-
return write!(f, "No differences found.");
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
60
}
61
0
0
0
0
0
0
62
let title_style = nu_ansi_term::Style::new()
63
.underline()
64
.bold()
···
91
writeln!(f)?;
92
}
93
94
-
{
95
-
let delta = self.size_delta;
96
-
let sign = if delta > 0 { "+" } else { "-" };
97
-
let size: u64 = delta.abs().try_into().unwrap_or(0);
98
-
writeln!(f, "size diff: {sign}{}", format_size(size, DECIMAL))?;
99
-
}
100
101
-
Ok(())
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
102
}
103
}
···
0
1
use nu_ansi_term::Color::{self, Green, Red, Yellow};
2
use std::collections::BTreeMap;
3
4
use super::{
5
+
package::{DiffType, Package, SizeDelta},
6
parser::DiffRoot,
7
};
8
+
9
+
#[derive(Debug)]
10
+
pub struct PackageExtra {
11
+
name: String,
12
+
base_package: Package,
13
+
}
14
15
#[derive(Debug)]
16
pub struct PackageListDiff {
17
+
all: Vec<PackageExtra>,
18
+
added: BTreeMap<String, Package>,
19
+
removed: BTreeMap<String, Package>,
20
+
changed: BTreeMap<String, Package>,
21
+
size_delta: SizeDelta,
22
longest_name: usize,
23
+
24
+
// Whether to sort by size difference when displaying
25
+
pub by_size: bool,
26
}
27
28
+
impl PackageListDiff {
29
+
pub fn new() -> Self {
30
+
PackageListDiff {
31
+
all: Vec::new(),
32
added: BTreeMap::new(),
33
removed: BTreeMap::new(),
34
changed: BTreeMap::new(),
35
+
size_delta: SizeDelta(0),
36
longest_name: 0,
37
+
by_size: false,
38
+
}
39
+
}
40
+
}
41
42
+
impl std::fmt::Display for PackageListDiff {
43
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44
+
if self.by_size {
45
+
self.display_by_size(f)?;
46
+
} else {
47
+
if self.added.is_empty() && self.removed.is_empty() && self.changed.is_empty() {
48
+
return write!(f, "No differences found.");
49
+
}
50
51
+
self.display_by_category(f)?;
52
+
}
53
54
+
{
55
+
let delta = &self.size_delta;
56
+
writeln!(f, "size diff: {delta}")?;
0
0
0
0
0
0
0
0
0
0
0
0
57
}
58
59
+
Ok(())
60
}
61
}
62
63
+
impl PackageListDiff {
64
+
fn display_by_size(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65
+
let all = {
66
+
let mut v: Vec<_> = self.all.iter().collect();
67
+
v.sort_by_key(|pkg| -pkg.base_package.size_delta.0);
68
+
v
69
+
};
70
+
71
+
let name_width = self.longest_name + 2;
72
+
let package_width = (all
73
+
.iter()
74
+
.map(|pkg| strip_ansi_escapes::strip(format!("{}", pkg.base_package)).len())
75
+
.max()
76
+
.expect("At least one package exists"))
77
+
.min(120);
78
+
79
+
for package in &all {
80
+
let name = &package.name;
81
+
let package = &package.base_package;
82
+
let delta = &package.size_delta;
83
+
let versions = format!("{package}");
84
+
let visual_len = strip_ansi_escapes::strip(&versions).len();
85
+
let padding = " ".repeat(package_width.saturating_sub(visual_len));
86
+
writeln!(f, "{name:name_width$}{versions}{padding} {delta}")?;
87
}
88
89
+
writeln!(f)?;
90
+
91
+
Ok(())
92
+
}
93
+
94
+
fn display_by_category(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95
let title_style = nu_ansi_term::Style::new()
96
.underline()
97
.bold()
···
124
writeln!(f)?;
125
}
126
127
+
Ok(())
128
+
}
129
+
130
+
pub fn from_diff_root(&mut self, diff_root: DiffRoot) {
131
+
for (name, diff_package) in diff_root.packages {
132
+
let package = Package::from(diff_package);
133
134
+
self.size_delta.0 += package.size_delta.0;
135
+
self.longest_name = self.longest_name.max(name.len());
136
+
137
+
if self.by_size {
138
+
self.all.push(PackageExtra {
139
+
name,
140
+
base_package: package,
141
+
});
142
+
143
+
continue;
144
+
}
145
+
146
+
match package.diff_type {
147
+
DiffType::Added => {
148
+
self.added.insert(name, package);
149
+
}
150
+
DiffType::Removed => {
151
+
self.removed.insert(name, package);
152
+
}
153
+
DiffType::Changed => {
154
+
self.changed.insert(name, package);
155
+
}
156
+
DiffType::Unknown => {
157
+
// This should never happen, but just in case
158
+
eprintln!("Unknown diff type for package: {name}");
159
+
}
160
+
}
161
+
}
162
}
163
}
+8
-1
src/main.rs
···
25
/// the generation we are switching to
26
#[arg(default_value = "/run/current-system/")]
27
after: PathBuf,
0
0
0
0
28
}
29
30
fn main() -> Result<()> {
···
52
std::process::exit(1);
53
}
54
55
-
let packages: PackageListDiff = DiffRoot::new(lix_exe, &before, &after)?.into();
0
0
0
56
57
let arrow_style = Style::new().bold().fg(Color::LightGray);
58
···
25
/// the generation we are switching to
26
#[arg(default_value = "/run/current-system/")]
27
after: PathBuf,
28
+
29
+
/// sort by size difference
30
+
#[arg(short, long)]
31
+
size: bool,
32
}
33
34
fn main() -> Result<()> {
···
56
std::process::exit(1);
57
}
58
59
+
let packages_diff = DiffRoot::new(lix_exe, &before, &after)?;
60
+
let mut packages: PackageListDiff = PackageListDiff::new();
61
+
packages.by_size = args.size;
62
+
packages.from_diff_root(packages_diff);
63
64
let arrow_style = Style::new().bold().fg(Color::LightGray);
65
+20
-2
src/package.rs
···
0
1
use std::{cmp::Ordering, fmt::Display};
2
3
use super::{
···
17
18
#[derive(Debug)]
19
pub struct Package {
20
-
pub size_delta: i64,
21
pub diff_type: DiffType,
22
23
pub versions_before: VersionList,
24
pub versions_after: VersionList,
25
}
0
0
0
26
27
impl DiffType {
28
pub fn from_versions(before: &[String], after: &[String]) -> DiffType {
···
66
};
67
68
Package {
69
-
size_delta: diff.size_delta,
70
versions_before: parsed_before,
71
versions_after: parsed_after,
72
diff_type,
···
133
134
(parsed_before, parsed_after)
135
}
0
0
0
0
0
0
0
0
0
0
0
0
0
0
···
1
+
use humansize::{format_size, DECIMAL};
2
use std::{cmp::Ordering, fmt::Display};
3
4
use super::{
···
18
19
#[derive(Debug)]
20
pub struct Package {
21
+
pub size_delta: SizeDelta,
22
pub diff_type: DiffType,
23
24
pub versions_before: VersionList,
25
pub versions_after: VersionList,
26
}
27
+
28
+
#[derive(Debug)]
29
+
pub struct SizeDelta(pub i64);
30
31
impl DiffType {
32
pub fn from_versions(before: &[String], after: &[String]) -> DiffType {
···
70
};
71
72
Package {
73
+
size_delta: diff.size_delta.into(),
74
versions_before: parsed_before,
75
versions_after: parsed_after,
76
diff_type,
···
137
138
(parsed_before, parsed_after)
139
}
140
+
141
+
impl std::fmt::Display for SizeDelta {
142
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143
+
let sign = if self.0 >= 0 { "+" } else { "-" };
144
+
let size: u64 = self.0.abs().try_into().unwrap_or(0);
145
+
write!(f, "{sign}{}", format_size(size, DECIMAL))
146
+
}
147
+
}
148
+
149
+
impl From<i64> for SizeDelta {
150
+
fn from(size: i64) -> Self {
151
+
SizeDelta(size)
152
+
}
153
+
}
+1
-1
src/parser.rs
···
52
lix_exe = lix_path;
53
} else {
54
lix_exe = "nix".into();
55
-
};
56
57
let raw_diff = Command::new(lix_exe)
58
.args(["store", "diff-closures", "--json"])
···
52
lix_exe = lix_path;
53
} else {
54
lix_exe = "nix".into();
55
+
}
56
57
let raw_diff = Command::new(lix_exe)
58
.args(["store", "diff-closures", "--json"])