11use std:: {
2- collections:: { BTreeMap , HashMap } ,
2+ collections:: {
3+ BTreeMap ,
4+ HashMap ,
5+ } ,
36 fmt,
4- path:: { Path , PathBuf } ,
7+ path:: {
8+ Path ,
9+ PathBuf ,
10+ } ,
511 time:: SystemTime ,
612} ;
713
8- use color_eyre:: eyre:: { bail, eyre, Context , ContextCompat } ;
9- use nix:: errno:: Errno ;
14+ use color_eyre:: eyre:: {
15+ bail,
16+ eyre,
17+ Context ,
18+ ContextCompat ,
19+ } ;
1020use nix:: {
21+ errno:: Errno ,
1122 fcntl:: AtFlags ,
12- unistd:: { faccessat, AccessFlags } ,
23+ unistd:: {
24+ faccessat,
25+ AccessFlags ,
26+ } ,
1327} ;
1428use regex:: Regex ;
15- use tracing:: { debug, info, instrument, span, warn, Level } ;
29+ use tracing:: {
30+ debug,
31+ info,
32+ instrument,
33+ span,
34+ warn,
35+ Level ,
36+ } ;
1637use uzers:: os:: unix:: UserExt ;
1738
18- use crate :: { commands:: Command , * } ;
39+ use crate :: {
40+ commands:: Command ,
41+ Result , interface,
42+ } ;
1943
2044// Nix impl:
2145// https://github.com/NixOS/nix/blob/master/src/nix-collect-garbage/nix-collect-garbage.cc
2246
2347#[ derive( Debug , Hash , PartialEq , Eq , PartialOrd , Ord ) ]
2448struct Generation {
25- number : u32 ,
49+ number : u32 ,
2650 last_modified : SystemTime ,
27- path : PathBuf ,
51+ path : PathBuf ,
2852}
2953
3054type ToBeRemoved = bool ;
@@ -42,12 +66,12 @@ impl interface::CleanMode {
4266 // What profiles to clean depending on the call mode
4367 let uid = nix:: unistd:: Uid :: effective ( ) ;
4468 let args = match self {
45- interface :: CleanMode :: Profile ( args) => {
69+ Self :: Profile ( args) => {
4670 profiles. push ( args. profile . clone ( ) ) ;
4771 is_profile_clean = true ;
4872 & args. common
49- }
50- interface :: CleanMode :: All ( args) => {
73+ } ,
74+ Self :: All ( args) => {
5175 if !uid. is_root ( ) {
5276 crate :: self_elevate ( ) ;
5377 }
@@ -57,22 +81,20 @@ impl interface::CleanMode {
5781 profiles. extend ( profiles_in_dir ( path) ) ;
5882 }
5983
60- // Most unix systems start regular users at uid 1000+, but macos is special at 501+
61- // https://en.wikipedia.org/wiki/User_identifier
84+ // Most unix systems start regular users at uid 1000+, but macos is special at
85+ // 501+ https://en.wikipedia.org/wiki/User_identifier
6286 let uid_min = if cfg ! ( target_os = "macos" ) { 501 } else { 1000 } ;
6387 let uid_max = uid_min + 100 ;
6488 debug ! ( "Scanning XDG profiles for users 0, ${uid_min}-${uid_max}" ) ;
6589 for user in unsafe { uzers:: all_users ( ) } {
6690 if user. uid ( ) >= uid_min && user. uid ( ) < uid_max || user. uid ( ) == 0 {
6791 debug ! ( ?user, "Adding XDG profiles for user" ) ;
68- profiles. extend ( profiles_in_dir (
69- user. home_dir ( ) . join ( ".local/state/nix/profiles" ) ,
70- ) ) ;
92+ profiles. extend ( profiles_in_dir ( user. home_dir ( ) . join ( ".local/state/nix/profiles" ) ) ) ;
7193 }
7294 }
7395 args
74- }
75- interface :: CleanMode :: User ( args) => {
96+ } ,
97+ Self :: User ( args) => {
7698 if uid. is_root ( ) {
7799 bail ! ( "nh clean user: don't run me as root!" ) ;
78100 }
@@ -84,16 +106,13 @@ impl interface::CleanMode {
84106 PathBuf :: from ( "/nix/var/nix/profiles/per-user" ) . join ( user. name ) ,
85107 ) ) ;
86108 args
87- }
109+ } ,
88110 } ;
89111
90112 // Use mutation to raise errors as they come
91113 let mut profiles_tagged = ProfilesTagged :: new ( ) ;
92114 for p in profiles {
93- profiles_tagged. insert (
94- p. clone ( ) ,
95- cleanable_generations ( & p, args. keep , args. keep_since ) ?,
96- ) ;
115+ profiles_tagged. insert ( p. clone ( ) , cleanable_generations ( & p, args. keep , args. keep_since ) ?) ;
97116 }
98117
99118 // Query gcroots
@@ -114,10 +133,7 @@ impl interface::CleanMode {
114133 let _entered = span. enter ( ) ;
115134 debug ! ( ?src) ;
116135
117- if !regexes
118- . iter ( )
119- . any ( |next| next. is_match ( & dst. to_string_lossy ( ) ) )
120- {
136+ if !regexes. iter ( ) . any ( |next| next. is_match ( & dst. to_string_lossy ( ) ) ) {
121137 debug ! ( "dst doesn't match any gcroot regex, skipping" ) ;
122138 continue ;
123139 } ;
@@ -129,12 +145,14 @@ impl interface::CleanMode {
129145 AccessFlags :: F_OK | AccessFlags :: W_OK ,
130146 AtFlags :: AT_SYMLINK_NOFOLLOW ,
131147 ) {
132- Ok ( _) => true ,
133- Err ( errno) => match errno {
134- Errno :: EACCES | Errno :: ENOENT => false ,
135- _ => {
136- bail ! ( eyre!( "Checking access for gcroot {:?}, unknown error" , dst)
137- . wrap_err( errno) )
148+ Ok ( ( ) ) => true ,
149+ Err ( errno) => {
150+ match errno {
151+ Errno :: EACCES | Errno :: ENOENT => false ,
152+ _ => {
153+ bail ! ( eyre!( "Checking access for gcroot {:?}, unknown error" , dst)
154+ . wrap_err( errno) )
155+ } ,
138156 }
139157 } ,
140158 } {
@@ -147,13 +165,13 @@ impl interface::CleanMode {
147165 match dur {
148166 Err ( err) => {
149167 warn ! ( ?err, ?now, "Failed to compare time!" ) ;
150- }
168+ } ,
151169 Ok ( val) if val <= args. keep_since . into ( ) => {
152170 gcroots_tagged. insert ( dst, false ) ;
153- }
171+ } ,
154172 Ok ( _) => {
155173 gcroots_tagged. insert ( dst, true ) ;
156- }
174+ } ,
157175 }
158176 } else {
159177 debug ! ( "dst doesn't exist or is not writable, skipping" ) ;
@@ -175,9 +193,7 @@ impl interface::CleanMode {
175193 if !gcroots_tagged. is_empty ( ) {
176194 println ! (
177195 "{}" ,
178- "gcroots (matching the following regex patterns)"
179- . blue( )
180- . bold( )
196+ "gcroots (matching the following regex patterns)" . blue( ) . bold( )
181197 ) ;
182198 for re in regexes {
183199 println ! ( "- {} {}" , "RE" . purple( ) , re) ;
@@ -191,7 +207,7 @@ impl interface::CleanMode {
191207 }
192208 println ! ( ) ;
193209 }
194- for ( profile, generations_tagged) in profiles_tagged. iter ( ) {
210+ for ( profile, generations_tagged) in & profiles_tagged {
195211 println ! ( "{}" , profile. to_string_lossy( ) . blue( ) . bold( ) ) ;
196212 for ( gen, tbr) in generations_tagged. iter ( ) . rev ( ) {
197213 if * tbr {
@@ -218,7 +234,7 @@ impl interface::CleanMode {
218234 }
219235 }
220236
221- for ( _ , generations_tagged) in profiles_tagged. iter ( ) {
237+ for generations_tagged in profiles_tagged. values ( ) {
222238 for ( gen, tbr) in generations_tagged. iter ( ) . rev ( ) {
223239 if * tbr {
224240 remove_path_nofail ( & gen. path ) ;
@@ -252,27 +268,24 @@ fn profiles_in_dir<P: AsRef<Path> + fmt::Debug>(dir: P) -> Vec<PathBuf> {
252268 let path = e. path ( ) ;
253269
254270 if let Ok ( dst) = path. read_link ( ) {
255- let name = dst
256- . file_name ( )
257- . expect ( "Failed to get filename" )
258- . to_string_lossy ( ) ;
271+ let name = dst. file_name ( ) . expect ( "Failed to get filename" ) . to_string_lossy ( ) ;
259272
260273 let generation_regex = Regex :: new ( r"^(.*)-(\d+)-link$" ) . unwrap ( ) ;
261274
262275 if generation_regex. captures ( & name) . is_some ( ) {
263276 res. push ( path) ;
264277 }
265278 }
266- }
279+ } ,
267280 Err ( error) => {
268281 warn ! ( ?dir, ?error, "Failed to read folder element" ) ;
269- }
282+ } ,
270283 }
271284 }
272- }
285+ } ,
273286 Err ( error) => {
274287 warn ! ( ?dir, ?error, "Failed to read profiles directory" ) ;
275- }
288+ } ,
276289 }
277290
278291 res
@@ -324,15 +337,15 @@ fn cleanable_generations(
324337 }
325338
326339 let now = SystemTime :: now ( ) ;
327- for ( gen, tbr) in result. iter_mut ( ) {
340+ for ( gen, tbr) in & mut result {
328341 match now. duration_since ( gen. last_modified ) {
329342 Err ( err) => {
330343 warn ! ( ?err, ?now, ?gen , "Failed to compare time!" ) ;
331- }
344+ } ,
332345 Ok ( val) if val <= keep_since. into ( ) => {
333346 * tbr = false ;
334- }
335- Ok ( _) => { }
347+ } ,
348+ Ok ( _) => { } ,
336349 }
337350 }
338351
0 commit comments