Files
Packer-Cn/common/boot_command/boot_command_ast.go
T
Matthew Hooker 59376294ef Maximize scancode throughput.
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
2018-04-19 14:26:29 -07:00

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))
}