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 }