@@ -14,6 +14,7 @@ import (
14
14
"os/exec"
15
15
"path"
16
16
"strings"
17
+ "runtime"
17
18
)
18
19
19
20
// ProgressWrapper type is used to track download progress.
@@ -77,12 +78,19 @@ func compareMd5(md5str1, md5str2 string) {
77
78
}
78
79
}
79
80
81
+ func pathJoin (path1 , path2 string ) string {
82
+ if runtime .GOOS == "windows" {
83
+ return strings .Replace (path .Join (path1 , path2 ), "/" , "\\ " , - 1 )
84
+ }
85
+ return path .Join (path1 , path2 )
86
+ }
87
+
80
88
// DownloadVM function downloads VM archive defined by a user and returns the path where it was stored.
81
89
func DownloadVM (uc UserChoice ) string {
82
90
// TODO: during download add .part extension to the downloaded file
83
91
// TODO: add check for .part file for resumable downloads
84
92
// TODO: return error instead of panic()
85
- vmFile := path . Join (uc .DownloadPath , path .Base (uc .VMImage .FileURL ))
93
+ vmFile := pathJoin (uc .DownloadPath , path .Base (uc .VMImage .FileURL ))
86
94
fmt .Printf ("Prepare to download %s to %s\n " , uc .VMImage .FileURL , vmFile )
87
95
88
96
origMd5 := getOrigMd5 (uc .VMImage )
@@ -147,6 +155,8 @@ func vmFilePath(hypervisor string, collectedPaths []string) string {
147
155
search = ".ova"
148
156
} else if hypervisor == "VMware" {
149
157
search = ".ovf"
158
+ } else if hypervisor == "HyperV" {
159
+ search = ".xml"
150
160
} else {
151
161
fmt .Printf ("Hypervisor %s isn't supported.\n " , hypervisor )
152
162
return ""
@@ -162,14 +172,14 @@ func vmFilePath(hypervisor string, collectedPaths []string) string {
162
172
163
173
// UnzipVM function unpack downloaded VM archive.
164
174
func UnzipVM (uc UserChoice ) string {
165
- vmPath := path . Join (uc .DownloadPath , path .Base (uc .VMImage .FileURL ))
175
+ vmPath := pathJoin (uc .DownloadPath , path .Base (uc .VMImage .FileURL ))
166
176
zipReader , err := zip .OpenReader (vmPath )
167
177
if err != nil {
168
178
panic (err )
169
179
}
170
180
defer zipReader .Close ()
171
181
172
- unzipFolder := path . Join (uc .DownloadPath , path .Base (uc .VMImage .FileURL ))
182
+ unzipFolder := pathJoin (uc .DownloadPath , path .Base (uc .VMImage .FileURL ))
173
183
unzipFolderParts := strings .Split (unzipFolder , "." )
174
184
unzipFolder = strings .Join (unzipFolderParts [:len (unzipFolderParts )- 1 ], "." )
175
185
if _ , err := os .Stat (unzipFolder ); os .IsNotExist (err ) {
@@ -182,10 +192,10 @@ func UnzipVM(uc UserChoice) string {
182
192
var collectedPaths []string
183
193
for _ , file := range zipReader .File {
184
194
fmt .Printf ("Unpacking '%s'\n " , file .Name )
185
- filePath := path . Join (unzipFolder , file .Name )
195
+ filePath := pathJoin (unzipFolder , file .Name )
186
196
if _ , err := os .Stat (filePath ); err == nil {
187
197
collectedPaths = append (collectedPaths , filePath )
188
- fmt .Printf ("File '%s' already exist, skip\n " , filePath )
198
+ fmt .Printf ("File '%s' already exist, skip. \n " , filePath )
189
199
continue
190
200
}
191
201
if file .FileInfo ().IsDir () {
@@ -245,6 +255,7 @@ func virtualboxImportVM(vmPath string) error {
245
255
}
246
256
247
257
func vmwareCheck () error {
258
+ // TODO: improve VMware installation checks for Windows platforms.
248
259
// NOTE: VMware requires two command line tools to works with VMs.
249
260
fmt .Println ("Checking VMware installation.." )
250
261
cmdName := "ovftool"
@@ -258,9 +269,11 @@ func vmwareCheck() error {
258
269
259
270
// NOTE: vmrun doesn't have --help or --version or similar options.
260
271
// Without any parameters it exits with status code 255 and help text.
272
+ // NOTE: Under Windows vmrun has exist status 4294967295.
261
273
cmdName = "vmrun"
262
274
result , err = exec .Command (cmdName ).CombinedOutput ()
263
- if fmt .Sprintf ("%s" , err ) != "exit status 255" {
275
+ // TODO: improve this check
276
+ if ! strings .Contains (fmt .Sprintf ("%s" , err ), "exit status" ) {
264
277
fmt .Println (string (result ), err )
265
278
return err
266
279
}
@@ -317,13 +330,47 @@ func vmwareImportVM(vmxPath string) error {
317
330
return nil
318
331
}
319
332
333
+ func checkHyperv () error {
334
+ // Powershell is required for Hyper-V.
335
+ cmdName := "powershell"
336
+ cmdArgs1 := []string {"-Command" , "Get-Host" }
337
+ if result , err := exec .Command (cmdName , cmdArgs1 ... ).CombinedOutput (); err != nil {
338
+ fmt .Println (string (result ))
339
+ return err
340
+ }
341
+ fmt .Println ("Powershell is present." )
342
+
343
+ // Check if Hyper-V cmdlets are available.
344
+ cmdArgs2 := []string {"-Command" , "Get-Command" , "-Module" , "Hyper-V" }
345
+ if result , err := exec .Command (cmdName , cmdArgs2 ... ).CombinedOutput (); err != nil {
346
+ fmt .Println (string (result ))
347
+ return err
348
+ }
349
+ fmt .Println ("Hyper-V Cmdlets are present." )
350
+ return nil
351
+ }
352
+
353
+ func hypervImportVM (vmPath string ) error {
354
+ fmt .Printf ("Import '%s'. Please wait.\n " , vmPath )
355
+ cmdName := "powershell"
356
+ cmdArgs1 := []string {"-Command" , "Import-VM" , "-Path" , fmt .Sprintf ("'%s'" , vmPath )}
357
+ if result , err := exec .Command (cmdName , cmdArgs1 ... ).CombinedOutput (); err != nil {
358
+ fmt .Println (string (result ))
359
+ return err
360
+ }
361
+ // TODO: check if it is possible to fix network for HyperV.
362
+ fmt .Println ("WARNING: Please check Network adapter settings. By default it isn't connected." )
363
+ return nil
364
+ }
365
+
320
366
// InstallVM function installs unpacked VM into a selected hypervisor.
321
367
func InstallVM (hypervisor string , vmPath string ) {
322
- if hypervisor == "VirtualBox" {
368
+ switch hypervisor {
369
+ case "VirtualBox" :
323
370
if err := virtualboxCheck (); err == nil {
324
371
virtualboxImportVM (vmPath )
325
372
}
326
- } else if hypervisor == "VMware" {
373
+ case "VMware" :
327
374
if err := vmwareCheck (); err != nil {
328
375
os .Exit (1 )
329
376
}
@@ -333,7 +380,11 @@ func InstallVM(hypervisor string, vmPath string) {
333
380
}
334
381
vmwareFixNetwork (vmxPath )
335
382
vmwareImportVM (vmxPath )
336
- } else {
383
+ case "HyperV" :
384
+ if err := checkHyperv (); err == nil {
385
+ hypervImportVM (vmPath )
386
+ }
387
+ default :
337
388
fmt .Printf ("Hypervisor %s isn't supported.\n " , hypervisor )
338
389
}
339
390
}
0 commit comments