@@ -182,14 +182,14 @@ pub fn handle_command(matches: &ArgMatches, config: &Config, output: &OutputMana
182182 list_extensions ( config, output) ;
183183 }
184184 Some ( ( "merge" , _) ) => {
185- merge_extensions ( output) ;
185+ merge_extensions ( config , output) ;
186186 }
187187 Some ( ( "unmerge" , unmerge_matches) ) => {
188188 let unmount = unmerge_matches. get_flag ( "unmount" ) ;
189189 unmerge_extensions ( unmount, output) ;
190190 }
191191 Some ( ( "refresh" , _) ) => {
192- refresh_extensions ( output) ;
192+ refresh_extensions ( config , output) ;
193193 }
194194 Some ( ( "status" , _) ) => {
195195 status_extensions ( output) ;
@@ -251,8 +251,8 @@ fn list_extensions(config: &Config, output: &OutputManager) {
251251}
252252
253253/// Merge extensions using systemd-sysext and systemd-confext
254- pub fn merge_extensions ( output : & OutputManager ) {
255- match merge_extensions_internal ( output) {
254+ pub fn merge_extensions ( config : & Config , output : & OutputManager ) {
255+ match merge_extensions_internal ( config , output) {
256256 Ok ( _) => {
257257 output. success ( "Extension Merge" , "Extensions merged successfully" ) ;
258258 }
@@ -267,7 +267,7 @@ pub fn merge_extensions(output: &OutputManager) {
267267}
268268
269269/// Internal merge function that returns a Result
270- fn merge_extensions_internal ( output : & OutputManager ) -> Result < ( ) , SystemdError > {
270+ fn merge_extensions_internal ( config : & Config , output : & OutputManager ) -> Result < ( ) , SystemdError > {
271271 let environment_info = if is_running_in_initrd ( ) {
272272 "initrd environment"
273273 } else {
@@ -281,18 +281,29 @@ fn merge_extensions_internal(output: &OutputManager) -> Result<(), SystemdError>
281281 // Prepare the environment by setting up symlinks and get the list of enabled extensions
282282 let enabled_extensions = prepare_extension_environment_with_output ( output) ?;
283283
284+ // Get the mutability setting from config
285+ let mutability = match config. get_extension_mutable ( ) {
286+ Ok ( value) => value,
287+ Err ( e) => {
288+ output. error (
289+ "Configuration Error" ,
290+ & format ! ( "Invalid mutable configuration: {e}" ) ,
291+ ) ;
292+ return Err ( SystemdError :: ConfigurationError {
293+ message : e. to_string ( ) ,
294+ } ) ;
295+ }
296+ } ;
297+ let mutable_arg = format ! ( "--mutable={mutability}" ) ;
298+
284299 // Merge system extensions
285- let sysext_result = run_systemd_command (
286- "systemd-sysext" ,
287- & [ "merge" , "--mutable=ephemeral" , "--json=short" ] ,
288- ) ?;
300+ let sysext_result =
301+ run_systemd_command ( "systemd-sysext" , & [ "merge" , & mutable_arg, "--json=short" ] ) ?;
289302 handle_systemd_output ( "systemd-sysext merge" , & sysext_result, output) ?;
290303
291304 // Merge configuration extensions
292- let confext_result = run_systemd_command (
293- "systemd-confext" ,
294- & [ "merge" , "--mutable=ephemeral" , "--json=short" ] ,
295- ) ?;
305+ let confext_result =
306+ run_systemd_command ( "systemd-confext" , & [ "merge" , & mutable_arg, "--json=short" ] ) ?;
296307 handle_systemd_output ( "systemd-confext merge" , & confext_result, output) ?;
297308
298309 // Process post-merge tasks only for enabled extensions
@@ -378,7 +389,9 @@ fn unmerge_extensions_internal_with_options(
378389///
379390/// Merge extensions - direct access for top-level alias
380391pub fn merge_extensions_direct ( output : & OutputManager ) {
381- merge_extensions ( output) ;
392+ // Use default config for direct access
393+ let config = Config :: default ( ) ;
394+ merge_extensions ( & config, output) ;
382395}
383396
384397/// Unmerge extensions - direct access for top-level alias
@@ -388,7 +401,9 @@ pub fn unmerge_extensions_direct(unmount: bool, output: &OutputManager) {
388401
389402/// Refresh extensions - direct access for top-level alias
390403pub fn refresh_extensions_direct ( output : & OutputManager ) {
391- refresh_extensions ( output) ;
404+ // Use default config for direct access
405+ let config = Config :: default ( ) ;
406+ refresh_extensions ( & config, output) ;
392407}
393408
394409/// Enable extensions for a specific OS release version
@@ -450,8 +465,8 @@ pub fn enable_extensions(
450465
451466 for ext_name in extensions {
452467 // Check if extension exists - try both directory and .raw file
453- let ext_dir_path = format ! ( "{}/{}" , extensions_dir , ext_name ) ;
454- let ext_raw_path = format ! ( "{}/{}.raw" , extensions_dir , ext_name ) ;
468+ let ext_dir_path = format ! ( "{extensions_dir }/{ext_name}" ) ;
469+ let ext_raw_path = format ! ( "{extensions_dir }/{ext_name }.raw" ) ;
455470
456471 let source_path = if Path :: new ( & ext_dir_path) . exists ( ) {
457472 ext_dir_path
@@ -643,8 +658,8 @@ pub fn disable_extensions(
643658 // Disable specific extensions
644659 for ext_name in ext_names {
645660 // Check for both directory and .raw file symlinks
646- let symlink_dir = format ! ( "{}/{}" , os_releases_dir , ext_name ) ;
647- let symlink_raw = format ! ( "{}/{}.raw" , os_releases_dir , ext_name ) ;
661+ let symlink_dir = format ! ( "{os_releases_dir }/{ext_name}" ) ;
662+ let symlink_raw = format ! ( "{os_releases_dir }/{ext_name }.raw" ) ;
648663
649664 let mut found = false ;
650665
@@ -735,7 +750,7 @@ pub fn disable_extensions(
735750}
736751
737752/// Refresh extensions (unmerge then merge)
738- pub fn refresh_extensions ( output : & OutputManager ) {
753+ pub fn refresh_extensions ( config : & Config , output : & OutputManager ) {
739754 let environment_info = if is_running_in_initrd ( ) {
740755 "initrd environment"
741756 } else {
@@ -757,7 +772,7 @@ pub fn refresh_extensions(output: &OutputManager) {
757772 output. step ( "Refresh" , "Extensions unmerged" ) ;
758773
759774 // Then merge (this will call depmod via post-merge processing)
760- if let Err ( e) = merge_extensions_internal ( output) {
775+ if let Err ( e) = merge_extensions_internal ( config , output) {
761776 output. error (
762777 "Extension Refresh" ,
763778 & format ! ( "Failed to merge extensions: {e}" ) ,
@@ -1225,13 +1240,11 @@ fn cleanup_stale_extension_symlinks(
12251240 if should_remove {
12261241 if let Err ( e) = fs:: remove_file ( & path) {
12271242 output. progress ( & format ! (
1228- "Warning: Failed to remove stale sysext symlink {}: {}" ,
1229- file_name, e
1230- ) ) ;
1243+ "Warning: Failed to remove stale sysext symlink {file_name}: {e}"
1244+ ) ) ;
12311245 } else {
12321246 output. progress ( & format ! (
1233- "Removed stale sysext symlink: {}" ,
1234- file_name
1247+ "Removed stale sysext symlink: {file_name}"
12351248 ) ) ;
12361249 }
12371250 }
@@ -1281,13 +1294,11 @@ fn cleanup_stale_extension_symlinks(
12811294 if should_remove {
12821295 if let Err ( e) = fs:: remove_file ( & path) {
12831296 output. progress ( & format ! (
1284- "Warning: Failed to remove stale confext symlink {}: {}" ,
1285- file_name, e
1286- ) ) ;
1297+ "Warning: Failed to remove stale confext symlink {file_name}: {e}"
1298+ ) ) ;
12871299 } else {
12881300 output. progress ( & format ! (
1289- "Removed stale confext symlink: {}" ,
1290- file_name
1301+ "Removed stale confext symlink: {file_name}"
12911302 ) ) ;
12921303 }
12931304 }
@@ -1437,9 +1448,8 @@ fn scan_extensions_from_all_sources_with_verbosity(
14371448 Entry :: Occupied ( _) => {
14381449 if verbose {
14391450 println ! (
1440- "Skipping OS release raw extension {} (higher priority version preferred)" ,
1441- ext_name
1442- ) ;
1451+ "Skipping OS release raw extension {ext_name} (higher priority version preferred)"
1452+ ) ;
14431453 }
14441454 }
14451455 }
@@ -1512,7 +1522,7 @@ fn scan_extensions_from_all_sources_with_verbosity(
15121522 // Add versioned names for raw files we're about to process
15131523 for ( name, version, _path) in & raw_files {
15141524 if let Some ( ver) = version {
1515- available_loop_names. push ( format ! ( "{}-{}" , name , ver ) ) ;
1525+ available_loop_names. push ( format ! ( "{name }-{ver}" ) ) ;
15161526 } else {
15171527 available_loop_names. push ( name. clone ( ) ) ;
15181528 }
@@ -2769,6 +2779,9 @@ pub enum SystemdError {
27692779 exit_code : Option < i32 > ,
27702780 stderr : String ,
27712781 } ,
2782+
2783+ #[ error( "Configuration error: {message}" ) ]
2784+ ConfigurationError { message : String } ,
27722785}
27732786
27742787#[ cfg( test) ]
@@ -3246,4 +3259,31 @@ OTHER_KEY=value
32463259 let result = is_confext_enabled_for_current_environment ( & ext_path, "test_ext" ) ;
32473260 assert ! ( result) ;
32483261 }
3262+
3263+ #[ test]
3264+ fn test_config_mutable_integration ( ) {
3265+ // Test that the config mutable option is properly used
3266+ let mut config = Config :: default ( ) ;
3267+
3268+ // Test with default value (ephemeral)
3269+ assert_eq ! ( config. get_extension_mutable( ) . unwrap( ) , "ephemeral" ) ;
3270+
3271+ // Test with custom value
3272+ config. avocado . ext . mutable = Some ( "yes" . to_string ( ) ) ;
3273+ assert_eq ! ( config. get_extension_mutable( ) . unwrap( ) , "yes" ) ;
3274+
3275+ // Test with another valid value
3276+ config. avocado . ext . mutable = Some ( "auto" . to_string ( ) ) ;
3277+ assert_eq ! ( config. get_extension_mutable( ) . unwrap( ) , "auto" ) ;
3278+
3279+ // Test error handling for invalid value
3280+ config. avocado . ext . mutable = Some ( "invalid" . to_string ( ) ) ;
3281+ let result = config. get_extension_mutable ( ) ;
3282+ assert ! ( result. is_err( ) ) ;
3283+
3284+ let error = result. unwrap_err ( ) ;
3285+ assert ! ( error
3286+ . to_string( )
3287+ . contains( "Invalid mutable value 'invalid'" ) ) ;
3288+ }
32493289}
0 commit comments