Skip to content

Do not rewrite a proto file that -fix did not change - #565

Open
Eljees wants to merge 1 commit into
yoheimuta:masterfrom
Eljees:fix-452-skip-write-when-unchanged
Open

Do not rewrite a proto file that -fix did not change#565
Eljees wants to merge 1 commit into
yoheimuta:masterfrom
Eljees:fix-452-skip-write-when-unchanged

Conversation

@Eljees

@Eljees Eljees commented Aug 15, 2026

Copy link
Copy Markdown

Fixes #452

The problem

protolint lint -fix updates the modification time of a file even when it changes
nothing in it. Tools that read a changed mtime as "the formatter touched this file"
then report a clean tree as dirty — the reporter hit this with treefmt-nix.

Reproduced on master:

$ cat clean.proto
syntax = "proto3";

package example;

message Example {
  string name = 1;
}

$ protolint lint clean.proto          # nothing to report
$ stat -c %y clean.proto
2020-01-01 00:00:00.000000000 +0000
$ protolint lint -fix clean.proto
$ stat -c %y clean.proto
2026-08-15 08:08:31.098081148 +0000   # changed
$ sha1sum clean.proto                 # ...while the content did not
8a4b2d6ea797ddc89b4907c77cf48d893e1e0530

The cause

BaseFixing.Finally always ends in osutil.WriteExistingFile, and that opens the
file with os.O_WRONLY|os.O_TRUNC, so the file is truncated and written back
unconditionally. BaseFixableVisitor.Finally calls it once per fixable rule, so a
file with nothing to fix is rewritten many times in a single run.

The change

Keep the bytes read in NewBaseFixing and skip the write when the fixed content is
equal to them. Files that do need fixing are written exactly as before.

Tests

linter/fixer had no test file, so this adds one: the case above plus a control
that a real edit is still written to disk.

  • before the change: mtime of an unmodified file changed: before ..., after ...
  • after the change: both tests pass
  • go test -race ./...: no new failures. internal/linter/report/reporters
    (TestEnvMatcherReporterFromUnallowedTemplateFile_Report) already fails on a
    clean master here and is unrelated to this change.

Checked on the CLI after the change: the clean file above keeps its 2020-01-01
timestamp, while a file with a real indentation problem is still fixed and written.

BaseFixing.Finally always ended in osutil.WriteExistingFile, which opens the
file with O_TRUNC, so every -fix run rewrote every file it looked at and updated
its modification time even when the content was byte-for-byte identical. Tools
that read a changed mtime as "the formatter touched this file", such as treefmt,
then report a clean file as modified.

Keep the content read at construction time and skip the write when the fixed
content is equal to it.

Fixes yoheimuta#452
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.

protolint -fix always updates the timestamp of the file

1 participant