github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/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 dst := p.config.Destination 99 ui.Say(fmt.Sprintf("Downloading %s => %s", src, dst)) 100 // ensure destination dir exists. p.config.Destination may either be a file or a dir. 101 dir := dst 102 // if it doesn't end with a /, set dir as the parent dir 103 if !strings.HasSuffix(dst, "/") { 104 dir = filepath.Dir(dir) 105 } else if !strings.HasSuffix(src, "/") && !strings.HasSuffix(src, "*") { 106 dst = filepath.Join(dst, filepath.Base(src)) 107 } 108 if dir != "" { 109 err := os.MkdirAll(dir, os.FileMode(0755)) 110 if err != nil { 111 return err 112 } 113 } 114 // if the src was a dir, download the dir 115 if strings.HasSuffix(src, "/") || strings.IndexAny(src, "*?[") >= 0 { 116 return comm.DownloadDir(src, dst, nil) 117 } 118 119 f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) 120 if err != nil { 121 return err 122 } 123 defer f.Close() 124 125 err = comm.Download(src, f) 126 if err != nil { 127 ui.Error(fmt.Sprintf("Download failed: %s", err)) 128 return err 129 } 130 } 131 return nil 132 } 133 134 func (p *Provisioner) ProvisionUpload(ui packer.Ui, comm packer.Communicator) error { 135 for _, src := range p.config.Sources { 136 dst := p.config.Destination 137 138 ui.Say(fmt.Sprintf("Uploading %s => %s", src, dst)) 139 140 info, err := os.Stat(src) 141 if err != nil { 142 return err 143 } 144 145 // If we're uploading a directory, short circuit and do that 146 if info.IsDir() { 147 return comm.UploadDir(p.config.Destination, src, nil) 148 } 149 150 // We're uploading a file... 151 f, err := os.Open(src) 152 if err != nil { 153 return err 154 } 155 defer f.Close() 156 157 fi, err := f.Stat() 158 if err != nil { 159 return err 160 } 161 162 if strings.HasSuffix(dst, "/") { 163 dst = filepath.Join(dst, filepath.Base(src)) 164 } 165 166 err = comm.Upload(dst, f, &fi) 167 if err != nil { 168 ui.Error(fmt.Sprintf("Upload failed: %s", err)) 169 return err 170 } 171 } 172 return nil 173 } 174 175 func (p *Provisioner) Cancel() { 176 // Just hard quit. It isn't a big deal if what we're doing keeps 177 // running on the other side. 178 os.Exit(0) 179 }