@@ -11,16 +11,15 @@ import (
1111 "net"
1212 "strings"
1313 "time"
14- "unicode"
15- "unicode/utf8"
1614
15+ "github.com/hashicorp/packer-plugin-sdk/bootcommand"
1716 "github.com/hashicorp/packer-plugin-sdk/multistep"
1817 "github.com/hashicorp/packer-plugin-sdk/packer"
1918 "github.com/hashicorp/packer-plugin-sdk/template/interpolate"
2019 "github.com/mitchellh/go-vnc"
2120)
2221
23- const KeyLeftShift uint = 0xFFE1
22+ const KeyLeftShift uint32 = 0xFFE1
2423
2524type bootCommandTemplateData struct {
2625 Name string
@@ -149,9 +148,13 @@ func (step *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateB
149148 uint (httpPort ),
150149 }
151150
151+ d := bootcommand .NewVNCDriver (vncClient , time .Second / 10 )
152+
152153 ui .Say ("Typing boot commands over VNC..." )
153154 for _ , command := range config .BootCommand {
154-
155+ if len (command ) == 0 {
156+ continue
157+ }
155158 command , err := interpolate .Render (command , & step .Ctx )
156159 if err != nil {
157160 err := fmt .Errorf ("Error preparing boot command: %s" , err )
@@ -160,112 +163,24 @@ func (step *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateB
160163 return multistep .ActionHalt
161164 }
162165
163- // Check for interrupts
164- if _ , ok := state .GetOk (multistep .StateCancelled ); ok {
166+ seq , err := bootcommand .GenerateExpressionSequence (command )
167+ if err != nil {
168+ err := fmt .Errorf ("Error generating boot command: %s" , err )
169+ state .Put ("error" , err )
170+ ui .Error (err .Error ())
171+ return multistep .ActionHalt
172+ }
173+
174+ if err := seq .Do (ctx , d ); err != nil {
175+ err := fmt .Errorf ("Error running boot command: %s" , err )
176+ state .Put ("error" , err )
177+ ui .Error (err .Error ())
165178 return multistep .ActionHalt
166179 }
167180
168- vncSendString (vncClient , command )
169181 }
170182
171183 return multistep .ActionContinue
172184}
173185
174186func (step * StepTypeBootCommand ) Cleanup (multistep.StateBag ) {}
175-
176- // Taken from qemu's builder plugin - not an exported function.
177- func vncSendString (c * vnc.ClientConn , original string ) {
178- // Scancodes reference: https://github.com/qemu/qemu/blob/master/ui/vnc_keysym.h
179- special := make (map [string ]uint32 )
180- special ["<bs>" ] = 0xFF08
181- special ["<del>" ] = 0xFFFF
182- special ["<enter>" ] = 0xFF0D
183- special ["<esc>" ] = 0xFF1B
184- special ["<f1>" ] = 0xFFBE
185- special ["<f2>" ] = 0xFFBF
186- special ["<f3>" ] = 0xFFC0
187- special ["<f4>" ] = 0xFFC1
188- special ["<f5>" ] = 0xFFC2
189- special ["<f6>" ] = 0xFFC3
190- special ["<f7>" ] = 0xFFC4
191- special ["<f8>" ] = 0xFFC5
192- special ["<f9>" ] = 0xFFC6
193- special ["<f10>" ] = 0xFFC7
194- special ["<f11>" ] = 0xFFC8
195- special ["<f12>" ] = 0xFFC9
196- special ["<return>" ] = 0xFF0D
197- special ["<tab>" ] = 0xFF09
198- special ["<up>" ] = 0xFF52
199- special ["<down>" ] = 0xFF54
200- special ["<left>" ] = 0xFF51
201- special ["<right>" ] = 0xFF53
202- special ["<spacebar>" ] = 0x020
203- special ["<insert>" ] = 0xFF63
204- special ["<home>" ] = 0xFF50
205- special ["<end>" ] = 0xFF57
206- special ["<pageUp>" ] = 0xFF55
207- special ["<pageDown>" ] = 0xFF56
208-
209- shiftedChars := "~!@#$%^&*()_+{}|:\" <>?"
210-
211- // TODO(mitchellh): Ripe for optimizations of some point, perhaps.
212- for len (original ) > 0 {
213- var keyCode uint32
214- keyShift := false
215-
216- if strings .HasPrefix (original , "<wait>" ) {
217- log .Printf ("Special code '<wait>' found, sleeping one second" )
218- time .Sleep (1 * time .Second )
219- original = original [len ("<wait>" ):]
220- continue
221- }
222-
223- if strings .HasPrefix (original , "<wait5>" ) {
224- log .Printf ("Special code '<wait5>' found, sleeping 5 seconds" )
225- time .Sleep (5 * time .Second )
226- original = original [len ("<wait5>" ):]
227- continue
228- }
229-
230- if strings .HasPrefix (original , "<wait10>" ) {
231- log .Printf ("Special code '<wait10>' found, sleeping 10 seconds" )
232- time .Sleep (10 * time .Second )
233- original = original [len ("<wait10>" ):]
234- continue
235- }
236-
237- for specialCode , specialValue := range special {
238- if strings .HasPrefix (original , specialCode ) {
239- log .Printf ("Special code '%s' found, replacing with: %d" , specialCode , specialValue )
240- keyCode = specialValue
241- original = original [len (specialCode ):]
242- break
243- }
244- }
245-
246- if keyCode == 0 {
247- r , size := utf8 .DecodeRuneInString (original )
248- original = original [size :]
249- keyCode = uint32 (r )
250- keyShift = unicode .IsUpper (r ) || strings .ContainsRune (shiftedChars , r )
251-
252- log .Printf ("Sending char '%c', code %d, shift %v" , r , keyCode , keyShift )
253- }
254-
255- if keyShift {
256- c .KeyEvent (uint32 (KeyLeftShift ), true )
257- }
258-
259- c .KeyEvent (keyCode , true )
260- time .Sleep (time .Second / 10 )
261- c .KeyEvent (keyCode , false )
262- time .Sleep (time .Second / 10 )
263-
264- if keyShift {
265- c .KeyEvent (uint32 (KeyLeftShift ), false )
266- }
267-
268- // no matter what, wait a small period
269- time .Sleep (50 * time .Millisecond )
270- }
271- }
0 commit comments