Skip to content

Commit c01931b

Browse files
committed
feat(parse_size): Add comprehensive builder validation to prevent fragile configurations
Addresses PR uutils#9653 review feedback about 'fragile commands' by implementing fail-fast validation in Parser builder pattern. Changes: - Add ParserBuilderError enum with 8 validation error variants - Refactor builder methods to return Result<&mut Self, ParserBuilderError> - Implement comprehensive unit validation (57 valid units including k/m/g/t) - Add cross-validation between builder settings (default_unit vs allow_list) - Detect conflicts (b_byte_count with 'b' unit, '%' with size units) - Update all call sites (sort, du, df, od) to handle new error types - Fix invalid '%' unit in sort's parse_byte_count allow_list Benefits: - Configuration errors detected immediately (not during parsing) - Clear error messages listing invalid/conflicting settings - Maintains backward compatibility through explicit error reporting Files modified: - src/uucore/src/lib/features/parser/parse_size.rs (core implementation) - src/uu/sort/src/sort.rs (error handling + fix invalid '%') - src/uu/du/src/du.rs (error handling) - src/uu/df/src/df.rs (error handling) - src/uu/od/src/od.rs (error handling)
1 parent b111634 commit c01931b

File tree

5 files changed

+335
-16
lines changed

5 files changed

+335
-16
lines changed

src/uu/df/src/df.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ impl Options {
167167
),
168168
ParseSizeError::ParseFailure(s) => OptionsError::InvalidBlockSize(s),
169169
ParseSizeError::PhysicalMem(s) => OptionsError::InvalidBlockSize(s),
170+
ParseSizeError::BuilderConfig(e) => OptionsError::InvalidBlockSize(e.to_string()),
170171
})?,
171172
header_mode: {
172173
if matches.get_flag(OPT_HUMAN_READABLE_BINARY)

src/uu/du/src/du.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,9 @@ fn format_error_message(error: &ParseSizeError, s: &str, option: &str) -> String
14901490
ParseSizeError::SizeTooBig(_) => {
14911491
translate!("du-error-argument-too-large", "option" => option, "value" => s.quote())
14921492
}
1493+
ParseSizeError::BuilderConfig(e) => {
1494+
format!("invalid configuration for {option}: {e}")
1495+
}
14931496
}
14941497
}
14951498

src/uu/od/src/od.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,5 +804,8 @@ fn format_error_message(error: &ParseSizeError, s: &str, option: &str) -> String
804804
ParseSizeError::SizeTooBig(_) => {
805805
translate!("od-error-argument-too-large", "option" => option, "value" => s.quote())
806806
}
807+
ParseSizeError::BuilderConfig(e) => {
808+
format!("invalid configuration for {option}: {e}")
809+
}
807810
}
808811
}

src/uu/sort/src/sort.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,10 @@ impl GlobalSettings {
319319
// GNU sort (8.32) invalid: b, B, 1B, p, e, z, y
320320
let size = Parser::default()
321321
.with_allow_list(&[
322-
"b", "k", "K", "m", "M", "g", "G", "t", "T", "P", "E", "Z", "Y", "R", "Q", "%",
323-
])
324-
.with_default_unit("K")
325-
.with_b_byte_count(true)
322+
"b", "k", "K", "m", "M", "g", "G", "t", "T", "P", "E", "Z", "Y", "R", "Q",
323+
])?
324+
.with_default_unit("K")?
325+
.with_b_byte_count(true)?
326326
.parse(input.trim())?;
327327

328328
usize::try_from(size).map_err(|_| {
@@ -2268,6 +2268,9 @@ fn format_error_message(error: &ParseSizeError, s: &str, option: &str) -> String
22682268
ParseSizeError::SizeTooBig(_) => {
22692269
translate!("sort-option-arg-too-large", "option" => option, "arg" => s.quote())
22702270
}
2271+
ParseSizeError::BuilderConfig(e) => {
2272+
format!("invalid configuration for {option}: {e}")
2273+
}
22712274
}
22722275
}
22732276

0 commit comments

Comments
 (0)