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