github.com/vchain-us/vcn@v0.9.11-0.20210921212052-a2484d23c0b3/pkg/extractor/dir/dir.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 dir 10 11 import ( 12 "fmt" 13 "os" 14 "path/filepath" 15 "strings" 16 17 "github.com/vchain-us/vcn/pkg/api" 18 "github.com/vchain-us/vcn/pkg/bundle" 19 "github.com/vchain-us/vcn/pkg/extractor" 20 "github.com/vchain-us/vcn/pkg/uri" 21 ) 22 23 // Scheme for dir 24 const Scheme = "dir" 25 26 // ManifestKey is the metadata's key for storing the manifest 27 const ManifestKey = "manifest" 28 29 // PathKey is the metadata's key for the directory path 30 const PathKey = "path" 31 32 type opts struct { 33 initIgnoreFile bool 34 skipIgnoreFileErr bool 35 } 36 37 // Artifact returns a file *api.Artifact from a given u 38 func Artifact(u *uri.URI, options ...extractor.Option) ([]*api.Artifact, error) { 39 40 if u.Scheme != Scheme { 41 return nil, nil 42 } 43 44 opts := &opts{} 45 if err := extractor.Options(options).Apply(opts); err != nil { 46 return nil, err 47 } 48 49 path := strings.TrimPrefix(u.Opaque, "//") 50 path, err := filepath.Abs(path) 51 if err != nil { 52 return nil, err 53 } 54 55 d, err := os.Open(path) 56 if err != nil { 57 return nil, err 58 } 59 defer d.Close() 60 61 // get file info and check if is a directory 62 stat, err := d.Stat() 63 if err != nil { 64 return nil, err 65 } 66 if !stat.IsDir() { 67 return nil, fmt.Errorf("read %s: is not a directory", path) 68 } 69 70 if opts.initIgnoreFile { 71 if err := InitIgnoreFile(path); err != nil { 72 if !opts.skipIgnoreFileErr { 73 return nil, err 74 } 75 } 76 } 77 78 files, err := Walk(path) 79 if err != nil { 80 return nil, err 81 } 82 83 manifest := bundle.NewManifest(files...) 84 digest, err := manifest.Digest() 85 if err != nil { 86 return nil, err 87 } 88 89 // Metadata container 90 m := api.Metadata{ 91 ManifestKey: manifest, 92 PathKey: path, 93 } 94 95 return []*api.Artifact{{ 96 Kind: Scheme, 97 Hash: digest.Encoded(), 98 Name: stat.Name(), 99 Metadata: m, 100 }}, nil 101 } 102 103 // WithIgnoreFileInit returns a functional option to instruct the dir's extractor to create the defualt ignore file 104 // when not yet present into the targeted directory. 105 func WithIgnoreFileInit() extractor.Option { 106 return func(o interface{}) error { 107 if o, ok := o.(*opts); ok { 108 o.initIgnoreFile = true 109 } 110 return nil 111 } 112 } 113 114 // WithSkipIgnoreFileErr returns a functional option to instruct the dir's extractor to skip errors during 115 // ignore file initialization. 116 func WithSkipIgnoreFileErr() extractor.Option { 117 return func(o interface{}) error { 118 if o, ok := o.(*opts); ok { 119 o.skipIgnoreFileErr = true 120 } 121 return nil 122 } 123 }