Skip to content

Commit 781f529

Browse files
authored
refactor: replace filepath.Walk with WalkDir (#5416)
* refactor: replace filepath.Walk with WalkDir Walk is less efficient than [WalkDir], introduced in Go 1.16 which avoids calling os.Lstat on every visited file or directory. * lint: fix linter issues * lint: fix linter issues * fix: only use walkdir when it makes sense * lint: fix linter issue
1 parent 542db76 commit 781f529

File tree

8 files changed

+54
-28
lines changed

8 files changed

+54
-28
lines changed

dev-tools/mage/common.go

+19-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"errors"
2020
"fmt"
2121
"io"
22+
"io/fs"
2223
"log"
2324
"net/http"
2425
"os"
@@ -365,17 +366,22 @@ func Tar(src string, targetFile string) error {
365366
tw := tar.NewWriter(zr)
366367

367368
// walk through every file in the folder
368-
err = filepath.Walk(src, func(file string, fi os.FileInfo, errFn error) error {
369+
err = filepath.WalkDir(src, func(file string, d fs.DirEntry, errFn error) error {
369370
if errFn != nil {
370371
return fmt.Errorf("error traversing the file system: %w", errFn)
371372
}
372373

373374
// if a symlink, skip file
374-
if fi.Mode().Type() == os.ModeSymlink {
375+
if d.Type() == os.ModeSymlink {
375376
fmt.Printf(">> skipping symlink: %s\n", file)
376377
return nil
377378
}
378379

380+
fi, err := d.Info()
381+
if err != nil {
382+
return fmt.Errorf("error getting direntry info: %w", err)
383+
}
384+
379385
// generate tar header
380386
header, err := tar.FileInfoHeader(fi, file)
381387
if err != nil {
@@ -640,23 +646,28 @@ func FindFiles(globs ...string) ([]string, error) {
640646
// FindFilesRecursive recursively traverses from the CWD and invokes the given
641647
// match function on each regular file to determine if the given path should be
642648
// returned as a match. It ignores files in .git directories.
643-
func FindFilesRecursive(match func(path string, info os.FileInfo) bool) ([]string, error) {
649+
func FindFilesRecursive(match func(path string, d fs.FileInfo) bool) ([]string, error) {
644650
var matches []string
645-
err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
651+
err := filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error {
646652
if err != nil {
647653
return err
648654
}
649655

650656
// Don't look for files in git directories
651-
if info.Mode().IsDir() && filepath.Base(path) == ".git" {
657+
if d.IsDir() && filepath.Base(path) == ".git" {
652658
return filepath.SkipDir
653659
}
654660

655-
if !info.Mode().IsRegular() {
661+
if !d.Type().IsRegular() {
656662
// continue
657663
return nil
658664
}
659665

666+
info, err := d.Info()
667+
if err != nil {
668+
return err
669+
}
670+
660671
if match(filepath.ToSlash(path), info) {
661672
matches = append(matches, path)
662673
}
@@ -786,15 +797,15 @@ func IsUpToDate(dst string, sources ...string) bool {
786797

787798
var files []string
788799
for _, s := range sources {
789-
err := filepath.Walk(s, func(path string, info os.FileInfo, err error) error {
800+
err := filepath.WalkDir(s, func(path string, d fs.DirEntry, err error) error {
790801
if err != nil {
791802
if os.IsNotExist(err) {
792803
return nil
793804
}
794805
return err
795806
}
796807

797-
if info.Mode().IsRegular() {
808+
if d.Type().IsRegular() {
798809
files = append(files, path)
799810
}
800811

dev-tools/mage/dockerbuilder.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"errors"
1111
"fmt"
1212
"io"
13+
"io/fs"
1314
"os"
1415
"os/exec"
1516
"path/filepath"
@@ -115,8 +116,8 @@ func (b *dockerBuilder) prepareBuild() error {
115116
"Variant": b.DockerVariant.String(),
116117
}
117118

118-
err = filepath.Walk(templatesDir, func(path string, info os.FileInfo, _ error) error {
119-
if !info.IsDir() && !isDockerFile(path) {
119+
err = filepath.WalkDir(templatesDir, func(path string, d fs.DirEntry, _ error) error {
120+
if !d.Type().IsDir() && !isDockerFile(path) {
120121
target := strings.TrimSuffix(
121122
filepath.Join(b.buildDir, filepath.Base(path)),
122123
".tmpl",

dev-tools/mage/pkgtypes.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"compress/gzip"
1212
"fmt"
1313
"io"
14+
"io/fs"
1415
"log"
1516
"os"
1617
"path/filepath"
@@ -828,7 +829,7 @@ func addUIDGidEnvArgs(args []string) ([]string, error) {
828829

829830
// addFileToZip adds a file (or directory) to a zip archive.
830831
func addFileToZip(ar *zip.Writer, baseDir string, pkgFile PackageFile) error {
831-
return filepath.Walk(pkgFile.Source, func(path string, info os.FileInfo, err error) error {
832+
return filepath.Walk(pkgFile.Source, func(path string, info fs.FileInfo, err error) error {
832833
if err != nil {
833834
if pkgFile.SkipOnMissing && os.IsNotExist(err) {
834835
return nil
@@ -903,22 +904,27 @@ func addFileToTar(ar *tar.Writer, baseDir string, pkgFile PackageFile) error {
903904
"cloud-defend.spec.yml",
904905
}
905906

906-
return filepath.Walk(pkgFile.Source, func(path string, info os.FileInfo, err error) error {
907+
return filepath.WalkDir(pkgFile.Source, func(path string, d fs.DirEntry, err error) error {
907908
if err != nil {
908909
if pkgFile.SkipOnMissing && os.IsNotExist(err) {
909910
return nil
910911
}
911912
return err
912913
}
913914

914-
if slices.Contains(excludedFiles, info.Name()) {
915+
if slices.Contains(excludedFiles, d.Name()) {
915916
// it's a file we have to exclude
916917
if mg.Verbose() {
917918
log.Printf("Skipping file %q...", path)
918919
}
919920
return nil
920921
}
921922

923+
info, err := d.Info()
924+
if err != nil {
925+
return err
926+
}
927+
922928
header, err := tar.FileInfoHeader(info, info.Name())
923929
if err != nil {
924930
return err
@@ -984,7 +990,7 @@ func addSymlinkToTar(tmpdir string, ar *tar.Writer, baseDir string, pkgFile Pack
984990
return err
985991
}
986992

987-
return filepath.Walk(link, func(path string, info os.FileInfo, err error) error {
993+
return filepath.Walk(link, func(path string, info fs.FileInfo, err error) error {
988994
if err != nil {
989995
if pkgFile.SkipOnMissing && os.IsNotExist(err) {
990996
return nil

internal/pkg/agent/perms/windows.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func FixPermissions(topPath string, opts ...OptFunc) error {
8282
// call to `takeOwnership` which sets the ownership information requires the current process
8383
// token to have the 'SeRestorePrivilege' or it's unable to adjust the ownership
8484
return winio.RunWithPrivileges([]string{winio.SeRestorePrivilege}, func() error {
85-
return filepath.Walk(topPath, func(name string, info fs.FileInfo, err error) error {
85+
return filepath.WalkDir(topPath, func(name string, _ fs.DirEntry, err error) error {
8686
if err == nil {
8787
// first level doesn't inherit
8888
inherit := true
@@ -111,7 +111,7 @@ func FixPermissions(topPath string, opts ...OptFunc) error {
111111
}
112112

113113
// ownership cannot be changed, this will keep the ownership as it currently is but apply the ACL's
114-
return filepath.Walk(topPath, func(name string, info fs.FileInfo, err error) error {
114+
return filepath.WalkDir(topPath, func(name string, _ fs.DirEntry, err error) error {
115115
if err == nil {
116116
// first level doesn't inherit
117117
inherit := true

magefile.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"errors"
1515
"fmt"
1616
"html/template"
17+
"io/fs"
1718
"log"
1819
"maps"
1920
"math/rand/v2"
@@ -1599,16 +1600,16 @@ func selectedPackageTypes() string {
15991600
}
16001601

16011602
func copyAll(from, to string, suffixes ...[]string) error {
1602-
return filepath.Walk(from, func(path string, info os.FileInfo, err error) error {
1603+
return filepath.WalkDir(from, func(path string, d fs.DirEntry, err error) error {
16031604
if err != nil {
16041605
return err
16051606
}
16061607

1607-
if info.IsDir() {
1608+
if d.IsDir() {
16081609
return nil
16091610
}
16101611

1611-
targetFile := filepath.Join(to, info.Name())
1612+
targetFile := filepath.Join(to, d.Name())
16121613

16131614
// overwrites with current build
16141615
return sh.Copy(targetFile, path)
@@ -1760,8 +1761,8 @@ func prepareIronbankBuild() error {
17601761
"MajorMinor": majorMinor(),
17611762
}
17621763

1763-
err := filepath.Walk(templatesDir, func(path string, info os.FileInfo, _ error) error {
1764-
if !info.IsDir() {
1764+
err := filepath.WalkDir(templatesDir, func(path string, d fs.DirEntry, _ error) error {
1765+
if !d.IsDir() {
17651766
target := strings.TrimSuffix(
17661767
filepath.Join(buildDir, filepath.Base(path)),
17671768
".tmpl",

pkg/testing/fixture_install.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -721,11 +721,11 @@ func (f *Fixture) archiveInstallDirectory(installPath string, outputPath string)
721721
w := zip.NewWriter(file)
722722
defer w.Close()
723723

724-
walker := func(path string, info os.FileInfo, err error) error {
724+
walker := func(path string, d fs.DirEntry, err error) error {
725725
if err != nil {
726726
return err
727727
}
728-
if info.IsDir() {
728+
if d.IsDir() {
729729
return nil
730730
}
731731
file, err := os.Open(path)
@@ -748,7 +748,7 @@ func (f *Fixture) archiveInstallDirectory(installPath string, outputPath string)
748748
return nil
749749
}
750750

751-
err = filepath.Walk(f.workDir, walker)
751+
err = filepath.WalkDir(f.workDir, walker)
752752
if err != nil {
753753
return fmt.Errorf("walking %s to create zip: %w", f.workDir, err)
754754
}

testing/installtest/checks_unix.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package installtest
99
import (
1010
"context"
1111
"fmt"
12+
"io/fs"
1213
"os"
1314
"os/exec"
1415
"path/filepath"
@@ -103,14 +104,18 @@ func checkPlatform(ctx context.Context, _ *atesting.Fixture, topPath string, opt
103104
}
104105

105106
func validateFileTree(dir string, uid uint32, gid uint32) error {
106-
return filepath.Walk(dir, func(file string, info os.FileInfo, err error) error {
107+
return filepath.WalkDir(dir, func(file string, d fs.DirEntry, err error) error {
107108
if err != nil {
108109
return fmt.Errorf("error traversing the file tree: %w", err)
109110
}
110-
if info.Mode().Type() == os.ModeSymlink {
111+
if d.Type() == os.ModeSymlink {
111112
// symlink don't check permissions
112113
return nil
113114
}
115+
info, err := d.Info()
116+
if err != nil {
117+
return fmt.Errorf("error caling info: %w", err)
118+
}
114119
fs, ok := info.Sys().(*syscall.Stat_t)
115120
if !ok {
116121
return fmt.Errorf("failed to convert info.Sys() into *syscall.Stat_t")

testing/integration/diagnostics_test.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,14 @@ func verifyDiagnosticArchive(t *testing.T, compSetup map[string]integrationtest.
245245

246246
actualExtractedDiagFiles := map[string]struct{}{}
247247

248-
err = filepath.Walk(extractionDir, func(path string, info fs.FileInfo, err error) error {
248+
err = filepath.WalkDir(extractionDir, func(path string, entry fs.DirEntry, err error) error {
249249
require.NoErrorf(t, err, "error walking extracted path %q", path)
250250

251251
// we are not interested in directories
252-
if !info.IsDir() {
252+
if !entry.IsDir() {
253253
actualExtractedDiagFiles[path] = struct{}{}
254+
info, err := entry.Info()
255+
require.NoError(t, err, path)
254256
assert.Greaterf(t, info.Size(), int64(0), "file %q has an invalid size", path)
255257
}
256258

0 commit comments

Comments
 (0)