diff --git a/action.go b/action.go index ea6ddd3a..0ccdbcd0 100644 --- a/action.go +++ b/action.go @@ -54,8 +54,12 @@ func (c *DebosContext) Origin(o string) (string, bool) { } type Action interface { + // Verify runs first /* FIXME verify should probably be prepare or somesuch */ Verify(context *DebosContext) error + // CheckEnv runs in the environment that Run will execute in, + // prior to Run commencing + CheckEnv(context *DebosContext) error PreMachine(context *DebosContext, m *fakemachine.Machine, args *[]string) error PreNoMachine(context *DebosContext) error Run(context *DebosContext) error @@ -75,6 +79,7 @@ type BaseAction struct { } func (b *BaseAction) Verify(context *DebosContext) error { return nil } +func (b *BaseAction) CheckEnv(context *DebosContext) error { return nil } func (b *BaseAction) PreMachine(context *DebosContext, m *fakemachine.Machine, args *[]string) error { diff --git a/actions/debootstrap_action.go b/actions/debootstrap_action.go index 728fa87d..45d1dd03 100644 --- a/actions/debootstrap_action.go +++ b/actions/debootstrap_action.go @@ -125,6 +125,15 @@ func (d *DebootstrapAction) Verify(context *debos.DebosContext) error { return nil } +func (d *DebootstrapAction) CheckEnv(context *debos.DebosContext) error { + // Check that debootstrap is available + cmd := debos.Command{} + if err := cmd.CheckExists("Debootstrap", "debootstrap", "--version"); err != nil { + return err + } + return nil +} + func (d *DebootstrapAction) PreMachine(context *debos.DebosContext, m *fakemachine.Machine, args *[]string) error { mounts := d.listOptionFiles(context) diff --git a/actions/filesystem_deploy_action.go b/actions/filesystem_deploy_action.go index 57215599..d40c62d4 100644 --- a/actions/filesystem_deploy_action.go +++ b/actions/filesystem_deploy_action.go @@ -54,6 +54,14 @@ func NewFilesystemDeployAction() *FilesystemDeployAction { return fd } +func (fd *FilesystemDeployAction) CheckEnv(context *debos.DebosContext) error { + cmd := debos.Command{} + if err := cmd.CheckExists("Cp", "cp", "--help"); err != nil { + return err + } + return nil +} + func (fd *FilesystemDeployAction) setupFSTab(context *debos.DebosContext) error { if context.ImageFSTab.Len() == 0 { return errors.New("Fstab not generated, missing image-partition action?") diff --git a/actions/image_partition_action.go b/actions/image_partition_action.go index ea3d6219..f90c4114 100644 --- a/actions/image_partition_action.go +++ b/actions/image_partition_action.go @@ -332,10 +332,7 @@ func (i ImagePartitionAction) PreMachine(context *debos.DebosContext, m *fakemac return nil } -func (i ImagePartitionAction) formatPartition(p *Partition, context debos.DebosContext) error { - label := fmt.Sprintf("Formatting partition %d", p.number) - path := i.getPartitionDevice(p.number, context) - +func (i ImagePartitionAction) getPartitionCommand(p *Partition) []string { cmdline := []string{} switch p.FS { case "vfat": @@ -385,6 +382,14 @@ func (i ImagePartitionAction) formatPartition(p *Partition, context debos.DebosC } } } + return cmdline +} + +func (i ImagePartitionAction) formatPartition(p *Partition, context debos.DebosContext) error { + label := fmt.Sprintf("Formatting partition %d", p.number) + path := i.getPartitionDevice(p.number, context) + + cmdline := i.getPartitionCommand(p) if len(cmdline) != 0 { cmdline = append(cmdline, path) @@ -655,6 +660,27 @@ func (i ImagePartitionAction) PostMachineCleanup(context *debos.DebosContext) er return nil } +func (i *ImagePartitionAction) CheckEnv(context *debos.DebosContext) error { + commands := []string{ + "blkid", "parted", "sfdisk", "udevadm" } + + cmd := debos.Command{} + for _, c := range commands { + if err := cmd.CheckExists(strings.Title(c), c, "--help"); err != nil { + return err + } + } + for idx, _ := range i.Partitions { + p := &i.Partitions[idx] + cmdline := i.getPartitionCommand(p) + cmd := debos.Command{} + if err := cmd.CheckExists(strings.Title(cmdline[0]), cmdline[0], "-V"); err != nil { + return err + } + } + return nil +} + func (i *ImagePartitionAction) Verify(context *debos.DebosContext) error { if len(i.GptGap) > 0 { log.Println("WARNING: special version of parted is needed for 'gpt_gap' option") diff --git a/actions/ostree_deploy_action.go b/actions/ostree_deploy_action.go index 1ba9b135..95428c79 100644 --- a/actions/ostree_deploy_action.go +++ b/actions/ostree_deploy_action.go @@ -81,6 +81,14 @@ func NewOstreeDeployAction() *OstreeDeployAction { return ot } +func (ot *OstreeDeployAction) CheckEnv(context *debos.DebosContext) error { + cmd := debos.Command{} + if err := cmd.CheckExists("Cp", "cp", "--help"); err != nil { + return err + } + return nil +} + func (ot *OstreeDeployAction) setupFSTab(deployment *ostree.Deployment, context *debos.DebosContext) error { deploymentDir := fmt.Sprintf("ostree/deploy/%s/deploy/%s.%d", deployment.Osname(), deployment.Csum(), deployment.Deployserial()) diff --git a/actions/pack_action.go b/actions/pack_action.go index 8d349796..c8178390 100644 --- a/actions/pack_action.go +++ b/actions/pack_action.go @@ -67,6 +67,14 @@ func (pf *PackAction) Verify(context *debos.DebosContext) error { pf.Compression, strings.Join(possibleTypes, ", ")) } +func (pf *PackAction) CheckEnv(context *debos.DebosContext) error { + cmd := debos.Command{} + if err := cmd.CheckExists("Tar", "tar", "--help"); err != nil { + return err + } + return nil +} + func (pf *PackAction) Run(context *debos.DebosContext) error { usePigz := false if pf.Compression == "gz" { diff --git a/actions/recipe_action.go b/actions/recipe_action.go index beacae82..1c7ef393 100644 --- a/actions/recipe_action.go +++ b/actions/recipe_action.go @@ -90,6 +90,15 @@ func (recipe *RecipeAction) Verify(context *debos.DebosContext) error { return nil } +func (recipe *RecipeAction) CheckEnv(context *debos.DebosContext) error { + for _, a := range recipe.Actions.Actions { + if err := a.CheckEnv(&recipe.context); err != nil { + return err + } + } + return nil +} + func (recipe *RecipeAction) PreMachine(context *debos.DebosContext, m *fakemachine.Machine, args *[]string) error { // TODO: check args? diff --git a/cmd/debos/debos.go b/cmd/debos/debos.go index d7e1b5aa..353e5e4a 100644 --- a/cmd/debos/debos.go +++ b/cmd/debos/debos.go @@ -244,7 +244,34 @@ func main() { return } + if !runInFakeMachine && !fakemachine.InMachine() { + // We will run on the host + for _, a := range r.Actions { + // Stack PostMachineCleanup methods + defer a.PostMachineCleanup(&context) + + err = a.PreNoMachine(&context) + if exitcode = checkError(&context, err, a, "PreNoMachine"); exitcode != 0 { + return + } + } + } + + if !runInFakeMachine { + // Either we're on the host and intend to run on it, + // or we're in the fake machine and intend to run on + // it. In the former case, PreNoMachine has just run; + // in the latter PreMachine has already run. + for _, a := range r.Actions { + err = a.CheckEnv(&context) + if exitcode = checkError(&context, err, a, "CheckEnv"); exitcode != 0 { + return + } + } + } + if runInFakeMachine { + // We're on the host and intend to run on the fakemachine var args []string if options.Memory == "" { @@ -338,17 +365,8 @@ func main() { return } - if !fakemachine.InMachine() { - for _, a := range r.Actions { - // Stack PostMachineCleanup methods - defer a.PostMachineCleanup(&context) - - err = a.PreNoMachine(&context) - if exitcode = checkError(&context, err, a, "PreNoMachine"); exitcode != 0 { - return - } - } - } + // We're on the host and intend to run on the host, or we're + // in the fakemachine and intend to run on the fakemachine. // Create Rootdir if _, err = os.Stat(context.Rootdir); os.IsNotExist(err) { diff --git a/commands.go b/commands.go index c8430fb0..519ba1fb 100644 --- a/commands.go +++ b/commands.go @@ -32,12 +32,13 @@ type Command struct { type commandWrapper struct { label string + writeBeforeFlush bool buffer *bytes.Buffer } -func newCommandWrapper(label string) *commandWrapper { +func newCommandWrapper(label string, writeBeforeFlush bool) *commandWrapper { b := bytes.Buffer{} - return &commandWrapper{label, &b} + return &commandWrapper{label, writeBeforeFlush, &b} } func (w commandWrapper) out(atEOF bool) { @@ -60,7 +61,9 @@ func (w commandWrapper) out(atEOF bool) { func (w commandWrapper) Write(p []byte) (n int, err error) { n, err = w.buffer.Write(p) - w.out(false) + if w.writeBeforeFlush { + w.out(false) + } return } @@ -208,7 +211,7 @@ func (cmd *Command) restoreResolvConf(sum *[sha256.Size]byte) error { return nil } -func (cmd Command) Run(label string, cmdline ...string) error { +func (cmd Command) run(label string, w *commandWrapper, cmdline []string) error { q := newQemuHelper(cmd) q.Setup() defer q.Cleanup() @@ -241,14 +244,11 @@ func (cmd Command) Run(label string, cmdline ...string) error { } exe := exec.Command(options[0], options[1:]...) - w := newCommandWrapper(label) exe.Stdin = nil exe.Stdout = w exe.Stderr = w - defer w.flush() - if len(cmd.extraEnv) > 0 && cmd.ChrootMethod != CHROOT_METHOD_NSPAWN { exe.Env = append(os.Environ(), cmd.extraEnv...) } @@ -278,6 +278,21 @@ func (cmd Command) Run(label string, cmdline ...string) error { return nil } +func (cmd Command) Run(label string, cmdline ...string) error { + w := newCommandWrapper(label, true) + defer w.flush() + return cmd.run(label, w, cmdline) +} + +func (cmd Command) CheckExists(label string, cmdline ...string) error { + w := newCommandWrapper(label, false) + if err := cmd.run(label, w, cmdline); err != nil { + w.flush() + return fmt.Errorf("Unable to find %[1]s, %[2]v", label, err) + } + return nil +} + type qemuHelper struct { qemusrc string qemutarget string