@@ -14,32 +14,115 @@ pub(crate) struct InstallConfigurationToplevel {
14
14
pub ( crate ) install : Option < InstallConfiguration > ,
15
15
}
16
16
17
+ /// Configuration for a filesystem
18
+ #[ derive( Debug , Clone , Serialize , Deserialize , Default ) ]
19
+ #[ serde( deny_unknown_fields) ]
20
+ pub ( crate ) struct RootFS {
21
+ #[ serde( rename = "type" ) ]
22
+ pub ( crate ) fstype : Option < super :: baseline:: Filesystem > ,
23
+ }
24
+
25
+ /// This structure should only define "system" or "basic" filesystems; we are
26
+ /// not trying to generalize this into e.g. supporting `/var` or other ones.
27
+ #[ derive( Debug , Clone , Serialize , Deserialize , Default ) ]
28
+ #[ serde( deny_unknown_fields) ]
29
+ pub ( crate ) struct BasicFilesystems {
30
+ pub ( crate ) root : Option < RootFS > ,
31
+ // TODO allow configuration of these other filesystems too
32
+ // pub(crate) xbootldr: Option<FilesystemCustomization>,
33
+ // pub(crate) esp: Option<FilesystemCustomization>,
34
+ }
35
+
17
36
/// The serialized [install] section
18
37
#[ derive( Debug , Clone , Serialize , Deserialize , Default ) ]
19
38
#[ serde( rename = "install" , rename_all = "kebab-case" , deny_unknown_fields) ]
20
39
pub ( crate ) struct InstallConfiguration {
21
40
/// Root filesystem type
22
41
pub ( crate ) root_fs_type : Option < super :: baseline:: Filesystem > ,
42
+ pub ( crate ) filesystem : Option < BasicFilesystems > ,
23
43
/// Kernel arguments, applied at installation time
24
44
#[ serde( skip_serializing_if = "Option::is_none" ) ]
25
45
pub ( crate ) kargs : Option < Vec < String > > ,
26
46
}
27
47
28
- impl InstallConfiguration {
29
- /// Apply any values in other, overriding any existing values in `self`.
30
- fn merge ( & mut self , other : Self ) {
31
- fn mergeopt < T > ( s : & mut Option < T > , o : Option < T > ) {
32
- if let Some ( o) = o {
33
- * s = Some ( o) ;
48
+ fn merge_basic < T > ( s : & mut Option < T > , o : Option < T > ) {
49
+ if let Some ( o) = o {
50
+ * s = Some ( o) ;
51
+ }
52
+ }
53
+
54
+ trait Mergeable {
55
+ fn merge ( & mut self , other : Self )
56
+ where
57
+ Self : Sized ;
58
+ }
59
+
60
+ impl < T > Mergeable for Option < T >
61
+ where
62
+ T : Mergeable ,
63
+ {
64
+ fn merge ( & mut self , other : Self )
65
+ where
66
+ Self : Sized ,
67
+ {
68
+ if let Some ( other) = other {
69
+ if let Some ( s) = self . as_mut ( ) {
70
+ s. merge ( other)
71
+ } else {
72
+ * self = Some ( other) ;
34
73
}
35
74
}
36
- mergeopt ( & mut self . root_fs_type , other. root_fs_type ) ;
75
+ }
76
+ }
77
+
78
+ impl Mergeable for RootFS {
79
+ /// Apply any values in other, overriding any existing values in `self`.
80
+ fn merge ( & mut self , other : Self ) {
81
+ merge_basic ( & mut self . fstype , other. fstype )
82
+ }
83
+ }
84
+
85
+ impl Mergeable for BasicFilesystems {
86
+ /// Apply any values in other, overriding any existing values in `self`.
87
+ fn merge ( & mut self , other : Self ) {
88
+ self . root . merge ( other. root )
89
+ }
90
+ }
91
+
92
+ impl Mergeable for InstallConfiguration {
93
+ /// Apply any values in other, overriding any existing values in `self`.
94
+ fn merge ( & mut self , other : Self ) {
95
+ merge_basic ( & mut self . root_fs_type , other. root_fs_type ) ;
96
+ self . filesystem . merge ( other. filesystem ) ;
37
97
if let Some ( other_kargs) = other. kargs {
38
98
self . kargs
39
99
. get_or_insert_with ( Default :: default)
40
100
. extend ( other_kargs)
41
101
}
42
102
}
103
+ }
104
+
105
+ impl InstallConfiguration {
106
+ /// Some fields can be specified multiple ways. This synchronizes the values of the fields
107
+ /// to ensure they're the same.
108
+ ///
109
+ /// - install.root-fs-type is synchronized with install.filesystems.root.type; if
110
+ /// both are set, then the latter takes precedence
111
+ pub ( crate ) fn canonicalize ( & mut self ) {
112
+ // New canonical form wins.
113
+ if let Some ( rootfs_type) = self . filesystem_root ( ) . and_then ( |f| f. fstype . as_ref ( ) ) {
114
+ self . root_fs_type = Some ( * rootfs_type)
115
+ } else if let Some ( rootfs) = self . root_fs_type . as_ref ( ) {
116
+ let fs = self . filesystem . get_or_insert_with ( Default :: default) ;
117
+ let root = fs. root . get_or_insert_with ( Default :: default) ;
118
+ root. fstype = Some ( * rootfs) ;
119
+ }
120
+ }
121
+
122
+ /// Convenience helper to access the root filesystem
123
+ pub ( crate ) fn filesystem_root ( & self ) -> Option < & RootFS > {
124
+ self . filesystem . as_ref ( ) . and_then ( |fs| fs. root . as_ref ( ) )
125
+ }
43
126
44
127
// Remove all configuration which is handled by `install to-filesystem`.
45
128
pub ( crate ) fn filter_to_external ( & mut self ) {
@@ -73,7 +156,9 @@ pub(crate) fn load_config() -> Result<InstallConfiguration> {
73
156
config = c. install ;
74
157
}
75
158
}
76
- config. ok_or_else ( || anyhow:: anyhow!( "No bootc/install config found; this operating system must define a default configuration to be installable" ) )
159
+ let mut config = config. ok_or_else ( || anyhow:: anyhow!( "No bootc/install config found; this operating system must define a default configuration to be installable" ) ) ?;
160
+ config. canonicalize ( ) ;
161
+ Ok ( config)
77
162
}
78
163
79
164
#[ test]
@@ -92,11 +177,23 @@ root-fs-type = "xfs"
92
177
let other = InstallConfigurationToplevel {
93
178
install : Some ( InstallConfiguration {
94
179
root_fs_type : Some ( Filesystem :: Ext4 ) ,
180
+ filesystem : None ,
95
181
kargs : None ,
96
182
} ) ,
97
183
} ;
98
184
install. merge ( other. install . unwrap ( ) ) ;
99
- assert_eq ! ( install. root_fs_type. unwrap( ) , Filesystem :: Ext4 ) ;
185
+ assert_eq ! (
186
+ install. root_fs_type. as_ref( ) . copied( ) . unwrap( ) ,
187
+ Filesystem :: Ext4
188
+ ) ;
189
+ // This one shouldn't have been set
190
+ assert ! ( install. filesystem_root( ) . is_none( ) ) ;
191
+ install. canonicalize ( ) ;
192
+ assert_eq ! ( install. root_fs_type. as_ref( ) . unwrap( ) , & Filesystem :: Ext4 ) ;
193
+ assert_eq ! (
194
+ install. filesystem_root( ) . unwrap( ) . fstype. unwrap( ) ,
195
+ Filesystem :: Ext4
196
+ ) ;
100
197
101
198
let c: InstallConfigurationToplevel = toml:: from_str (
102
199
r##"[install]
@@ -110,6 +207,7 @@ kargs = ["console=ttyS0", "foo=bar"]
110
207
let other = InstallConfigurationToplevel {
111
208
install : Some ( InstallConfiguration {
112
209
root_fs_type : None ,
210
+ filesystem : None ,
113
211
kargs : Some (
114
212
[ "console=tty0" , "nosmt" ]
115
213
. into_iter ( )
@@ -130,3 +228,35 @@ kargs = ["console=ttyS0", "foo=bar"]
130
228
)
131
229
)
132
230
}
231
+
232
+ #[ test]
233
+ fn test_parse_filesystems ( ) {
234
+ use super :: baseline:: Filesystem ;
235
+ let c: InstallConfigurationToplevel = toml:: from_str (
236
+ r##"[install.filesystem.root]
237
+ type = "xfs"
238
+ "## ,
239
+ )
240
+ . unwrap ( ) ;
241
+ let mut install = c. install . unwrap ( ) ;
242
+ assert_eq ! (
243
+ install. filesystem_root( ) . unwrap( ) . fstype. unwrap( ) ,
244
+ Filesystem :: Xfs
245
+ ) ;
246
+ let other = InstallConfigurationToplevel {
247
+ install : Some ( InstallConfiguration {
248
+ root_fs_type : None ,
249
+ filesystem : Some ( BasicFilesystems {
250
+ root : Some ( RootFS {
251
+ fstype : Some ( Filesystem :: Ext4 ) ,
252
+ } ) ,
253
+ } ) ,
254
+ kargs : None ,
255
+ } ) ,
256
+ } ;
257
+ install. merge ( other. install . unwrap ( ) ) ;
258
+ assert_eq ! (
259
+ install. filesystem_root( ) . unwrap( ) . fstype. unwrap( ) ,
260
+ Filesystem :: Ext4
261
+ ) ;
262
+ }
0 commit comments