github.com/askholme/packer@v0.7.2-0.20140924152349-70d9566a6852/post-processor/compress/post-processor.go (about)

     1  package compress
     2  
     3  import (
     4  	"archive/tar"
     5  	"compress/gzip"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  
    10  	"github.com/mitchellh/packer/common"
    11  	"github.com/mitchellh/packer/packer"
    12  )
    13  
    14  type Config struct {
    15  	common.PackerConfig `mapstructure:",squash"`
    16  
    17  	OutputPath string `mapstructure:"output"`
    18  
    19  	tpl *packer.ConfigTemplate
    20  }
    21  
    22  type PostProcessor struct {
    23  	config Config
    24  }
    25  
    26  func (self *PostProcessor) Configure(raws ...interface{}) error {
    27  	_, err := common.DecodeConfig(&self.config, raws...)
    28  	if err != nil {
    29  		return err
    30  	}
    31  
    32  	self.config.tpl, err = packer.NewConfigTemplate()
    33  	if err != nil {
    34  		return err
    35  	}
    36  	self.config.tpl.UserVars = self.config.PackerUserVars
    37  
    38  	templates := map[string]*string{
    39  		"output": &self.config.OutputPath,
    40  	}
    41  
    42  	errs := new(packer.MultiError)
    43  	for key, ptr := range templates {
    44  		if *ptr == "" {
    45  			errs = packer.MultiErrorAppend(
    46  				errs, fmt.Errorf("%s must be set", key))
    47  		}
    48  
    49  		*ptr, err = self.config.tpl.Process(*ptr, nil)
    50  		if err != nil {
    51  			errs = packer.MultiErrorAppend(
    52  				errs, fmt.Errorf("Error processing %s: %s", key, err))
    53  		}
    54  	}
    55  
    56  	if len(errs.Errors) > 0 {
    57  		return errs
    58  	}
    59  
    60  	return nil
    61  
    62  }
    63  
    64  func (self *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
    65  	ui.Say(fmt.Sprintf("Creating archive for '%s'", artifact.BuilderId()))
    66  
    67  	// Create the compressed archive file at the appropriate OutputPath.
    68  	fw, err := os.Create(self.config.OutputPath)
    69  	if err != nil {
    70  		return nil, false, fmt.Errorf(
    71  			"Failed creating file for compressed archive: %s", self.config.OutputPath)
    72  	}
    73  	defer fw.Close()
    74  
    75  	gw := gzip.NewWriter(fw)
    76  	defer gw.Close()
    77  
    78  	// Iterate through all of the artifact's files and put them into the
    79  	// compressed archive using the tar/gzip writers.
    80  	for _, path := range artifact.Files() {
    81  		fi, err := os.Stat(path)
    82  		if err != nil {
    83  			return nil, false, fmt.Errorf(
    84  				"Failed stating file: %s", path)
    85  		}
    86  
    87  		target, _ := os.Readlink(path)
    88  		header, err := tar.FileInfoHeader(fi, target)
    89  		if err != nil {
    90  			return nil, false, fmt.Errorf(
    91  				"Failed creating archive header: %s", path)
    92  		}
    93  
    94  		tw := tar.NewWriter(gw)
    95  		defer tw.Close()
    96  
    97  		// Write the header first to the archive. This takes partial data
    98  		// from the FileInfo that is grabbed by running the stat command.
    99  		if err := tw.WriteHeader(header); err != nil {
   100  			return nil, false, fmt.Errorf(
   101  				"Failed writing archive header: %s", path)
   102  		}
   103  
   104  		// Open the target file for archiving and compressing.
   105  		fr, err := os.Open(path)
   106  		if err != nil {
   107  			return nil, false, fmt.Errorf(
   108  				"Failed opening file '%s' to write compressed archive.", path)
   109  		}
   110  		defer fr.Close()
   111  
   112  		if _, err = io.Copy(tw, fr); err != nil {
   113  			return nil, false, fmt.Errorf(
   114  				"Failed copying file to archive: %s", path)
   115  		}
   116  	}
   117  
   118  	return NewArtifact(artifact.BuilderId(), self.config.OutputPath), false, nil
   119  }