From 38a3364f5f098906316f4ed0f3ee3cc27833b682 Mon Sep 17 00:00:00 2001 From: testing Date: Sun, 5 Apr 2026 07:17:05 +0200 Subject: [PATCH] fix: normalize stdin path to be relative to tree root When using --stdin with an absolute path, the RelPath was incorrectly set to the absolute path, causing pattern matching for includes and excludes to fail against project-relative globs. This change ensures that the path provided with --stdin is converted to a relative path from the tree root before processing. --- cmd/root_test.go | 36 ++++++++++++++++++++++++++++++++++++ walk/walk.go | 20 +++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/cmd/root_test.go b/cmd/root_test.go index 11cbcfed..119d27db 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -2117,6 +2117,42 @@ func TestStdin(t *testing.T) { }), ) + // verify that absolute paths work + absPath, err := filepath.Abs("test.nix") + as.NoError(err) + os.Stdin = test.TempFile(t, "", "stdin", &contents) + + treefmt(t, + withArgs("--stdin", absPath), + withNoError(t), + withStats(t, map[stats.Type]int{ + stats.Traversed: 1, + stats.Matched: 1, + stats.Formatted: 1, + stats.Changed: 1, + }), + withStdout(func(out []byte) { + as.Equal(`{ ...}: "hello" +`, string(out)) + }), + ) + + // verify that absolute paths in subdirectories work with glob patterns + absPathInSubdir, err := filepath.Abs(filepath.Join("go", "main.go")) + as.NoError(err) + goContents := "package main\n" + os.Stdin = test.TempFile(t, "", "stdin", &goContents) + + treefmt(t, + withArgs("--stdin", absPathInSubdir), + withNoError(t), + withStats(t, map[stats.Type]int{ + stats.Traversed: 1, + stats.Matched: 1, + stats.Formatted: 1, + }), + ) + // the nix formatters should have reduced the example to the following // try a file that's outside of the project root diff --git a/walk/walk.go b/walk/walk.go index b851bfa2..b767a217 100644 --- a/walk/walk.go +++ b/walk/walk.go @@ -283,12 +283,26 @@ func NewCompositeReader( } path := paths[0] + resolvedPath, err := resolvePath(path) + if err != nil { + // If the path doesn't exist, we still want to make it relative to the root if possible. + // We use the absolute path without resolving symlinks. + resolvedPath, err = filepath.Abs(path) + if err != nil { + return nil, fmt.Errorf("error computing absolute path of %s: %w", path, err) + } + } + + relativePath, err := filepath.Rel(root, resolvedPath) + if err != nil { + return nil, fmt.Errorf("error computing relative path from %s to %s: %w", root, resolvedPath, err) + } - if strings.HasPrefix(path, "..") { - return nil, fmt.Errorf("path %s not inside the tree root %s", path, root) + if strings.HasPrefix(relativePath, "..") { + return nil, fmt.Errorf("path %s not inside the tree root %s (relative path: %s)", path, root, relativePath) } - return NewStdinReader(root, path, statz), nil + return NewStdinReader(root, relativePath, statz), nil } // create a reader for each provided path