Skip to content

diff: EOL/header normalization - empty time_format (git-style header), ignore_missing_final_newline - #234

Merged
helly25 merged 3 commits into
mainfrom
feat/diff-normalization
Jul 5, 2026
Merged

diff: EOL/header normalization - empty time_format (git-style header), ignore_missing_final_newline#234
helly25 merged 3 commits into
mainfrom
feat/diff-normalization

Conversation

@helly25

@helly25 helly25 commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

Two mbo::diff normalization features that make diff output and comparison reproducible:

  • Empty DiffOptions::time_format omits the header timestamp: unified/context file headers become git-style --- name / +++ name (name only, no per-file mtime) instead of name with a trailing space and empty timestamp. Output is reproducible across machines and time zones (golden tests, content-addressed comparisons). Non-empty time_format unchanged; stays library-only.
  • ignore_missing_final_newline (DiffOptions field, --ignore_missing_final_newline CLI flag, diff_test rule attribute): a file with and one without a trailing newline compare equal; the \ No newline at end of file marker is suppressed in Data's shared line preprocessing so all three algorithms (naive/myers/direct) honor it identically. Only the terminator is ignored - an empty file stays distinct from a single empty line.

This completes the whitespace/EOL normalization set alongside ignore_all_space / ignore_consecutive_space / ignore_trailing_space.

Testing

  • DiffTest.EmptyTimeFormatOmitsHeaderTimestamp
  • DiffTest.IgnoreMissingFinalNewline (equal with option, differ without, empty != "\n")
  • AlgorithmFeatureMatrix case across naive/myers/direct
  • Full local run: 100/100 bazel tests pass, pre-commit clean

helly25 added 2 commits July 5, 2026 10:58
An empty DiffOptions::time_format now yields a git-style file header (`--- name` /
`+++ name`, name only, no per-file mtime) instead of `name ` with a trailing space and
empty timestamp. This makes unified/context diff output reproducible across machines and
time zones, which matters for golden tests and content-addressed comparisons. A non-empty
time_format is unchanged; time_format stays library-only.

Test: DiffTest.EmptyTimeFormatOmitsHeaderTimestamp.
DiffOptions::ignore_missing_final_newline (the --ignore_missing_final_newline CLI flag and
the diff_test `ignore_missing_final_newline` rule attribute) makes a file with and one
without a trailing newline compare equal: the `\ No newline at end of file` marker is
suppressed in Data's shared line preprocessing, so all three algorithms honor it. It only
ignores the terminator - the zero-length-input guard still fires on the real got_nl, so an
empty file stays distinct from a single empty line.

This is the one whitespace/EOL normalization mbo::diff was missing; leading / consecutive /
trailing space and CRLF-vs-LF (a trailing '\r' is trailing whitespace) are already covered
by ignore_all_space / ignore_consecutive_space / ignore_trailing_space.

Tests: DiffTest.IgnoreMissingFinalNewline (equal with, differ without, empty != "\n") and an
AlgorithmFeatureMatrix case across naive/myers/direct.
@helly25
helly25 requested a review from Fab-Cat July 5, 2026 15:29
@helly25
helly25 merged commit 55a6b2c into main Jul 5, 2026
40 checks passed
@helly25
helly25 deleted the feat/diff-normalization branch July 5, 2026 16:23
helly25 added a commit to helly25/xff that referenced this pull request Jul 5, 2026
Re-pins the mbo git_override to the main commit merging helly25/mbo#234 (which added the
empty-time_format git-style header and ignore_missing_final_newline), and wires the two
xff-side bits:

- -diff now sets time_format="" so the unified/context header omits the per-file mtime
  (`--- a/one.txt`), making the output reproducible. The diff golden tests drop the
  mtime-strip sed (normalize) and the fixture drops its `touch` - the git-style header is
  verbatim, so the committed goldens match directly.
- --diff-ignore gains an `eofnl` token (-> mbo ignore_missing_final_newline): a file with
  and one without a final newline compare equal. No `lead`/`eol` token - leading whitespace
  is subsumed by `change`/`ws`, and CRLF-vs-LF by `trail` (a `\r` is trailing whitespace).

Tests: run_test + diff_test.sh gain eofnl cases (equal with the token, differ without);
the diff goldens pass with no normalization. `bazel test //xff/...` green (66 tests).
helly25 added a commit to helly25/xff that referenced this pull request Jul 12, 2026
mbo 0.13.0 is now in the Bazel Central Registry, so drop the temporary
git_override (pinned at the main commit merging helly25/mbo#234) for a plain
bazel_dep version bump. 0.13.0 carries mbo/diff (the rich diff API behind -diff,
#88) and mbo/digest (the -hash algorithms, #105), which the override provided;
it also keeps the macOS clang+asan verification (#188) and StatusIs code-matcher
support (#190) our test conventions rely on. Comment refreshed to match.

Test: bazel test //xff/cli:hash_test //xff/cli:diff_test //xff/examples:cookbook_test
(mbo/digest + mbo/diff + smoke) pass against the BCR 0.13.0; pre-commit green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants