github.com/vchain-us/vcn@v0.9.11-0.20210921212052-a2484d23c0b3/pkg/extractor/wildcard/wildcard.go (about)

     1  /*
     2   * Copyright (c) 2018-2020 vChain, Inc. All Rights Reserved.
     3   * This software is released under GPL3.
     4   * The full license information can be found under:
     5   * https://www.gnu.org/licenses/gpl-3.0.en.html
     6   *
     7   */
     8  
     9  package wildcard
    10  
    11  import (
    12  	"errors"
    13  	"github.com/vchain-us/vcn/pkg/extractor/dir"
    14  	"github.com/vchain-us/vcn/pkg/extractor/file"
    15  	"os"
    16  	"path/filepath"
    17  	"strings"
    18  
    19  	"github.com/vchain-us/vcn/pkg/api"
    20  	"github.com/vchain-us/vcn/pkg/extractor"
    21  	"github.com/vchain-us/vcn/pkg/uri"
    22  )
    23  
    24  // Scheme for dir
    25  const Scheme = "wildcard"
    26  
    27  // ManifestKey is the metadata's key for storing the manifest
    28  const ManifestKey = "manifest"
    29  
    30  // PathKey is the metadata's key for the directory path
    31  const PathKey = "path"
    32  
    33  type opts struct {
    34  	initIgnoreFile    bool
    35  	skipIgnoreFileErr bool
    36  	recursive         bool
    37  }
    38  
    39  // Artifact returns a file *api.Artifact from a given u
    40  func Artifact(u *uri.URI, options ...extractor.Option) ([]*api.Artifact, error) {
    41  
    42  	if u.Scheme != "" && u.Scheme != Scheme {
    43  		return nil, nil
    44  	}
    45  
    46  	opts := &opts{}
    47  	if err := extractor.Options(options).Apply(opts); err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	path := strings.TrimPrefix(u.Opaque, "//")
    52  	wildcard := filepath.Base(path)
    53  	p, err := filepath.Abs(path)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	// provided path is a file
    59  	if fileInfo, err := os.Stat(p); err == nil {
    60  		if !fileInfo.IsDir() {
    61  			u, err := uri.Parse("file://" + p)
    62  			if err != nil {
    63  				return nil, err
    64  			}
    65  			return file.Artifact(u)
    66  		}
    67  		u, err := uri.Parse("dir://" + p)
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  		return dir.Artifact(u)
    72  	}
    73  
    74  	root := filepath.Dir(p)
    75  
    76  	if opts.initIgnoreFile {
    77  		if err := dir.InitIgnoreFile(path); err != nil {
    78  			if !opts.skipIgnoreFileErr {
    79  				return nil, err
    80  			}
    81  		}
    82  	}
    83  
    84  	// build a list of all files matching the wildcard provided. Method is based on filepath.Glob
    85  	var filePaths []string
    86  	if opts.recursive {
    87  		err = filepath.Walk(root, buildFilePaths(wildcard, &filePaths))
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  	} else {
    92  		i, err := os.Stat(root)
    93  		if err != nil {
    94  			return nil, err
    95  		}
    96  		err = buildFilePaths(wildcard, &filePaths)(root, i, nil)
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  	}
   101  
   102  	if len(filePaths) == 0 {
   103  		return nil, errors.New("no files matching from provided search terms")
   104  	}
   105  
   106  	arst := []*api.Artifact{}
   107  	// convert files path list to artifacts
   108  	for _, fp := range filePaths {
   109  		u, err := uri.Parse("file://" + fp)
   110  		if err != nil {
   111  			return nil, err
   112  		}
   113  		ars, err := file.Artifact(u)
   114  		if err != nil {
   115  			return nil, err
   116  		}
   117  		arst = append(arst, ars...)
   118  	}
   119  
   120  	return arst, nil
   121  }
   122  
   123  func buildFilePaths(wildcard string, filePaths *[]string) func(ele string, info os.FileInfo, err error) error {
   124  	return func(ele string, info os.FileInfo, err error) error {
   125  		if info.IsDir() {
   126  			fpd, err := filepath.Glob(filepath.Join(ele, wildcard))
   127  			if err != nil {
   128  				return err
   129  			}
   130  			if len(fpd) > 0 {
   131  				for _, fp := range fpd {
   132  					info, err = os.Stat(fp)
   133  					if err != nil {
   134  						return err
   135  					}
   136  					if !info.IsDir() {
   137  						*filePaths = append(*filePaths, fp)
   138  					}
   139  				}
   140  			}
   141  		}
   142  		return nil
   143  	}
   144  }
   145  
   146  // WithRecursive wildcard usage will walk inside subdirectories of provided path
   147  func WithRecursive() extractor.Option {
   148  	return func(o interface{}) error {
   149  		if o, ok := o.(*opts); ok {
   150  			o.recursive = true
   151  		}
   152  		return nil
   153  	}
   154  }