* added function ParseSnapshotData to parse a string representation of a VBox snapshot tree

* fixed bugs
This commit is contained in:
Thomas Meckel 2019-03-23 22:02:36 +01:00 committed by Thomas Meckel
parent 45e2095ae3
commit f1f7c4e10c
1 changed files with 69 additions and 5 deletions

View File

@ -1,7 +1,12 @@
package common
import (
"bufio"
"log"
"regexp"
"strings"
"github.com/golang-collections/collections/stack"
)
// VBoxSnapshot stores the hierarchy of snapshots for a VM instance
@ -13,6 +18,66 @@ type VBoxSnapshot struct {
Children []*VBoxSnapshot
}
// ParseSnapshotData parses the machinereadable representation of a virtualbox snapshot tree
func ParseSnapshotData(snapshotData string) (*VBoxSnapshot, error) {
scanner := bufio.NewScanner(strings.NewReader(snapshotData))
SnapshotNamePartsRe := regexp.MustCompile("Snapshot(?P<Type>Name|UUID)(?P<Path>(-[1-9]+)*)=\"(?P<Value>[^\"]*)\"")
var currentIndicator string
parentStack := stack.New()
var node *VBoxSnapshot
var rootNode *VBoxSnapshot
for scanner.Scan() {
txt := scanner.Text()
idx := strings.Index(txt, "=")
if idx > 0 {
if strings.HasPrefix(txt, "Current") {
node.IsCurrent = true
} else {
matches := SnapshotNamePartsRe.FindStringSubmatch(txt)
log.Printf("************ Snapshot %s name parts", txt)
log.Printf("Matches %#v\n", matches)
log.Printf("Node %s\n", matches[0])
log.Printf("Type %s\n", matches[1])
log.Printf("Path %s\n", matches[2])
log.Printf("Leaf %s\n", matches[3])
log.Printf("Value %s\n", matches[4])
if matches[1] == "Name" {
if nil == rootNode {
node = new(VBoxSnapshot)
rootNode = node
currentIndicator = matches[2]
} else {
pathLenCur := strings.Count(currentIndicator, "-")
pathLen := strings.Count(matches[2], "-")
if pathLen > pathLenCur {
currentIndicator = matches[2]
parentStack.Push(node)
} else if pathLen < pathLenCur {
currentIndicator = matches[2]
for i := 0; i < pathLenCur-1; i++ {
parentStack.Pop()
}
}
node = new(VBoxSnapshot)
parent := parentStack.Peek().(*VBoxSnapshot)
if nil != parent {
node.Parent = parent
parent.Children = append(parent.Children, node)
}
}
node.Name = matches[4]
} else if matches[1] == "UUID" {
node.UUID = matches[4]
}
}
} else {
log.Printf("Invalid key,value pair [%s]", txt)
}
}
return rootNode, nil
}
// IsChildOf verifies if the current snaphot is a child of the passed as argument
func (sn *VBoxSnapshot) IsChildOf(candidate *VBoxSnapshot) bool {
if nil == candidate {
@ -37,9 +102,8 @@ func walk(sn *VBoxSnapshot, ch chan *VBoxSnapshot) {
for _, child := range sn.Children {
walk(child, ch)
}
} else {
ch <- sn
}
ch <- sn
}
func walker(sn *VBoxSnapshot) <-chan *VBoxSnapshot {
@ -76,7 +140,7 @@ func (sn *VBoxSnapshot) GetSnapshotsByName(name string) []*VBoxSnapshot {
for {
node, ok := <-ch
if !ok {
panic("Internal channel error while traversing the snapshot tree")
break
}
if strings.EqualFold(node.Name, name) {
result = append(result, node)
@ -92,7 +156,7 @@ func (sn *VBoxSnapshot) GetSnapshotByUUID(uuid string) *VBoxSnapshot {
for {
node, ok := <-ch
if !ok {
panic("Internal channel error while traversing the snapshot tree")
break
}
if strings.EqualFold(node.UUID, uuid) {
return node
@ -108,7 +172,7 @@ func (sn *VBoxSnapshot) GetCurrentSnapshot() *VBoxSnapshot {
for {
node, ok := <-ch
if !ok {
panic("Internal channel error while traversing the snapshot tree")
break
}
if node.IsCurrent {
return node