From 5306a5e092a5fc5930b910f4c6fd14b63e5e42d7 Mon Sep 17 00:00:00 2001 From: zimbatm Date: Wed, 28 Aug 2024 15:24:41 +0200 Subject: [PATCH] fix: resolve commands relative to the root When configuring treefmt with relative paths to commands, for example if you want to create your own repo-specific wrappers, treefmt would fail if executed in a sub-directory. This change makes sure that the relative path is resolved based on the treefmt root instead of the current directory. --- cli/format.go | 5 ++++- cli/format_test.go | 9 ++++++++- format/formatter.go | 12 ++++++------ go.mod | 3 +++ go.sum | 26 ++++++++++---------------- nix/packages/treefmt/gomod2nix.toml | 9 +++++++++ 6 files changed, 40 insertions(+), 24 deletions(-) diff --git a/cli/format.go b/cli/format.go index 4b8f7fa1..584cece7 100644 --- a/cli/format.go +++ b/cli/format.go @@ -15,6 +15,7 @@ import ( "git.numtide.com/numtide/treefmt/format" "git.numtide.com/numtide/treefmt/stats" + "mvdan.cc/sh/v3/expand" "git.numtide.com/numtide/treefmt/cache" "git.numtide.com/numtide/treefmt/config" @@ -136,8 +137,10 @@ func (f *Format) Run() (err error) { // initialise formatters f.formatters = make(map[string]*format.Formatter) + env := expand.ListEnviron(os.Environ()...) + for name, formatterCfg := range cfg.Formatters { - formatter, err := format.NewFormatter(name, f.TreeRoot, formatterCfg) + formatter, err := format.NewFormatter(name, f.TreeRoot, env, formatterCfg) if errors.Is(err, format.ErrCommandNotFound) && f.AllowMissingFormatter { log.Debugf("formatter command not found: %v", name) diff --git a/cli/format_test.go b/cli/format_test.go index e8b48047..303cbfcc 100644 --- a/cli/format_test.go +++ b/cli/format_test.go @@ -718,6 +718,13 @@ func TestRunInSubdir(t *testing.T) { tempDir := test.TempExamples(t) configPath := filepath.Join(tempDir, "/treefmt.toml") + // Also test that formatters are resolved relative to the treefmt root + echoPath, err := exec.LookPath("echo") + as.NoError(err) + echoRel := path.Join(tempDir, "echo") + err = os.Symlink(echoPath, echoRel) + as.NoError(err) + // change working directory to sub directory as.NoError(os.Chdir(filepath.Join(tempDir, "elm"))) @@ -725,7 +732,7 @@ func TestRunInSubdir(t *testing.T) { cfg := config.Config{ Formatters: map[string]*config.Formatter{ "echo": { - Command: "echo", + Command: "./echo", Includes: []string{"*"}, }, }, diff --git a/format/formatter.go b/format/formatter.go index 36687393..58ea1894 100644 --- a/format/formatter.go +++ b/format/formatter.go @@ -8,12 +8,13 @@ import ( "os/exec" "time" - "git.numtide.com/numtide/treefmt/walk" - "git.numtide.com/numtide/treefmt/config" + "git.numtide.com/numtide/treefmt/walk" "github.com/charmbracelet/log" "github.com/gobwas/glob" + "mvdan.cc/sh/v3/expand" + "mvdan.cc/sh/v3/interp" ) // ErrCommandNotFound is returned when the Command for a Formatter is not available. @@ -101,6 +102,7 @@ func (f *Formatter) Wants(file *walk.File) bool { func NewFormatter( name string, treeRoot string, + env expand.Environ, cfg *config.Formatter, ) (*Formatter, error) { var err error @@ -113,11 +115,9 @@ func NewFormatter( f.workingDir = treeRoot // test if the formatter is available - executable, err := exec.LookPath(cfg.Command) - if errors.Is(err, exec.ErrNotFound) { + executable, err := interp.LookPathDir(treeRoot, env, cfg.Command) + if err != nil { return nil, ErrCommandNotFound - } else if err != nil { - return nil, err } f.executable = executable diff --git a/go.mod b/go.mod index 53fc4d1e..c526de13 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/vmihailenco/msgpack/v5 v5.4.1 go.etcd.io/bbolt v1.3.11 golang.org/x/sync v0.8.0 + mvdan.cc/sh/v3 v3.9.0 ) require ( @@ -35,6 +36,7 @@ require ( github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect @@ -48,6 +50,7 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sys v0.24.0 // indirect + golang.org/x/term v0.23.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index f1f5d114..669b3c81 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,8 @@ github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1 github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI= github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= +github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= +github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -42,26 +44,18 @@ github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.1-0.20240805213603-fac749f7395a h1:E7kbQRzNItbtGVcgXR8HtmtOiyTGIjD3s/LX9e89kcA= -github.com/go-git/go-billy/v5 v5.5.1-0.20240805213603-fac749f7395a/go.mod h1:X5ZGvb06udYfe+YUV3Hml7eWViUhjq98lqGLz53viVc= -github.com/go-git/go-billy/v5 v5.5.1-0.20240814154544-eaed248167f1 h1:MGoBSiT4C9k32pmVplTXDBGupItZle84QUa9pVTuOSQ= -github.com/go-git/go-billy/v5 v5.5.1-0.20240814154544-eaed248167f1/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= github.com/go-git/go-billy/v5 v5.5.1-0.20240819193939-9b484184bdcc h1:fpw3vn8skBvfPwsKRq6K2o/55ZcwAid/9lubG/NyNNE= github.com/go-git/go-billy/v5 v5.5.1-0.20240819193939-9b484184bdcc/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= github.com/go-git/go-billy/v5 v5.5.1-0.20240828070317-59c50b000c7a h1:CDPmu0p7gv6zJn35T/RtZyIq98I2SwHtLrp697pM3KI= github.com/go-git/go-billy/v5 v5.5.1-0.20240828070317-59c50b000c7a/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.12.1-0.20240807144107-c594bae8d75d h1:hJt4GF2BxUI1X20p6APebYu4T7TG4t3HWNwEbgFVilU= -github.com/go-git/go-git/v5 v5.12.1-0.20240807144107-c594bae8d75d/go.mod h1:HxWls9Nx+4sukm5KsYVOz6rR+YJBB4QaVDFaXzG/weQ= -github.com/go-git/go-git/v5 v5.12.1-0.20240809133458-4fd9979d5c29 h1:ziylW6O1GsEiHK+i7/F0ZlFRV3b6bodRsVtzdaom6EM= -github.com/go-git/go-git/v5 v5.12.1-0.20240809133458-4fd9979d5c29/go.mod h1:tTeL/MQl8Pjm1QfKA/x/F0E04y9g5EynnXfV52kvvTw= -github.com/go-git/go-git/v5 v5.12.1-0.20240821090644-6d583524d3e1 h1:ggoxUMCVjbfxO/CqzeYCUdUyVgCBoXjlN7aeksTylSQ= -github.com/go-git/go-git/v5 v5.12.1-0.20240821090644-6d583524d3e1/go.mod h1:tTeL/MQl8Pjm1QfKA/x/F0E04y9g5EynnXfV52kvvTw= github.com/go-git/go-git/v5 v5.12.1-0.20240821195137-5c762aefcd8d h1:+KOoJFltZdLrtMrrOqaTYr8LWc7q296l6Y/+/bS9At0= github.com/go-git/go-git/v5 v5.12.1-0.20240821195137-5c762aefcd8d/go.mod h1:tTeL/MQl8Pjm1QfKA/x/F0E04y9g5EynnXfV52kvvTw= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -88,6 +82,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= @@ -108,8 +104,8 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -127,8 +123,6 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= -go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -169,8 +163,6 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -204,3 +196,5 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +mvdan.cc/sh/v3 v3.9.0 h1:it14fyjCdQUk4jf/aYxLO3FG8jFarR9GzMCtnlvvD7c= +mvdan.cc/sh/v3 v3.9.0/go.mod h1:cdBk8bgoiBI7lSZqK5JhUuq7OB64VQ7fgm85xelw3Nk= diff --git a/nix/packages/treefmt/gomod2nix.toml b/nix/packages/treefmt/gomod2nix.toml index 335d5812..65ace2ca 100644 --- a/nix/packages/treefmt/gomod2nix.toml +++ b/nix/packages/treefmt/gomod2nix.toml @@ -74,6 +74,9 @@ schema = 3 [mod."github.com/mattn/go-runewidth"] version = "v0.0.15" hash = "sha256-WP39EU2UrQbByYfnwrkBDoKN7xzXsBssDq3pNryBGm0=" + [mod."github.com/muesli/cancelreader"] + version = "v0.2.2" + hash = "sha256-uEPpzwRJBJsQWBw6M71FDfgJuR7n55d/7IV8MO+rpwQ=" [mod."github.com/muesli/reflow"] version = "v0.3.0" hash = "sha256-Pou2ybE9SFSZG6YfZLVV1Eyfm+X4FuVpDPLxhpn47Cc=" @@ -128,9 +131,15 @@ schema = 3 [mod."golang.org/x/sys"] version = "v0.24.0" hash = "sha256-P0fsA+qy9taYHWPTtCs5XmrJ1i8tWfvkno+PNuc2elw=" + [mod."golang.org/x/term"] + version = "v0.23.0" + hash = "sha256-ECmmK3Wc0g/zUy5wAokj7ItRsUi6eoqSe9s9Uhcwu90=" [mod."gopkg.in/warnings.v0"] version = "v0.1.2" hash = "sha256-ATVL9yEmgYbkJ1DkltDGRn/auGAjqGOfjQyBYyUo8s8=" [mod."gopkg.in/yaml.v3"] version = "v3.0.1" hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU=" + [mod."mvdan.cc/sh/v3"] + version = "v3.9.0" + hash = "sha256-yTQXBY9TSqRmS1Vx7k1rtiwK7xQwTPTv37dR8D4/zdU="