github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/provisioner/file/provisioner.go (about) 1 package file 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/hashicorp/packer/common" 11 "github.com/hashicorp/packer/helper/config" 12 "github.com/hashicorp/packer/packer" 13 "github.com/hashicorp/packer/template/interpolate" 14 ) 15 16 type Config struct { 17 common.PackerConfig `mapstructure:",squash"` 18 19 // The local path of the file to upload. 20 Source string 21 Sources []string 22 23 // The remote path where the local file will be uploaded to. 24 Destination string 25 26 // Direction 27 Direction string 28 29 // False if the sources have to exist. 30 Generated bool 31 32 ctx interpolate.Context 33 } 34 35 type Provisioner struct { 36 config Config 37 } 38 39 func (p *Provisioner) Prepare(raws ...interface{}) error { 40 err := config.Decode(&p.config, &config.DecodeOpts{ 41 Interpolate: true, 42 InterpolateContext: &p.config.ctx, 43 InterpolateFilter: &interpolate.RenderFilter{ 44 Exclude: []string{}, 45 }, 46 }, raws...) 47 if err != nil { 48 return err 49 } 50 51 if p.config.Direction == "" { 52 p.config.Direction = "upload" 53 } 54 55 var errs *packer.MultiError 56 57 if p.config.Direction != "download" && p.config.Direction != "upload" { 58 errs = packer.MultiErrorAppend(errs, 59 errors.New("Direction must be one of: download, upload.")) 60 } 61 if p.config.Source != "" { 62 p.config.Sources = append(p.config.Sources, p.config.Source) 63 } 64 65 if p.config.Direction == "upload" { 66 for _, src := range p.config.Sources { 67 if _, err := os.Stat(src); p.config.Generated == false && err != nil { 68 errs = packer.MultiErrorAppend(errs, 69 fmt.Errorf("Bad source '%s': %s", src, err)) 70 } 71 } 72 } 73 74 if len(p.config.Sources) < 1 { 75 errs = packer.MultiErrorAppend(errs, 76 errors.New("Source must be specified.")) 77 } 78 79 if p.config.Destination == "" { 80 errs = packer.MultiErrorAppend(errs, 81 errors.New("Destination must be specified.")) 82 } 83 84 if errs != nil && len(errs.Errors) > 0 { 85 return errs 86 } 87 88 return nil 89 } 90 91 func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { 92 if p.config.Direction == "download" { 93 return p.ProvisionDownload(ui, comm) 94 } else { 95 return p.ProvisionUpload(ui, comm) 96 } 97 } 98 99 func (p *Provisioner) ProvisionDownload(ui packer.Ui, comm packer.Communicator) error { 100 for _, src := range p.config.Sources { 101 dst := p.config.Destination 102 ui.Say(fmt.Sprintf("Downloading %s => %s", src, dst)) 103 // ensure destination dir exists. p.config.Destination may either be a file or a dir. 104 dir := dst 105 // if it doesn't end with a /, set dir as the parent dir 106 if !strings.HasSuffix(dst, "/") { 107 dir = filepath.Dir(dir) 108 } else if !strings.HasSuffix(src, "/") && !strings.HasSuffix(src, "*") { 109 dst = filepath.Join(dst, filepath.Base(src)) 110 } 111 if dir != "" { 112 err := os.MkdirAll(dir, os.FileMode(0755)) 113 if err != nil { 114 return err 115 } 116 } 117 // if the src was a dir, download the dir 118 if strings.HasSuffix(src, "/") || strings.ContainsAny(src, "*?[") { 119 return comm.DownloadDir(src, dst, nil) 120 } 121 122 f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) 123 if err != nil { 124 return err 125 } 126 defer f.Close() 127 128 err = comm.Download(src, f) 129 if err != nil { 130 ui.Error(fmt.Sprintf("Download failed: %s", err)) 131 return err 132 } 133 } 134 return nil 135 } 136 137 func (p *Provisioner) ProvisionUpload(ui packer.Ui, comm packer.Communicator) error { 138 for _, src := range p.config.Sources { 139 dst := p.config.Destination 140 141 ui.Say(fmt.Sprintf("Uploading %s => %s", src, dst)) 142 143 info, err := os.Stat(src) 144 if err != nil { 145 return err 146 } 147 148 // If we're uploading a directory, short circuit and do that 149 if info.IsDir() { 150 return comm.UploadDir(p.config.Destination, src, nil) 151 } 152 153 // We're uploading a file... 154 f, err := os.Open(src) 155 if err != nil { 156 return err 157 } 158 defer f.Close() 159 160 fi, err := f.Stat() 161 if err != nil { 162 return err 163 } 164 165 if strings.HasSuffix(dst, "/") { 166 dst = filepath.Join(dst, filepath.Base(src)) 167 } 168 169 err = comm.Upload(dst, f, &fi) 170 if err != nil { 171 ui.Error(fmt.Sprintf("Upload failed: %s", err)) 172 return err 173 } 174 } 175 return nil 176 } 177 178 func (p *Provisioner) Cancel() { 179 // Just hard quit. It isn't a big deal if what we're doing keeps 180 // running on the other side. 181 os.Exit(0) 182 }