Merge pull request #173 from jasonberanek/force-build
packer, builder/*: Add support for -force flag on builds [GH-119]
This commit is contained in:
commit
2e492fd747
|
@ -54,6 +54,7 @@ type config struct {
|
|||
|
||||
PackerBuildName string `mapstructure:"packer_build_name"`
|
||||
PackerDebug bool `mapstructure:"packer_debug"`
|
||||
PackerForce bool `mapstructure:"packer_force"`
|
||||
|
||||
RawBootWait string `mapstructure:"boot_wait"`
|
||||
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||
|
@ -219,8 +220,13 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
|||
}
|
||||
|
||||
if _, err := os.Stat(b.config.OutputDir); err == nil {
|
||||
if b.config.PackerForce {
|
||||
log.Printf("Build forced, removing existing output directory: %s", string(b.config.OutputDir))
|
||||
os.RemoveAll(b.config.OutputDir)
|
||||
} else {
|
||||
errs = append(errs, errors.New("Output directory already exists. It must not exist."))
|
||||
}
|
||||
}
|
||||
|
||||
b.config.BootWait, err = time.ParseDuration(b.config.RawBootWait)
|
||||
if err != nil {
|
||||
|
|
|
@ -55,6 +55,7 @@ type config struct {
|
|||
|
||||
PackerBuildName string `mapstructure:"packer_build_name"`
|
||||
PackerDebug bool `mapstructure:"packer_debug"`
|
||||
PackerForce bool `mapstructure:"packer_force"`
|
||||
|
||||
RawBootWait string `mapstructure:"boot_wait"`
|
||||
RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
|
||||
|
@ -175,8 +176,13 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
|||
}
|
||||
|
||||
if _, err := os.Stat(b.config.OutputDir); err == nil {
|
||||
if b.config.PackerForce {
|
||||
log.Printf("Build forced, removing existing output directory: %s", string(b.config.OutputDir))
|
||||
os.RemoveAll(b.config.OutputDir)
|
||||
} else {
|
||||
errs = append(errs, errors.New("Output directory already exists. It must not exist."))
|
||||
}
|
||||
}
|
||||
|
||||
if b.config.SSHUser == "" {
|
||||
errs = append(errs, errors.New("An ssh_username must be specified."))
|
||||
|
|
|
@ -21,12 +21,14 @@ func (Command) Help() string {
|
|||
|
||||
func (c Command) Run(env packer.Environment, args []string) int {
|
||||
var cfgDebug bool
|
||||
var cfgForce bool
|
||||
var cfgExcept []string
|
||||
var cfgOnly []string
|
||||
|
||||
cmdFlags := flag.NewFlagSet("build", flag.ContinueOnError)
|
||||
cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
|
||||
cmdFlags.BoolVar(&cfgDebug, "debug", false, "debug mode for builds")
|
||||
cmdFlags.BoolVar(&cfgForce, "force", false, "force a build if artifacts exist")
|
||||
cmdFlags.Var((*stringSliceValue)(&cfgExcept), "except", "build all builds except these")
|
||||
cmdFlags.Var((*stringSliceValue)(&cfgOnly), "only", "only build the given builds by name")
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
|
@ -141,11 +143,13 @@ func (c Command) Run(env packer.Environment, args []string) int {
|
|||
env.Ui().Say("")
|
||||
|
||||
log.Printf("Build debug mode: %v", cfgDebug)
|
||||
log.Printf("Force build: %v", cfgForce)
|
||||
|
||||
// Set the debug mode and prepare all the builds
|
||||
// Set the debug and force mode and prepare all the builds
|
||||
for _, b := range builds {
|
||||
log.Printf("Preparing build: %s", b.Name())
|
||||
b.SetDebug(cfgDebug)
|
||||
b.SetForce(cfgForce)
|
||||
err := b.Prepare()
|
||||
if err != nil {
|
||||
env.Ui().Error(err.Error())
|
||||
|
|
|
@ -9,6 +9,7 @@ Usage: packer build [options] TEMPLATE
|
|||
Options:
|
||||
|
||||
-debug Debug mode enabled for builds
|
||||
-force Force a build to continue if artifacts exist, deletes existing artifacts
|
||||
-except=foo,bar,baz Build all builds other than these
|
||||
-only=foo,bar,baz Only build the given builds by name
|
||||
`
|
||||
|
|
|
@ -14,6 +14,10 @@ const BuildNameConfigKey = "packer_build_name"
|
|||
// debugging is enabled.
|
||||
const DebugConfigKey = "packer_debug"
|
||||
|
||||
// This is the key in configurations that is set to "true" when Packer
|
||||
// force build is enabled.
|
||||
const ForceConfigKey = "packer_force"
|
||||
|
||||
// A Build represents a single job within Packer that is responsible for
|
||||
// building some machine image artifact. Builds are meant to be parallelized.
|
||||
type Build interface {
|
||||
|
@ -42,6 +46,12 @@ type Build interface {
|
|||
// When SetDebug is set to true, parallelism between builds is
|
||||
// strictly prohibited.
|
||||
SetDebug(bool)
|
||||
|
||||
// SetForce will enable/disable forcing a build when artifacts exist.
|
||||
//
|
||||
// When SetForce is set to true, existing artifacts from the build are
|
||||
// deleted prior to the build.
|
||||
SetForce(bool)
|
||||
}
|
||||
|
||||
// A build struct represents a single build job, the result of which should
|
||||
|
@ -58,6 +68,7 @@ type coreBuild struct {
|
|||
provisioners []coreBuildProvisioner
|
||||
|
||||
debug bool
|
||||
force bool
|
||||
l sync.Mutex
|
||||
prepareCalled bool
|
||||
}
|
||||
|
@ -98,6 +109,7 @@ func (b *coreBuild) Prepare() (err error) {
|
|||
packerConfig := map[string]interface{}{
|
||||
BuildNameConfigKey: b.name,
|
||||
DebugConfigKey: b.debug,
|
||||
ForceConfigKey: b.force,
|
||||
}
|
||||
|
||||
// Prepare the builder
|
||||
|
@ -265,6 +277,14 @@ func (b *coreBuild) SetDebug(val bool) {
|
|||
b.debug = val
|
||||
}
|
||||
|
||||
func (b *coreBuild) SetForce(val bool) {
|
||||
if b.prepareCalled {
|
||||
panic("prepare has already been called")
|
||||
}
|
||||
|
||||
b.force = val
|
||||
}
|
||||
|
||||
// Cancels the build if it is running.
|
||||
func (b *coreBuild) Cancel() {
|
||||
b.builder.Cancel()
|
||||
|
|
|
@ -42,6 +42,7 @@ func TestBuild_Prepare(t *testing.T) {
|
|||
packerConfig := map[string]interface{}{
|
||||
BuildNameConfigKey: "test",
|
||||
DebugConfigKey: false,
|
||||
ForceConfigKey: false,
|
||||
}
|
||||
|
||||
build := testBuild()
|
||||
|
@ -88,6 +89,7 @@ func TestBuild_Prepare_Debug(t *testing.T) {
|
|||
packerConfig := map[string]interface{}{
|
||||
BuildNameConfigKey: "test",
|
||||
DebugConfigKey: true,
|
||||
ForceConfigKey: false,
|
||||
}
|
||||
|
||||
build := testBuild()
|
||||
|
|
|
@ -69,6 +69,12 @@ func (b *build) SetDebug(val bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *build) SetForce(val bool) {
|
||||
if err := b.client.Call("Build.SetForce", val, new(interface{})); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *build) Cancel() {
|
||||
if err := b.client.Call("Build.Cancel", new(interface{}), new(interface{})); err != nil {
|
||||
panic(err)
|
||||
|
@ -111,6 +117,11 @@ func (b *BuildServer) SetDebug(val *bool, reply *interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *BuildServer) SetForce(val *bool, reply *interface{}) error {
|
||||
b.build.SetForce(*val)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BuildServer) Cancel(args *interface{}, reply *interface{}) error {
|
||||
b.build.Cancel()
|
||||
return nil
|
||||
|
|
|
@ -17,6 +17,7 @@ type testBuild struct {
|
|||
runCache packer.Cache
|
||||
runUi packer.Ui
|
||||
setDebugCalled bool
|
||||
setForceCalled bool
|
||||
cancelCalled bool
|
||||
|
||||
errRunResult bool
|
||||
|
@ -48,6 +49,10 @@ func (b *testBuild) SetDebug(bool) {
|
|||
b.setDebugCalled = true
|
||||
}
|
||||
|
||||
func (b *testBuild) SetForce(bool) {
|
||||
b.setForceCalled = true
|
||||
}
|
||||
|
||||
func (b *testBuild) Cancel() {
|
||||
b.cancelCalled = true
|
||||
}
|
||||
|
@ -104,6 +109,10 @@ func TestBuildRPC(t *testing.T) {
|
|||
bClient.SetDebug(true)
|
||||
assert.True(b.setDebugCalled, "should be called")
|
||||
|
||||
// Test SetForce
|
||||
bClient.SetForce(true)
|
||||
assert.True(b.setForceCalled, "should be called")
|
||||
|
||||
// Test Cancel
|
||||
bClient.Cancel()
|
||||
assert.True(b.cancelCalled, "cancel should be called")
|
||||
|
|
|
@ -17,6 +17,12 @@ artifacts that are created will be outputted at the end of the build.
|
|||
between each step, waiting for keyboard input before continuing. This will allow
|
||||
the user to inspect state and so on.
|
||||
|
||||
* `-force` - Forces a builder to run when artifacts from a previous build prevent
|
||||
a build from running. The exact behavior of a forced build is left to the builder.
|
||||
In general, a builder supporting the forced build will remove the artifacts from
|
||||
the previous build. This will allow the user to repeat a build without having to
|
||||
manually clean these artifacts beforehand.
|
||||
|
||||
* `-except=foo,bar,baz` - Builds all the builds except those with the given
|
||||
comma-separated names. Build names by default are the names of their builders,
|
||||
unless a specific `name` attribute is specified within the configuration.
|
||||
|
|
Loading…
Reference in New Issue