Implement new parser for Parallels boot command
This commit is contained in:
parent
99d61920d0
commit
9b7704c714
|
@ -3,7 +3,6 @@ package common
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hashicorp/packer/helper/multistep"
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
|
@ -18,8 +17,6 @@ import (
|
||||||
//
|
//
|
||||||
// Produces:
|
// Produces:
|
||||||
type StepRun struct {
|
type StepRun struct {
|
||||||
BootWait time.Duration
|
|
||||||
|
|
||||||
vmName string
|
vmName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,22 +37,6 @@ func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.Ste
|
||||||
|
|
||||||
s.vmName = vmName
|
s.vmName = vmName
|
||||||
|
|
||||||
if int64(s.BootWait) > 0 {
|
|
||||||
ui.Say(fmt.Sprintf("Waiting %s for boot...", s.BootWait))
|
|
||||||
wait := time.After(s.BootWait)
|
|
||||||
WAITLOOP:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-wait:
|
|
||||||
break WAITLOOP
|
|
||||||
case <-time.After(1 * time.Second):
|
|
||||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
packer_common "github.com/hashicorp/packer/common"
|
packer_common "github.com/hashicorp/packer/common"
|
||||||
|
"github.com/hashicorp/packer/common/boot_command"
|
||||||
"github.com/hashicorp/packer/helper/multistep"
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"github.com/hashicorp/packer/template/interpolate"
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
|
@ -23,29 +21,32 @@ type bootCommandTemplateData struct {
|
||||||
|
|
||||||
// StepTypeBootCommand is a step that "types" the boot command into the VM via
|
// StepTypeBootCommand is a step that "types" the boot command into the VM via
|
||||||
// the prltype script, built on the Parallels Virtualization SDK - Python API.
|
// the prltype script, built on the Parallels Virtualization SDK - Python API.
|
||||||
//
|
|
||||||
// Uses:
|
|
||||||
// driver Driver
|
|
||||||
// http_port int
|
|
||||||
// ui packer.Ui
|
|
||||||
// vmName string
|
|
||||||
//
|
|
||||||
// Produces:
|
|
||||||
// <nothing>
|
|
||||||
type StepTypeBootCommand struct {
|
type StepTypeBootCommand struct {
|
||||||
BootCommand []string
|
BootCommand []string
|
||||||
|
BootWait time.Duration
|
||||||
HostInterfaces []string
|
HostInterfaces []string
|
||||||
VMName string
|
VMName string
|
||||||
Ctx interpolate.Context
|
Ctx interpolate.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run types the boot command by sending key scancodes into the VM.
|
// Run types the boot command by sending key scancodes into the VM.
|
||||||
func (s *StepTypeBootCommand) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
debug := state.Get("debug").(bool)
|
debug := state.Get("debug").(bool)
|
||||||
httpPort := state.Get("http_port").(uint)
|
httpPort := state.Get("http_port").(uint)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
driver := state.Get("driver").(Driver)
|
driver := state.Get("driver").(Driver)
|
||||||
|
|
||||||
|
// Wait the for the vm to boot.
|
||||||
|
if int64(s.BootWait) > 0 {
|
||||||
|
ui.Say(fmt.Sprintf("Waiting %s for boot...", s.BootWait.String()))
|
||||||
|
select {
|
||||||
|
case <-time.After(s.BootWait):
|
||||||
|
break
|
||||||
|
case <-ctx.Done():
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var pauseFn multistep.DebugPauseFn
|
var pauseFn multistep.DebugPauseFn
|
||||||
if debug {
|
if debug {
|
||||||
pauseFn = state.Get("pauseFn").(multistep.DebugPauseFn)
|
pauseFn = state.Get("pauseFn").(multistep.DebugPauseFn)
|
||||||
|
@ -76,6 +77,12 @@ func (s *StepTypeBootCommand) Run(_ context.Context, state multistep.StateBag) m
|
||||||
s.VMName,
|
s.VMName,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendCodes := func(codes []string) error {
|
||||||
|
log.Printf("Sending scancodes: %#v", codes)
|
||||||
|
return driver.SendKeyScanCodes(s.VMName, codes...)
|
||||||
|
}
|
||||||
|
d := bootcommand.NewPCATDriver(sendCodes)
|
||||||
|
|
||||||
ui.Say("Typing the boot command...")
|
ui.Say("Typing the boot command...")
|
||||||
for i, command := range s.BootCommand {
|
for i, command := range s.BootCommand {
|
||||||
command, err := interpolate.Render(command, &s.Ctx)
|
command, err := interpolate.Render(command, &s.Ctx)
|
||||||
|
@ -86,63 +93,24 @@ func (s *StepTypeBootCommand) Run(_ context.Context, state multistep.StateBag) m
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
codes := []string{}
|
seq, err := bootcommand.GenerateExpressionSequence(command)
|
||||||
for _, code := range scancodes(command) {
|
if err != nil {
|
||||||
if code == "wait" {
|
err := fmt.Errorf("Error generating boot command: %s", err)
|
||||||
if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil {
|
state.Put("error", err)
|
||||||
err = fmt.Errorf("Error sending boot command: %s", err)
|
ui.Error(err.Error())
|
||||||
state.Put("error", err)
|
return multistep.ActionHalt
|
||||||
ui.Error(err.Error())
|
}
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
codes = []string{}
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if code == "wait5" {
|
if err := seq.Do(ctx, d); err != nil {
|
||||||
if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil {
|
err := fmt.Errorf("Error running boot command: %s", err)
|
||||||
err = fmt.Errorf("Error sending boot command: %s", err)
|
state.Put("error", err)
|
||||||
state.Put("error", err)
|
ui.Error(err.Error())
|
||||||
ui.Error(err.Error())
|
return multistep.ActionHalt
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
codes = []string{}
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if code == "wait10" {
|
|
||||||
if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil {
|
|
||||||
err = fmt.Errorf("Error sending boot command: %s", err)
|
|
||||||
state.Put("error", err)
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
codes = []string{}
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since typing is sometimes so slow, we check for an interrupt
|
|
||||||
// in between each character.
|
|
||||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
codes = append(codes, code)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if pauseFn != nil {
|
if pauseFn != nil {
|
||||||
pauseFn(multistep.DebugLocationAfterRun, fmt.Sprintf("boot_command[%d]: %s", i, command), state)
|
pauseFn(multistep.DebugLocationAfterRun, fmt.Sprintf("boot_command[%d]: %s", i, command), state)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Sending scancodes: %#v", codes)
|
|
||||||
if err := driver.SendKeyScanCodes(s.VMName, codes...); err != nil {
|
|
||||||
err = fmt.Errorf("Error sending boot command: %s", err)
|
|
||||||
state.Put("error", err)
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
|
@ -150,202 +118,3 @@ func (s *StepTypeBootCommand) Run(_ context.Context, state multistep.StateBag) m
|
||||||
|
|
||||||
// Cleanup does nothing.
|
// Cleanup does nothing.
|
||||||
func (*StepTypeBootCommand) Cleanup(multistep.StateBag) {}
|
func (*StepTypeBootCommand) Cleanup(multistep.StateBag) {}
|
||||||
|
|
||||||
func scancodes(message string) []string {
|
|
||||||
// Scancodes reference: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
|
|
||||||
//
|
|
||||||
// Scancodes represent raw keyboard output and are fed to the VM by the
|
|
||||||
// Parallels Virtualization SDK - C API, PrlDevKeyboard_SendKeyEvent
|
|
||||||
//
|
|
||||||
// Scancodes are recorded here in pairs. The first entry represents
|
|
||||||
// the key press and the second entry represents the key release and is
|
|
||||||
// derived from the first by the addition of 0x80.
|
|
||||||
special := make(map[string][]string)
|
|
||||||
special["<bs>"] = []string{"0e", "8e"}
|
|
||||||
special["<del>"] = []string{"53", "d3"}
|
|
||||||
special["<enter>"] = []string{"1c", "9c"}
|
|
||||||
special["<esc>"] = []string{"01", "81"}
|
|
||||||
special["<f1>"] = []string{"3b", "bb"}
|
|
||||||
special["<f2>"] = []string{"3c", "bc"}
|
|
||||||
special["<f3>"] = []string{"3d", "bd"}
|
|
||||||
special["<f4>"] = []string{"3e", "be"}
|
|
||||||
special["<f5>"] = []string{"3f", "bf"}
|
|
||||||
special["<f6>"] = []string{"40", "c0"}
|
|
||||||
special["<f7>"] = []string{"41", "c1"}
|
|
||||||
special["<f8>"] = []string{"42", "c2"}
|
|
||||||
special["<f9>"] = []string{"43", "c3"}
|
|
||||||
special["<f10>"] = []string{"44", "c4"}
|
|
||||||
special["<return>"] = []string{"1c", "9c"}
|
|
||||||
special["<tab>"] = []string{"0f", "8f"}
|
|
||||||
|
|
||||||
special["<up>"] = []string{"48", "c8"}
|
|
||||||
special["<down>"] = []string{"50", "d0"}
|
|
||||||
special["<left>"] = []string{"4b", "cb"}
|
|
||||||
special["<right>"] = []string{"4d", "cd"}
|
|
||||||
special["<spacebar>"] = []string{"39", "b9"}
|
|
||||||
special["<insert>"] = []string{"52", "d2"}
|
|
||||||
special["<home>"] = []string{"47", "c7"}
|
|
||||||
special["<end>"] = []string{"4f", "cf"}
|
|
||||||
special["<pageUp>"] = []string{"49", "c9"}
|
|
||||||
special["<pageDown>"] = []string{"51", "d1"}
|
|
||||||
|
|
||||||
special["<leftAlt>"] = []string{"38", "b8"}
|
|
||||||
special["<leftCtrl>"] = []string{"1d", "9d"}
|
|
||||||
special["<leftShift>"] = []string{"2a", "aa"}
|
|
||||||
special["<rightAlt>"] = []string{"e038", "e0b8"}
|
|
||||||
special["<rightCtrl>"] = []string{"e01d", "e09d"}
|
|
||||||
special["<rightShift>"] = []string{"36", "b6"}
|
|
||||||
|
|
||||||
shiftedChars := "!@#$%^&*()_+{}:\"~|<>?"
|
|
||||||
|
|
||||||
scancodeIndex := make(map[string]uint)
|
|
||||||
scancodeIndex["1234567890-="] = 0x02
|
|
||||||
scancodeIndex["!@#$%^&*()_+"] = 0x02
|
|
||||||
scancodeIndex["qwertyuiop[]"] = 0x10
|
|
||||||
scancodeIndex["QWERTYUIOP{}"] = 0x10
|
|
||||||
scancodeIndex["asdfghjkl;'`"] = 0x1e
|
|
||||||
scancodeIndex[`ASDFGHJKL:"~`] = 0x1e
|
|
||||||
scancodeIndex["\\zxcvbnm,./"] = 0x2b
|
|
||||||
scancodeIndex["|ZXCVBNM<>?"] = 0x2b
|
|
||||||
scancodeIndex[" "] = 0x39
|
|
||||||
|
|
||||||
scancodeMap := make(map[rune]uint)
|
|
||||||
for chars, start := range scancodeIndex {
|
|
||||||
var i uint
|
|
||||||
for len(chars) > 0 {
|
|
||||||
r, size := utf8.DecodeRuneInString(chars)
|
|
||||||
chars = chars[size:]
|
|
||||||
scancodeMap[r] = start + i
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make([]string, 0, len(message)*2)
|
|
||||||
for len(message) > 0 {
|
|
||||||
var scancode []string
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<leftAltOn>") {
|
|
||||||
scancode = []string{"38"}
|
|
||||||
message = message[len("<leftAltOn>"):]
|
|
||||||
log.Printf("Special code '<leftAltOn>' found, replacing with: 38")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<leftCtrlOn>") {
|
|
||||||
scancode = []string{"1d"}
|
|
||||||
message = message[len("<leftCtrlOn>"):]
|
|
||||||
log.Printf("Special code '<leftCtrlOn>' found, replacing with: 1d")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<leftShiftOn>") {
|
|
||||||
scancode = []string{"2a"}
|
|
||||||
message = message[len("<leftShiftOn>"):]
|
|
||||||
log.Printf("Special code '<leftShiftOn>' found, replacing with: 2a")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<leftAltOff>") {
|
|
||||||
scancode = []string{"b8"}
|
|
||||||
message = message[len("<leftAltOff>"):]
|
|
||||||
log.Printf("Special code '<leftAltOff>' found, replacing with: b8")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<leftCtrlOff>") {
|
|
||||||
scancode = []string{"9d"}
|
|
||||||
message = message[len("<leftCtrlOff>"):]
|
|
||||||
log.Printf("Special code '<leftCtrlOff>' found, replacing with: 9d")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<leftShiftOff>") {
|
|
||||||
scancode = []string{"aa"}
|
|
||||||
message = message[len("<leftShiftOff>"):]
|
|
||||||
log.Printf("Special code '<leftShiftOff>' found, replacing with: aa")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<rightAltOn>") {
|
|
||||||
scancode = []string{"e038"}
|
|
||||||
message = message[len("<rightAltOn>"):]
|
|
||||||
log.Printf("Special code '<rightAltOn>' found, replacing with: e038")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<rightCtrlOn>") {
|
|
||||||
scancode = []string{"e01d"}
|
|
||||||
message = message[len("<rightCtrlOn>"):]
|
|
||||||
log.Printf("Special code '<rightCtrlOn>' found, replacing with: e01d")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<rightShiftOn>") {
|
|
||||||
scancode = []string{"36"}
|
|
||||||
message = message[len("<rightShiftOn>"):]
|
|
||||||
log.Printf("Special code '<rightShiftOn>' found, replacing with: 36")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<rightAltOff>") {
|
|
||||||
scancode = []string{"e0b8"}
|
|
||||||
message = message[len("<rightAltOff>"):]
|
|
||||||
log.Printf("Special code '<rightAltOff>' found, replacing with: e0b8")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<rightCtrlOff>") {
|
|
||||||
scancode = []string{"e09d"}
|
|
||||||
message = message[len("<rightCtrlOff>"):]
|
|
||||||
log.Printf("Special code '<rightCtrlOff>' found, replacing with: e09d")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<rightShiftOff>") {
|
|
||||||
scancode = []string{"b6"}
|
|
||||||
message = message[len("<rightShiftOff>"):]
|
|
||||||
log.Printf("Special code '<rightShiftOff>' found, replacing with: b6")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<wait>") {
|
|
||||||
log.Printf("Special code <wait> found, will sleep 1 second at this point.")
|
|
||||||
scancode = []string{"wait"}
|
|
||||||
message = message[len("<wait>"):]
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<wait5>") {
|
|
||||||
log.Printf("Special code <wait5> found, will sleep 5 seconds at this point.")
|
|
||||||
scancode = []string{"wait5"}
|
|
||||||
message = message[len("<wait5>"):]
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(message, "<wait10>") {
|
|
||||||
log.Printf("Special code <wait10> found, will sleep 10 seconds at this point.")
|
|
||||||
scancode = []string{"wait10"}
|
|
||||||
message = message[len("<wait10>"):]
|
|
||||||
}
|
|
||||||
|
|
||||||
if scancode == nil {
|
|
||||||
for specialCode, specialValue := range special {
|
|
||||||
if strings.HasPrefix(message, specialCode) {
|
|
||||||
log.Printf("Special code '%s' found, replacing with: %s", specialCode, specialValue)
|
|
||||||
scancode = specialValue
|
|
||||||
message = message[len(specialCode):]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if scancode == nil {
|
|
||||||
r, size := utf8.DecodeRuneInString(message)
|
|
||||||
message = message[size:]
|
|
||||||
scancodeInt := scancodeMap[r]
|
|
||||||
keyShift := unicode.IsUpper(r) || strings.ContainsRune(shiftedChars, r)
|
|
||||||
|
|
||||||
scancode = make([]string, 0, 4)
|
|
||||||
if keyShift {
|
|
||||||
scancode = append(scancode, "2a")
|
|
||||||
}
|
|
||||||
|
|
||||||
scancode = append(scancode, fmt.Sprintf("%02x", scancodeInt))
|
|
||||||
scancode = append(scancode, fmt.Sprintf("%02x", scancodeInt+0x80))
|
|
||||||
|
|
||||||
if keyShift {
|
|
||||||
scancode = append(scancode, "aa")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = append(result, scancode...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
|
@ -185,10 +185,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
Commands: b.config.Prlctl,
|
Commands: b.config.Prlctl,
|
||||||
Ctx: b.config.ctx,
|
Ctx: b.config.ctx,
|
||||||
},
|
},
|
||||||
¶llelscommon.StepRun{
|
¶llelscommon.StepRun{},
|
||||||
BootWait: b.config.BootWait,
|
|
||||||
},
|
|
||||||
¶llelscommon.StepTypeBootCommand{
|
¶llelscommon.StepTypeBootCommand{
|
||||||
|
BootWait: b.config.BootWait,
|
||||||
BootCommand: b.config.BootCommand,
|
BootCommand: b.config.BootCommand,
|
||||||
HostInterfaces: b.config.HostInterfaces,
|
HostInterfaces: b.config.HostInterfaces,
|
||||||
VMName: b.config.VMName,
|
VMName: b.config.VMName,
|
||||||
|
|
|
@ -74,11 +74,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
Commands: b.config.Prlctl,
|
Commands: b.config.Prlctl,
|
||||||
Ctx: b.config.ctx,
|
Ctx: b.config.ctx,
|
||||||
},
|
},
|
||||||
¶llelscommon.StepRun{
|
¶llelscommon.StepRun{},
|
||||||
BootWait: b.config.BootWait,
|
|
||||||
},
|
|
||||||
¶llelscommon.StepTypeBootCommand{
|
¶llelscommon.StepTypeBootCommand{
|
||||||
BootCommand: b.config.BootCommand,
|
BootCommand: b.config.BootCommand,
|
||||||
|
BootWait: b.config.BootWait,
|
||||||
HostInterfaces: []string{},
|
HostInterfaces: []string{},
|
||||||
VMName: b.config.VMName,
|
VMName: b.config.VMName,
|
||||||
Ctx: b.config.ctx,
|
Ctx: b.config.ctx,
|
||||||
|
|
|
@ -20,16 +20,6 @@ type bootCommandTemplateData struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// This step "types" the boot command into the VM over VNC.
|
|
||||||
//
|
|
||||||
// Uses:
|
|
||||||
// driver Driver
|
|
||||||
// http_port int
|
|
||||||
// ui packer.Ui
|
|
||||||
// vmName string
|
|
||||||
//
|
|
||||||
// Produces:
|
|
||||||
// <nothing>
|
|
||||||
type StepTypeBootCommand struct {
|
type StepTypeBootCommand struct {
|
||||||
BootCommand []string
|
BootCommand []string
|
||||||
BootWait time.Duration
|
BootWait time.Duration
|
||||||
|
@ -72,10 +62,7 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
|
||||||
args := []string{"controlvm", vmName, "keyboardputscancode"}
|
args := []string{"controlvm", vmName, "keyboardputscancode"}
|
||||||
args = append(args, codes...)
|
args = append(args, codes...)
|
||||||
|
|
||||||
if err := driver.VBoxManage(args...); err != nil {
|
return driver.VBoxManage(args...)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
d := bootcommand.NewPCATDriver(sendCodes)
|
d := bootcommand.NewPCATDriver(sendCodes)
|
||||||
|
|
||||||
|
@ -97,10 +84,6 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
// This executes vboxmanage once for each character code. This seems
|
|
||||||
// fine for now, but changes the prior behavior. If this becomes
|
|
||||||
// a problem, we can always have the driver cache scancodes, and then
|
|
||||||
// add a `Flush` method which we can call after this.
|
|
||||||
if err := seq.Do(ctx, d); err != nil {
|
if err := seq.Do(ctx, d); err != nil {
|
||||||
err := fmt.Errorf("Error running boot command: %s", err)
|
err := fmt.Errorf("Error running boot command: %s", err)
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
|
@ -111,7 +94,6 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
|
||||||
if pauseFn != nil {
|
if pauseFn != nil {
|
||||||
pauseFn(multistep.DebugLocationAfterRun, fmt.Sprintf("boot_command[%d]: %s", i, command), state)
|
pauseFn(multistep.DebugLocationAfterRun, fmt.Sprintf("boot_command[%d]: %s", i, command), state)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
|
|
|
@ -8,18 +8,26 @@ import (
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// This driver executes the driver once for each character code. This seems
|
||||||
|
// fine for now, but changes the prior behavior. If this becomes a problem, we
|
||||||
|
// can always have the driver cache scancodes, and then add a `Flush` method
|
||||||
|
// which we can call after this.
|
||||||
|
|
||||||
|
// SendCodeFunc will be called to send codes to the VM
|
||||||
type SendCodeFunc func([]string) error
|
type SendCodeFunc func([]string) error
|
||||||
|
|
||||||
type pcATDriver struct {
|
type pcATDriver struct {
|
||||||
//driver Driver
|
|
||||||
//vmName string
|
|
||||||
send SendCodeFunc
|
send SendCodeFunc
|
||||||
specialMap map[string][]string
|
specialMap map[string][]string
|
||||||
scancodeMap map[rune]byte
|
scancodeMap map[rune]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPCATDriver(send SendCodeFunc) *pcATDriver {
|
func NewPCATDriver(send SendCodeFunc) *pcATDriver {
|
||||||
// sMap contains on/off tuples
|
// Scancodes reference: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
|
||||||
|
//
|
||||||
|
// Scancodes are recorded here in pairs. The first entry represents
|
||||||
|
// the key press and the second entry represents the key release and is
|
||||||
|
// derived from the first by the addition of 0x80.
|
||||||
sMap := make(map[string][]string)
|
sMap := make(map[string][]string)
|
||||||
sMap["bs"] = []string{"0e", "8e"}
|
sMap["bs"] = []string{"0e", "8e"}
|
||||||
sMap["del"] = []string{"e053", "e0d3"}
|
sMap["del"] = []string{"e053", "e0d3"}
|
||||||
|
|
Loading…
Reference in New Issue