github.com/snyk/vervet/v3@v3.7.0/internal/files/files.go (about)

     1  package files
     2  
     3  import (
     4  	"io/fs"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/bmatcuk/doublestar/v4"
     9  
    10  	"github.com/snyk/vervet/v3"
    11  	"github.com/snyk/vervet/v3/config"
    12  )
    13  
    14  // FileSource defines a source of spec files to lint. This abstraction allows
    15  // linters to operate seamlessly over version control systems and local files.
    16  type FileSource interface {
    17  	// Name returns a string describing the file source.
    18  	Name() string
    19  
    20  	// Match returns a slice of logical paths to spec files that should be
    21  	// linted from the given resource set configuration.
    22  	Match(*config.ResourceSet) ([]string, error)
    23  
    24  	// Prefetch retrieves an entire directory tree starting at the given root,
    25  	// for remote sources which need to download and cache a local copy. For
    26  	// such sources, a call to Fetch without a pre-fetched root will error.
    27  	// The path to the local copy of the "root" is returned.
    28  	//
    29  	// For local sources, this method may be a no-op / passthrough.
    30  	//
    31  	// The root must contain all relative OpenAPI $ref references in all linted
    32  	// specs, or the lint will fail.
    33  	Prefetch(root string) (string, error)
    34  
    35  	// Fetch retrieves the contents of the requested logical path as a local
    36  	// file and returns the absolute path where it may be found. An empty
    37  	// string, rather than an error, is returned if the file does not exist.
    38  	Fetch(path string) (string, error)
    39  
    40  	// Close releases any resources consumed in content retrieval. Any files
    41  	// returned by Fetch will no longer be available after calling Close, and
    42  	// any further calls to Fetch will error.
    43  	Close() error
    44  }
    45  
    46  // NilSource is a FileSource that does not have any files in it.
    47  type NilSource struct{}
    48  
    49  // Name implements FileSource.
    50  func (NilSource) Name() string { return "does not exist" }
    51  
    52  // Match implements FileSource.
    53  func (NilSource) Match(*config.ResourceSet) ([]string, error) { return nil, nil }
    54  
    55  // Prefetch implements FileSource.
    56  func (NilSource) Prefetch(root string) (string, error) {
    57  	return "", nil
    58  }
    59  
    60  // Fetch implements FileSource.
    61  func (NilSource) Fetch(path string) (string, error) {
    62  	return "", nil
    63  }
    64  
    65  // Close implements FileSource.
    66  func (NilSource) Close() error { return nil }
    67  
    68  // LocalFSSource is a FileSource that resolves files from the local filesystem
    69  // relative to the current working directory.
    70  type LocalFSSource struct{}
    71  
    72  // Name implements FileSource.
    73  func (LocalFSSource) Name() string { return "local file" }
    74  
    75  // Match implements FileSource.
    76  func (LocalFSSource) Match(rcConfig *config.ResourceSet) ([]string, error) {
    77  	var result []string
    78  	err := doublestar.GlobWalk(os.DirFS(rcConfig.Path),
    79  		vervet.SpecGlobPattern,
    80  		func(path string, d fs.DirEntry) error {
    81  			rcPath := filepath.Join(rcConfig.Path, path)
    82  			for i := range rcConfig.Excludes {
    83  				if ok, err := doublestar.Match(rcConfig.Excludes[i], rcPath); ok {
    84  					return nil
    85  				} else if err != nil {
    86  					return err
    87  				}
    88  			}
    89  			result = append(result, rcPath)
    90  			return nil
    91  		})
    92  	return result, err
    93  }
    94  
    95  // Prefetch implements FileSource.
    96  func (LocalFSSource) Prefetch(root string) (string, error) {
    97  	cwd, err := os.Getwd()
    98  	if err != nil {
    99  		return "", err
   100  	}
   101  	return filepath.Join(cwd, root), nil
   102  }
   103  
   104  // Fetch implements FileSource.
   105  func (LocalFSSource) Fetch(path string) (string, error) {
   106  	if _, err := os.Stat(path); err == nil {
   107  		return filepath.Abs(path)
   108  	} else if os.IsNotExist(err) {
   109  		return "", nil
   110  	} else {
   111  		return "", err
   112  	}
   113  }
   114  
   115  // Close implements FileSource.
   116  func (LocalFSSource) Close() error { return nil }