@@ -2,14 +2,14 @@ package redesign
22
33import (
44 "io/fs"
5- "os"
65 "path/filepath"
76 "strings"
87
98 "github.com/gruntwork-io/terragrunt/internal/errors"
109 "github.com/gruntwork-io/terragrunt/internal/services/catalog/ignore"
1110 "github.com/gruntwork-io/terragrunt/internal/services/catalog/module"
1211 "github.com/gruntwork-io/terragrunt/internal/util"
12+ "github.com/gruntwork-io/terragrunt/internal/vfs"
1313 "github.com/gruntwork-io/terragrunt/pkg/config"
1414)
1515
@@ -41,12 +41,13 @@ const (
4141// Construct one via NewComponentDiscovery, customize it with the With*
4242// methods, then call Discover on a repo.
4343type ComponentDiscovery struct {
44+ fsys vfs.FS
4445 extraIgnoreFile string
4546 walkWithSymlinks bool
4647}
4748
4849// NewComponentDiscovery returns a ComponentDiscovery with default settings:
49- // no symlink following, no extra ignore file.
50+ // no symlink following, no extra ignore file, the real OS filesystem .
5051func NewComponentDiscovery () * ComponentDiscovery {
5152 return & ComponentDiscovery {}
5253}
@@ -65,6 +66,13 @@ func (cd *ComponentDiscovery) WithExtraIgnoreFile(i string) *ComponentDiscovery
6566 return cd
6667}
6768
69+ // WithFS sets the filesystem used for the discovery walk and per-component
70+ // README reads. When unset, Discover uses vfs.NewOSFS().
71+ func (cd * ComponentDiscovery ) WithFS (fsys vfs.FS ) * ComponentDiscovery {
72+ cd .fsys = fsys
73+ return cd
74+ }
75+
6876// Discover runs component discovery against repo.
6977func (cd * ComponentDiscovery ) Discover (repo * module.Repo ) (Components , error ) {
7078 if repo == nil {
@@ -78,18 +86,28 @@ func (cd *ComponentDiscovery) Discover(repo *module.Repo) (Components, error) {
7886 return nil , errors .New ("ComponentDiscovery.Discover: empty repo path" )
7987 }
8088
81- walkFunc := filepath .WalkDir
89+ fsys := cd .fsys
90+ if fsys == nil {
91+ fsys = vfs .NewOSFS ()
92+ }
93+
94+ // util.WalkDirWithSymlinks is OS-only; when symlink following is on, we
95+ // continue using it and leave vfs integration as a future cleanup.
96+ walkFunc := func (root string , fn fs.WalkDirFunc ) error {
97+ return vfs .WalkDir (fsys , root , fn )
98+ }
99+
82100 if cd .walkWithSymlinks {
83101 walkFunc = util .WalkDirWithSymlinks
84102 }
85103
86- ignoreMatcher , err := ignore .Load (repoPath )
104+ ignoreMatcher , err := ignore .Load (fsys , repoPath )
87105 if err != nil {
88106 return nil , err
89107 }
90108
91109 if cd .extraIgnoreFile != "" {
92- extraMatcher , err := ignore .LoadFile (cd .extraIgnoreFile )
110+ extraMatcher , err := ignore .LoadFile (fsys , cd .extraIgnoreFile )
93111 if err != nil {
94112 return nil , err
95113 }
@@ -126,7 +144,7 @@ func (cd *ComponentDiscovery) Discover(repo *module.Repo) (Components, error) {
126144 return fs .SkipDir
127145 }
128146
129- kind , isComponent , err := classifyDir (dir )
147+ kind , isComponent , err := classifyDir (fsys , dir )
130148 if err != nil {
131149 return err
132150 }
@@ -135,7 +153,7 @@ func (cd *ComponentDiscovery) Discover(repo *module.Repo) (Components, error) {
135153 return nil
136154 }
137155
138- c , err := newComponent (repo , repoPath , cloneURL , relDir , kind )
156+ c , err := newComponent (fsys , repo , repoPath , cloneURL , relDir , kind )
139157 if err != nil {
140158 return err
141159 }
@@ -164,8 +182,8 @@ func (cd *ComponentDiscovery) Discover(repo *module.Repo) (Components, error) {
164182// classifyDir inspects a single directory and returns its ComponentKind.
165183// Precedence: stack > unit > template > module. A terragrunt.stack.hcl wins
166184// over a terragrunt.hcl, a .boilerplate/, and plain .tf files.
167- func classifyDir (dir string ) (ComponentKind , bool , error ) {
168- entries , err := os . ReadDir ( dir )
185+ func classifyDir (fsys vfs. FS , dir string ) (ComponentKind , bool , error ) {
186+ entries , err := readDirEntries ( fsys , dir )
169187 if err != nil {
170188 return 0 , false , errors .New (err )
171189 }
@@ -229,8 +247,8 @@ func isSkippableDir(name string) bool {
229247// newComponent constructs a *Component for a directory that has been
230248// classified. It populates the doc and URL fields the same way the legacy
231249// module.NewModule does, but into the redesign-owned Component type.
232- func newComponent (repo * module.Repo , repoPath , cloneURL , relDir string , kind ComponentKind ) (* Component , error ) {
233- doc , err := FindComponentDoc (filepath .Join (repoPath , relDir ))
250+ func newComponent (fsys vfs. FS , repo * module.Repo , repoPath , cloneURL , relDir string , kind ComponentKind ) (* Component , error ) {
251+ doc , err := FindComponentDoc (fsys , filepath .Join (repoPath , relDir ))
234252 if err != nil {
235253 return nil , err
236254 }
0 commit comments