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  }