github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/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/mitchellh/packer/common" 11 "github.com/mitchellh/packer/helper/config" 12 "github.com/mitchellh/packer/packer" 13 "github.com/mitchellh/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 ctx interpolate.Context 30 } 31 32 type Provisioner struct { 33 config Config 34 } 35 36 func (p *Provisioner) Prepare(raws ...interface{}) error { 37 err := config.Decode(&p.config, &config.DecodeOpts{ 38 Interpolate: true, 39 InterpolateContext: &p.config.ctx, 40 InterpolateFilter: &interpolate.RenderFilter{ 41 Exclude: []string{}, 42 }, 43 }, raws...) 44 if err != nil { 45 return err 46 } 47 48 if p.config.Direction == "" { 49 p.config.Direction = "upload" 50 } 51 52 var errs *packer.MultiError 53 54 if p.config.Direction != "download" && p.config.Direction != "upload" { 55 errs = packer.MultiErrorAppend(errs, 56 errors.New("Direction must be one of: download, upload.")) 57 } 58 if p.config.Source != "" { 59 p.config.Sources = append(p.config.Sources, p.config.Source) 60 } 61 62 if p.config.Direction == "upload" { 63 for _, src := range p.config.Sources { 64 if _, err := os.Stat(src); err != nil { 65 errs = packer.MultiErrorAppend(errs, 66 fmt.Errorf("Bad source '%s': %s", src, err)) 67 } 68 } 69 } 70 71 if len(p.config.Sources) < 1 { 72 errs = packer.MultiErrorAppend(errs, 73 errors.New("Source must be specified.")) 74 } 75 76 if p.config.Destination == "" { 77 errs = packer.MultiErrorAppend(errs, 78 errors.New("Destination must be specified.")) 79 } 80 81 if errs != nil && len(errs.Errors) > 0 { 82 return errs 83 } 84 85 return nil 86 } 87 88 func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { 89 if p.config.Direction == "download" { 90 return p.ProvisionDownload(ui, comm) 91 } else { 92 return p.ProvisionUpload(ui, comm) 93 } 94 } 95 96 func (p *Provisioner) ProvisionDownload(ui packer.Ui, comm packer.Communicator) error { 97 for _, src := range p.config.Sources { 98 ui.Say(fmt.Sprintf("Downloading %s => %s", src, p.config.Destination)) 99 // ensure destination dir exists. p.config.Destination may either be a file or a dir. 100 dir := p.config.Destination 101 // if it doesn't end with a /, set dir as the parent dir 102 if !strings.HasSuffix(p.config.Destination, "/") { 103 dir = filepath.Dir(dir) 104 } 105 if dir != "" { 106 err := os.MkdirAll(dir, os.FileMode(0755)) 107 if err != nil { 108 return err 109 } 110 } 111 // if the config.Destination was a dir, download the dir 112 if strings.HasSuffix(p.config.Destination, "/") { 113 return comm.DownloadDir(src, p.config.Destination, nil) 114 } 115 116 f, err := os.OpenFile(p.config.Destination, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) 117 if err != nil { 118 return err 119 } 120 defer f.Close() 121 122 err = comm.Download(src, f) 123 if err != nil { 124 ui.Error(fmt.Sprintf("Download failed: %s", err)) 125 return err 126 } 127 } 128 return nil 129 } 130 131 func (p *Provisioner) ProvisionUpload(ui packer.Ui, comm packer.Communicator) error { 132 for _, src := range p.config.Sources { 133 ui.Say(fmt.Sprintf("Uploading %s => %s", src, p.config.Destination)) 134 135 info, err := os.Stat(src) 136 if err != nil { 137 return err 138 } 139 140 // If we're uploading a directory, short circuit and do that 141 if info.IsDir() { 142 return comm.UploadDir(p.config.Destination, src, nil) 143 } 144 145 // We're uploading a file... 146 f, err := os.Open(src) 147 if err != nil { 148 return err 149 } 150 defer f.Close() 151 152 fi, err := f.Stat() 153 if err != nil { 154 return err 155 } 156 157 err = comm.Upload(p.config.Destination, f, &fi) 158 if err != nil { 159 ui.Error(fmt.Sprintf("Upload failed: %s", err)) 160 return err 161 } 162 } 163 return nil 164 } 165 166 func (p *Provisioner) Cancel() { 167 // Just hard quit. It isn't a big deal if what we're doing keeps 168 // running on the other side. 169 os.Exit(0) 170 }