fix(filter): an unsupported rule in .loreignore is a hard error naming the line - #183
Conversation
… file load_filter propagated the error from add_inclusion/add_exclusion with ?, so a single rule the filter cannot express aborted the read and dropped every rule in the file, including the ones before it. repository::load_filter then turned that Err into None with no diagnostic, leaving the repository with no filter at all. The only signal reaching the user was that everything they meant to ignore showed up as changed. Report the offending line and skip it, keeping the rest of the file, and log the load failure in repository::load_filter instead of swallowing it. The refusal itself is unchanged: an unanchored multi-component re-inclusion is still rejected, it just no longer takes the file down with it. Fixes EpicGames#182 Signed-off-by: Mahiro Hirakawa <mahirohirakawa@glovrex.com>
|
General approach in Lore is that we don't skip over invalid configs and data but hard error - silently (which is basically what you get in an integration toolchain, a warning will just be printed in some log somewhere) skipping over invalid entries mean the filter no longer represents what the intent was, and the resulting partial filter will do potentially completely different inclusions/exclusions than the intention was. Arguably as bad as no filter. I would prefer a hard error but extended with the line info as suggested. |
|
Done — Your reasoning holds where mine did not: a filter that kept some of its rules and dropped others is not a smaller version of what the author wrote, it is a different filter, and nobody can tell which one they got by looking at the output. I was weighing it against "no filter at all" and treating a warning as the thing that closes the gap, which is the part you named — in an integration toolchain that warning is a line in a log nobody opens. One implementation note, since it decides whether the line number is worth anything. I first put it in Tests: the regression test now asserts the load fails and that the message names both the line and the rule as written. I added a positive control beside it — a file of supported rules still loads — so a failure is attributable to the unsupported rule rather than to every load.
One thing I did not do, because it is wider than this PR. Item 3 from the report — documenting which gitignore subset |
Per review: Lore hard-errors on invalid config rather than skipping it, and a partial filter no longer represents the author's intent, so warn-and-skip is replaced with a hard error carrying the file, the 1-based line number and the rule as written. The line info goes in the error message, not in internal_with_context: Display for Traced forwards to the inner error and never prints the trace, so a context string would name the line somewhere the reader never looks. The regression test now asserts the load fails and that the message names both the line and the rule. A positive control alongside it asserts a file of supported rules still loads, so the failure is attributable to the unsupported rule rather than to every load. Verification: cargo test -p lore-revision --test filter -> 12 passed. Negative control, tests kept and src reverted to warn-and-skip: the new test fails and the positive control stays green. Signed-off-by: Mahiro Hirakawa <mahirohirakawa@glovrex.com>
9e54260 to
3688e65
Compare
Fixes #182.
What goes wrong
filter::load_filterreads the ignore file line by line and propagates the rule error with?:So one rule the filter cannot express aborts the read and discards every rule in the file, including the ones before the offending line — and it does so with nothing naming the line at fault.
repository::load_filterthen turns thatErrintoNone:with no log at any level, so the repository ends up with no filter at all and the only signal reaching the user is that everything they meant to ignore shows up as changed. In #182 that was
**/DerivedDataCache/going dead because a later line said!**/Plugins/*/Binaries/.The change
The refusal itself is untouched —
add_inclusionstill rejects an unanchored multi-component re-inclusion, andunanchored_multi_component_inclusion_is_refusedstill passes. What changes is that the failure now says which line caused it instead of vanishing:filter::load_filterraises a hard error naming the path, the 1-based line number, and the rule as written. Per review (@mjansson): Lore hard-errors on invalid config rather than skipping it, and a filter that kept some rules and dropped others is not a smaller version of what the author wrote but a different filter, with no way for the reader to tell which one they got.FilterError::internal_with_context.Display for Tracedforwards to the inner error and never renders the trace, so a context string would have recorded the line somewhere no reader of the error looks. There is a comment at the call site saying so.repository::load_filterlogs the failure instead of swallowing it, for the errors that can still come out offilter::load.This gives the reporter's items 1 and 2. Item 3 — documenting which gitignore subset
.loreignoresupports — is not in this PR; happy to follow up if you want it indocs/.Still open, deliberately outside this diff
repository::load_filterreturnsOption<Arc<Filter>>andrepository.rs:2122does.unwrap_or_default(), so the hard error is raised, logged with the line, and then turned into an empty filter one level up. Propagating it isOption->Resultthrough that call site; say the word and it goes in here, or in a separate PR.Verification
unsupported_rule_fails_the_load_and_names_the_lineinlore-revision/tests/filter.rswrites the reporter's file plus a third rule after the bad line, asserts the load fails, and asserts the message names both the line and the rule as written.a_file_of_supported_rules_still_loadsbeside it is the positive control, so a failure is attributable to the unsupported rule rather than to every load.Negative control — tests kept,
lore-revision/src/filter.rsreverted to warn-and-skip: