Skip to content

Commit

Permalink
Added Hyper-V support, some code refactoring and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
artemdevel committed Mar 10, 2016
1 parent 2f23f45 commit 38c423d
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 19 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# getIE
Command line tool to download and setup Internet Explorer virtual machines provided by Microsoft for developers.

Inspired by [Automated installation of the Microsoft IE App Compat virtual machines](http://xdissent.github.com/ievms)
Inspired by [Automated installation of the Microsoft IE App Compat virtual machines](http://xdissent.github.com/ievms).

More information about IE virtual machines provided by Microsoft could be found [here](https://dev.windows.com/en-us/microsoft-edge/tools/vms/windows/)
More information about IE virtual machines provided by Microsoft could be found [here](https://dev.windows.com/en-us/microsoft-edge/tools/vms/windows/).

### Status
### Build status
[![Build Status](https://travis-ci.org/artemdevel/getIE.svg)](https://travis-ci.org/artemdevel/getIE)
3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ func main() {
platforms, "Select platform", "All", utils.GetDefaultPlatform)
userChoice.Hypervisor = utils.SelectOption(
hypervisors, "Select hypervisor", userChoice.Platform, utils.GetDefaultHypervisor)
if userChoice.Hypervisor == "HyperV" {
utils.EnterToContinue("WARNING: For HyperV you must run this tool as Administrator")
}
userChoice.BrowserOs = utils.SelectOption(
browsers, "Select browser and OS", userChoice.Hypervisor, utils.GetDefaultBrowser)
userChoice.VMImage = availableVms[userChoice.Spec]
Expand Down
6 changes: 3 additions & 3 deletions utils/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ func YesNoConfirmation(msg string) {
func EnterToContinue(msg string) {
reader := bufio.NewReader(os.Stdin)
if runtime.GOOS == "darwin" {
fmt.Printf("%s. Press ENTER to continue CMD-C to abort\n", msg)
fmt.Printf("%s. Press ENTER to continue CMD-C to abort.\n", msg)
} else {
fmt.Printf("%s. Press ENTER to continue CTRL-C to abort\n", msg)
fmt.Printf("%s. Press ENTER to continue CTRL-C to abort.\n", msg)
}
reader.ReadString('\n')
}
Expand All @@ -57,7 +57,7 @@ func SelectOption(choices ChoiceGroups, groupMsg, groupName string, defaultChoic
for {
fmt.Printf("%s [%d]: ", groupMsg, defaultChoice)
text, _ := reader.ReadString('\n')
if text == "\n" {
if strings.TrimSpace(text) == "" {
return sortedChoices[defaultChoice]
}
selected, err := strconv.Atoi(strings.TrimSpace(text))
Expand Down
7 changes: 3 additions & 4 deletions utils/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"io/ioutil"
"net/http"
"os"
"path"
"regexp"
"runtime"
"strings"
Expand Down Expand Up @@ -146,11 +145,11 @@ func ParseJSON(rawData *[]byte) (
func getDownloadPath() string {
switch runtime.GOOS {
case "linux":
return path.Join(os.Getenv("HOME"), "Downloads")
return pathJoin(os.Getenv("HOME"), "Downloads")
case "darwin":
return path.Join(os.Getenv("HOME"), "Downloads")
return pathJoin(os.Getenv("HOME"), "Downloads")
case "windows":
return path.Join(os.Getenv("USERPROFILE"), "Downloads")
return pathJoin(os.Getenv("USERPROFILE"), "Downloads")
default:
return ""
}
Expand Down
69 changes: 60 additions & 9 deletions utils/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"os/exec"
"path"
"strings"
"runtime"
)

// ProgressWrapper type is used to track download progress.
Expand Down Expand Up @@ -77,12 +78,19 @@ func compareMd5(md5str1, md5str2 string) {
}
}

func pathJoin(path1, path2 string) string {
if runtime.GOOS == "windows" {
return strings.Replace(path.Join(path1, path2), "/", "\\", -1)
}
return path.Join(path1, path2)
}

// DownloadVM function downloads VM archive defined by a user and returns the path where it was stored.
func DownloadVM(uc UserChoice) string {
// TODO: during download add .part extension to the downloaded file
// TODO: add check for .part file for resumable downloads
// TODO: return error instead of panic()
vmFile := path.Join(uc.DownloadPath, path.Base(uc.VMImage.FileURL))
vmFile := pathJoin(uc.DownloadPath, path.Base(uc.VMImage.FileURL))
fmt.Printf("Prepare to download %s to %s\n", uc.VMImage.FileURL, vmFile)

origMd5 := getOrigMd5(uc.VMImage)
Expand Down Expand Up @@ -147,6 +155,8 @@ func vmFilePath(hypervisor string, collectedPaths []string) string {
search = ".ova"
} else if hypervisor == "VMware" {
search = ".ovf"
} else if hypervisor == "HyperV" {
search = ".xml"
} else {
fmt.Printf("Hypervisor %s isn't supported.\n", hypervisor)
return ""
Expand All @@ -162,14 +172,14 @@ func vmFilePath(hypervisor string, collectedPaths []string) string {

// UnzipVM function unpack downloaded VM archive.
func UnzipVM(uc UserChoice) string {
vmPath := path.Join(uc.DownloadPath, path.Base(uc.VMImage.FileURL))
vmPath := pathJoin(uc.DownloadPath, path.Base(uc.VMImage.FileURL))
zipReader, err := zip.OpenReader(vmPath)
if err != nil {
panic(err)
}
defer zipReader.Close()

unzipFolder := path.Join(uc.DownloadPath, path.Base(uc.VMImage.FileURL))
unzipFolder := pathJoin(uc.DownloadPath, path.Base(uc.VMImage.FileURL))
unzipFolderParts := strings.Split(unzipFolder, ".")
unzipFolder = strings.Join(unzipFolderParts[:len(unzipFolderParts)-1], ".")
if _, err := os.Stat(unzipFolder); os.IsNotExist(err) {
Expand All @@ -182,10 +192,10 @@ func UnzipVM(uc UserChoice) string {
var collectedPaths []string
for _, file := range zipReader.File {
fmt.Printf("Unpacking '%s'\n", file.Name)
filePath := path.Join(unzipFolder, file.Name)
filePath := pathJoin(unzipFolder, file.Name)
if _, err := os.Stat(filePath); err == nil {
collectedPaths = append(collectedPaths, filePath)
fmt.Printf("File '%s' already exist, skip\n", filePath)
fmt.Printf("File '%s' already exist, skip.\n", filePath)
continue
}
if file.FileInfo().IsDir() {
Expand Down Expand Up @@ -245,6 +255,7 @@ func virtualboxImportVM(vmPath string) error {
}

func vmwareCheck() error {
// TODO: improve VMware installation checks for Windows platforms.
// NOTE: VMware requires two command line tools to works with VMs.
fmt.Println("Checking VMware installation..")
cmdName := "ovftool"
Expand All @@ -258,9 +269,11 @@ func vmwareCheck() error {

// NOTE: vmrun doesn't have --help or --version or similar options.
// Without any parameters it exits with status code 255 and help text.
// NOTE: Under Windows vmrun has exist status 4294967295.
cmdName = "vmrun"
result, err = exec.Command(cmdName).CombinedOutput()
if fmt.Sprintf("%s", err) != "exit status 255" {
// TODO: improve this check
if !strings.Contains(fmt.Sprintf("%s", err), "exit status") {
fmt.Println(string(result), err)
return err
}
Expand Down Expand Up @@ -317,13 +330,47 @@ func vmwareImportVM(vmxPath string) error {
return nil
}

func checkHyperv() error {
// Powershell is required for Hyper-V.
cmdName := "powershell"
cmdArgs1 := []string{"-Command", "Get-Host"}
if result, err := exec.Command(cmdName, cmdArgs1...).CombinedOutput(); err != nil {
fmt.Println(string(result))
return err
}
fmt.Println("Powershell is present.")

// Check if Hyper-V cmdlets are available.
cmdArgs2 := []string{"-Command", "Get-Command", "-Module", "Hyper-V"}
if result, err := exec.Command(cmdName, cmdArgs2...).CombinedOutput(); err != nil {
fmt.Println(string(result))
return err
}
fmt.Println("Hyper-V Cmdlets are present.")
return nil
}

func hypervImportVM(vmPath string) error {
fmt.Printf("Import '%s'. Please wait.\n", vmPath)
cmdName := "powershell"
cmdArgs1 := []string{"-Command", "Import-VM", "-Path", fmt.Sprintf("'%s'", vmPath)}
if result, err := exec.Command(cmdName, cmdArgs1...).CombinedOutput(); err != nil {
fmt.Println(string(result))
return err
}
// TODO: check if it is possible to fix network for HyperV.
fmt.Println("WARNING: Please check Network adapter settings. By default it isn't connected.")
return nil
}

// InstallVM function installs unpacked VM into a selected hypervisor.
func InstallVM(hypervisor string, vmPath string) {
if hypervisor == "VirtualBox" {
switch hypervisor{
case "VirtualBox":
if err := virtualboxCheck(); err == nil {
virtualboxImportVM(vmPath)
}
} else if hypervisor == "VMware" {
case "VMware":
if err := vmwareCheck(); err != nil {
os.Exit(1)
}
Expand All @@ -333,7 +380,11 @@ func InstallVM(hypervisor string, vmPath string) {
}
vmwareFixNetwork(vmxPath)
vmwareImportVM(vmxPath)
} else {
case "HyperV":
if err := checkHyperv(); err == nil {
hypervImportVM(vmPath)
}
default:
fmt.Printf("Hypervisor %s isn't supported.\n", hypervisor)
}
}

0 comments on commit 38c423d

Please sign in to comment.