Changed file builder to support content or source file operation

This commit is contained in:
Chris Bednarski 2015-06-12 18:18:38 -07:00
parent f7d85eb49c
commit e60b22d48f
3 changed files with 63 additions and 12 deletions

View File

@ -6,7 +6,10 @@ any virutalization or network resources, it's very fast and useful for testing.
*/ */
import ( import (
"fmt"
"io"
"io/ioutil" "io/ioutil"
"os"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
@ -47,7 +50,35 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
artifact := new(FileArtifact) artifact := new(FileArtifact)
ioutil.WriteFile(b.config.Filename, []byte(b.config.Contents), 0600) if b.config.Source != "" {
source, err := os.Open(b.config.Source)
defer source.Close()
if err != nil {
return nil, err
}
target, err := os.OpenFile(b.config.Target, os.O_WRONLY, 0600)
defer target.Close()
if err != nil {
return nil, err
}
ui.Say(fmt.Sprintf("Copying %s to %s", source.Name(), target.Name()))
bytes, err := io.Copy(source, target)
if err != nil {
return nil, err
}
ui.Say(fmt.Sprintf("Copied %d bytes", bytes))
artifact.filename = target.Name()
} else {
// We're going to write Contents; if it's empty we'll just create an
// empty file.
err := ioutil.WriteFile(b.config.Target, []byte(b.config.Content), 0600)
if err != nil {
return nil, err
}
artifact.filename = b.config.Target
}
return artifact, nil return artifact, nil
} }

View File

@ -9,11 +9,15 @@ import (
"github.com/mitchellh/packer/template/interpolate" "github.com/mitchellh/packer/template/interpolate"
) )
var ErrTargetRequired = fmt.Errorf("target required")
var ErrContentSourceConflict = fmt.Errorf("Cannot specify source file AND content")
type Config struct { type Config struct {
common.PackerConfig `mapstructure:",squash"` common.PackerConfig `mapstructure:",squash"`
Filename string `mapstructure:"filename"` Source string `mapstructure:"source"`
Contents string `mapstructure:"contents"` Target string `mapstructure:"target"`
Content string `mapstructure:"content"`
} }
func NewConfig(raws ...interface{}) (*Config, []string, error) { func NewConfig(raws ...interface{}) (*Config, []string, error) {
@ -32,12 +36,16 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
var errs *packer.MultiError var errs *packer.MultiError
if c.Filename == "" { if c.Target == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("filename is required")) errs = packer.MultiErrorAppend(errs, ErrTargetRequired)
} }
if c.Contents == "" { if c.Content == "" && c.Source == "" {
warnings = append(warnings, "contents is empty") warnings = append(warnings, "Both source file and contents are blank; target will have no content")
}
if c.Content != "" && c.Source != "" {
errs = packer.MultiErrorAppend(errs, ErrContentSourceConflict)
} }
if errs != nil && len(errs.Errors) > 0 { if errs != nil && len(errs.Errors) > 0 {

View File

@ -2,13 +2,24 @@ package file
import ( import (
"fmt" "fmt"
"strings"
"testing" "testing"
) )
func testConfig() map[string]interface{} { func testConfig() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"filename": "test.txt", "source": "src.txt",
"contents": "Hello, world!", "target": "dst.txt",
"content": "Hello, world!",
}
}
func TestContentSourceConflict(t *testing.T) {
raw := testConfig()
_, _, errs := NewConfig(raw)
if !strings.Contains(errs.Error(), ErrContentSourceConflict.Error()) {
t.Errorf("Expected config error: %s", ErrContentSourceConflict.Error())
} }
} }
@ -18,18 +29,19 @@ func TestNoFilename(t *testing.T) {
delete(raw, "filename") delete(raw, "filename")
_, _, errs := NewConfig(raw) _, _, errs := NewConfig(raw)
if errs == nil { if errs == nil {
t.Error("Expected config to error without a filename") t.Errorf("Expected config error: %s", ErrTargetRequired.Error())
} }
} }
func TestNoContent(t *testing.T) { func TestNoContent(t *testing.T) {
raw := testConfig() raw := testConfig()
delete(raw, "contents") delete(raw, "content")
delete(raw, "source")
_, warns, _ := NewConfig(raw) _, warns, _ := NewConfig(raw)
fmt.Println(len(warns)) fmt.Println(len(warns))
fmt.Printf("%#v\n", warns) fmt.Printf("%#v\n", warns)
if len(warns) == 0 { if len(warns) == 0 {
t.Error("Expected config to warn without any content") t.Error("Expected config warning without any content")
} }
} }