github.com/tooploox/oya@v0.0.21-0.20230524103240-1cda1861aad6/pkg/project/list.go (about)

     1  package project
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	"github.com/pkg/errors"
     9  	"github.com/tooploox/oya/pkg/oyafile"
    10  	"k8s.io/helm/pkg/ignore"
    11  )
    12  
    13  func (p *Project) Oyafiles() ([]*oyafile.Oyafile, error) {
    14  	return p.List(p.RootDir)
    15  }
    16  
    17  func (p *Project) List(startDir string) ([]*oyafile.Oyafile, error) {
    18  	skip := p.makeSkipFunc(startDir)
    19  	ignore, err := p.makeIgnoreFunc()
    20  	if err != nil {
    21  		return nil, errors.Wrapf(err, "error setting up ignores in %v", startDir)
    22  	}
    23  	var oyafiles []*oyafile.Oyafile
    24  	return oyafiles, filepath.Walk(startDir, func(path string, info os.FileInfo, err error) error {
    25  		if err != nil {
    26  			return err
    27  		}
    28  		if !info.IsDir() {
    29  			return nil
    30  		}
    31  		doSkip, err := skip(path)
    32  		if err != nil {
    33  			return errors.Wrapf(err, "error trying to determine if %v should be skipped", path)
    34  		}
    35  		if doSkip {
    36  			return filepath.SkipDir
    37  		}
    38  		oyafile, ok, err := p.oyafileIn(path)
    39  		if err != nil {
    40  			return errors.Wrapf(err, "error loading Oyafile from %v", path)
    41  		}
    42  		if !ok {
    43  			return nil
    44  		}
    45  		doIgnore, err := ignore(oyafile)
    46  		if err != nil {
    47  			return errors.Wrapf(err, "error trying to determine if %v should be ignored", oyafile.Path)
    48  		}
    49  		if doIgnore {
    50  			return filepath.SkipDir
    51  		}
    52  		oyafiles = append(oyafiles, oyafile)
    53  		return nil
    54  	})
    55  }
    56  
    57  // makeSkipFunc returns a function that given a path, returns
    58  // true if the entire subdirectory should be ignored.
    59  // Similar to makeIgnoreFunc but does not parse Oyafile, thus allowing
    60  // for broken Oyafile projects nested under the current project.
    61  func (p *Project) makeSkipFunc(startDir string) func(path string) (bool, error) {
    62  	return func(path string) (bool, error) {
    63  		// Exclude projects nested under the current project.
    64  
    65  		raw, found, err := p.rawOyafileIn(path)
    66  		if err != nil {
    67  			return false, err
    68  		}
    69  		if !found {
    70  			return false, nil
    71  		}
    72  
    73  		isRoot, err := raw.IsRoot()
    74  		if err != nil {
    75  			return false, err
    76  		}
    77  
    78  		// BUG(bilus): Clean up this magic string & logic duplication everywhere.
    79  		_, isProject, err := raw.Project()
    80  		if err != nil {
    81  			return false, err
    82  		}
    83  
    84  		return isProject && !isRoot, nil
    85  	}
    86  }
    87  
    88  // makeIgnoreFunc returns a function that given an oyafile returns true if its containing directory tree should be recursively ignored.
    89  // It uses an array of relative paths under "Ignore:" key in the project's root Oyafile.
    90  // BUG(bilus): We should probably make it more intuitive by supporting Ignore: directives in nested dirs as well as the root dir.
    91  func (p *Project) makeIgnoreFunc() (func(*oyafile.Oyafile) (bool, error), error) {
    92  	o, ok, err := p.oyafileIn(p.RootDir)
    93  	if err != nil {
    94  		return nil, errors.Wrapf(err, "error looking for Ignore: directive")
    95  	}
    96  	if !ok {
    97  		return nil, errors.Errorf("No oyafile found at %v", p.RootDir)
    98  	}
    99  	ignore, err := ignore.Parse(strings.NewReader(o.Ignores()))
   100  	if err != nil {
   101  		return nil, errors.Wrapf(err, "Ignore: in %v contains invalid entries", o.Path)
   102  	}
   103  	return func(o *oyafile.Oyafile) (bool, error) {
   104  		fi, err := os.Stat(o.Path)
   105  		if err != nil {
   106  			return true, err
   107  		}
   108  
   109  		return ignore.Ignore(o.RelPath(), fi), nil
   110  	}, nil
   111  }