mirror of
https://github.com/hashicorp/packer.git
synced 2026-10-01 12:13:59 -04:00
Let's cache the scancodes and flush them at the end. Also make sure to send only as many as the driver can send correctly. It's important here to chunk the scancodes correctly, so that we don't accidentally split them over successive calls to the driver
131 lines
2.6 KiB
Go
131 lines
2.6 KiB
Go
package bootcommand
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
/*
|
|
TODO:
|
|
* tests
|
|
* fix vbox tests
|
|
* comments
|
|
* lower-case specials
|
|
* check that `<del>` works on parallels. It's different now.
|
|
* take `Finalize` out of the Driver interface. let builders that need it
|
|
* use it. also rename to `Flush`.
|
|
*/
|
|
|
|
// KeysAction represents what we want to do with a key press.
|
|
// It can take 3 states. We either want to:
|
|
// * press the key once
|
|
// * press and hold
|
|
// * press and release
|
|
type KeyAction int
|
|
|
|
const (
|
|
KeyOn KeyAction = 1 << iota
|
|
KeyOff
|
|
KeyPress
|
|
)
|
|
|
|
func onOffToAction(t string) KeyAction {
|
|
if strings.EqualFold(t, "on") {
|
|
return KeyOn
|
|
} else if strings.EqualFold(t, "off") {
|
|
return KeyOff
|
|
}
|
|
panic(fmt.Sprintf("Unknown state '%s'. Expecting On or Off.", t))
|
|
}
|
|
|
|
func (k KeyAction) String() string {
|
|
switch k {
|
|
case KeyOn:
|
|
return "On"
|
|
case KeyOff:
|
|
return "Off"
|
|
case KeyPress:
|
|
return "Press"
|
|
}
|
|
panic(fmt.Sprintf("Unknwon KeyAction %d", k))
|
|
}
|
|
|
|
type expression interface {
|
|
Do(context.Context, BCDriver) error
|
|
}
|
|
|
|
type expressionSequence []expression
|
|
|
|
func (s expressionSequence) Do(ctx context.Context, b BCDriver) error {
|
|
for _, exp := range s {
|
|
if err := exp.Do(ctx, b); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return b.Finalize()
|
|
}
|
|
|
|
// GenerateExpressionSequence generates a sequence of expressions from the
|
|
// given command.
|
|
func GenerateExpressionSequence(command string) (expressionSequence, error) {
|
|
got, err := ParseReader("", strings.NewReader(command))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if got == nil {
|
|
return nil, fmt.Errorf("No expressions found.")
|
|
}
|
|
seq := expressionSequence{}
|
|
for _, exp := range got.([]interface{}) {
|
|
seq = append(seq, exp.(expression))
|
|
}
|
|
return seq, nil
|
|
}
|
|
|
|
type waitExpression struct {
|
|
d time.Duration
|
|
}
|
|
|
|
func (w *waitExpression) Do(ctx context.Context, _ BCDriver) error {
|
|
log.Printf("[INFO] Waiting %s", w.d)
|
|
select {
|
|
case <-time.After(w.d):
|
|
return nil
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
}
|
|
}
|
|
|
|
func (w *waitExpression) String() string {
|
|
return fmt.Sprintf("Wait<%s>", w.d)
|
|
}
|
|
|
|
type specialExpression struct {
|
|
s string
|
|
action KeyAction
|
|
}
|
|
|
|
func (s *specialExpression) Do(ctx context.Context, driver BCDriver) error {
|
|
return driver.SendSpecial(s.s, s.action)
|
|
}
|
|
|
|
func (s *specialExpression) String() string {
|
|
return fmt.Sprintf("Spec-%s(%s)", s.action, s.s)
|
|
}
|
|
|
|
type literal struct {
|
|
s rune
|
|
action KeyAction
|
|
}
|
|
|
|
func (l *literal) Do(ctx context.Context, driver BCDriver) error {
|
|
return driver.SendKey(l.s, l.action)
|
|
}
|
|
|
|
func (l *literal) String() string {
|
|
return fmt.Sprintf("LIT-%s(%s)", l.action, string(l.s))
|
|
}
|