<commit_before>package virtualbox

import (
	"bytes"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type StatusType string

const (
	NotFound  StatusType = "notfound"
	Invalid              = "invalid"
	Stopped              = "stopped"
	Suspended            = "suspended"
	Running              = "running"
	Saved                = "saved"
	// TODO: more statuses
)

func VboxManageOutput(exe string, args ...string) (string, error) {
	var stdout, stderr bytes.Buffer
	log.Debugf("Executing VBoxManageOutput: %#v", args)
	cmd := exec.Command(exe, args...)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()

	stderrString := strings.TrimSpace(stderr.String())

	if _, ok := err.(*exec.ExitError); ok {
		err = fmt.Errorf("VBoxManageOutput error: %s", stderrString)
	}

	return stdout.String(), err
}

func VBoxManage(args ...string) (string, error) {
	return VboxManageOutput("vboxmanage", args...)
}

func Version() (string, error) {
	version, err := VBoxManage("--version")
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(version), nil
}

func FindSSHPort(vmName string) (string, error) {
	info, err := VBoxManage("showvminfo", vmName)
	portRe := regexp.MustCompile(`guestssh.*host port = (\d+)`)
	sshPort := portRe.FindStringSubmatch(info)
	return sshPort[1], err
}

func Exist(vmName string) bool {
	_, err := VBoxManage("showvminfo", vmName)
	if err != nil {
		return false
	}
	return true
}

func CreateOsVM(vmName string, templateName string) error {
	_, err := VBoxManage("clonevm", vmName, "--mode", "machine", "--name", templateName, "--register")
	return err
}

func FindNextPort(highport string, usedPorts [][]string) string {
	for _, port := range usedPorts {
		if highport == port[1] {
			var temp int
			temp, _ = strconv.Atoi(highport)
			temp = temp + 1
			highport = strconv.Itoa(temp)
			highport = FindNextPort(highport, usedPorts)
		}
	}
	return highport
}

func ConfigureSSH(vmName string, vmSSHPort string) error {
	var localport string
	output, err := VBoxManage("list", "vms", "-l")
	allPortsRe := regexp.MustCompile(`host port = (\d+)`)
	usedPorts := allPortsRe.FindAllStringSubmatch(output, -1)
	log.Debugln(usedPorts)
	if usedPorts == nil {
		localport = "2222"
	} else {
		highport := "2222"
		localport = FindNextPort(highport, usedPorts)
	}

	rule := fmt.Sprintf("guestssh,tcp,127.0.0.1,%s,,%s", localport, vmSSHPort)
	_, err = VBoxManage("modifyvm", vmName, "--natpf1", rule)
	return err<commit_msg>Rework fix for #1074 based on feedback<commit_after>package virtualbox

import (
	"bytes"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"net"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type StatusType string

const (
	NotFound  StatusType = "notfound"
	Invalid              = "invalid"
	Stopped              = "stopped"
	Suspended            = "suspended"
	Running              = "running"
	Saved                = "saved"
	// TODO: more statuses
)

func VboxManageOutput(exe string, args ...string) (string, error) {
	var stdout, stderr bytes.Buffer
	log.Debugf("Executing VBoxManageOutput: %#v", args)
	cmd := exec.Command(exe, args...)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()

	stderrString := strings.TrimSpace(stderr.String())

	if _, ok := err.(*exec.ExitError); ok {
		err = fmt.Errorf("VBoxManageOutput error: %s", stderrString)
	}

	return stdout.String(), err
}

func VBoxManage(args ...string) (string, error) {
	return VboxManageOutput("vboxmanage", args...)
}

func Version() (string, error) {
	version, err := VBoxManage("--version")
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(version), nil
}

func FindSSHPort(vmName string) (string, error) {
	info, err := VBoxManage("showvminfo", vmName)
	portRe := regexp.MustCompile(`guestssh.*host port = (\d+)`)
	sshPort := portRe.FindStringSubmatch(info)
	return sshPort[1], err
}

func Exist(vmName string) bool {
	_, err := VBoxManage("showvminfo", vmName)
	if err != nil {
		return false
	}
	return true
}

func CreateOsVM(vmName string, templateName string) error {
	_, err := VBoxManage("clonevm", vmName, "--mode", "machine", "--name", templateName, "--register")
	return err
}

func FindNextPort(highport string, usedPorts [][]string) string {
	for _, port := range usedPorts {
		if highport == port[1] {
			var temp int
			temp, _ = strconv.Atoi(highport)
			temp = temp + 1
			highport = strconv.Itoa(temp)
			highport = FindNextPort(highport, usedPorts)
		}
	}
	return highport
}

func isPortUnassigned(highport string, usedPorts [][]string) bool {
	for _, port := range usedPorts {
		if highport == port[1] {
			return false
		}
	}
	return true
}

func getUsedVirtualboxPorts() ([][]string, error) {
	output, err := VBoxManage("list", "vms", "-l")
	if err != nil {
		return nil, err
	}
	allPortsRe := regexp.MustCompile(`host port = (\d+)`)
	usedPorts := allPortsRe.FindAllStringSubmatch(output, -1)
	log.Debugln(usedPorts)
	return usedPorts, nil
}

func ConfigureSSH(vmName string, vmSSHPort string) error {
	var localport string

	for {
		ln, err := net.Listen("tcp", ":0")
		if err != nil {
			log.Debugln(err)
			return err
		}
		defer ln.Close()

		addressElements := strings.Split(ln.Addr().String(), ":")
		localport = addressElements[len(addressElements)-1]

		usedPorts, err := getUsedVirtualboxPorts()
		if err != nil {
			log.Debugln(err)
			return err
		}

		if isPortUnassigned(localport, usedPorts) {
			break
		}
		// We're going around the loop again, getting a new ln
		ln.Close()
	}

	rule := fmt.Sprintf("guestssh,tcp,127.0.0.1,%s,,%s", localport, vmSSHPort)
	_, err := VBoxManage("modifyvm", vmName, "--natpf1", rule)
	return err
{'fraction_non_alphanumeric': 0.14934036939313985, 'fraction_numerical': 0.006508355321020229, 'mean_word_length': 3.7741393786733837, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '750083', 'n_tokens_mistral': 2177, 'n_tokens_neox': 2057, 'n_words': 494}