tar: create and validate a manifest from a tar stream
This commit contains added features to go-mtree that allows user to create an mtree spec with '-T' option when specifying a tar archive. Users can also validate an mtree spec against a tar archive with an mtree spec. Also for the test archive, there is a mixture of files, and folders (empty & non-empty), and symlinks (broken & unbroken). Signed-off-by: Stephen Chung <schung@redhat.com>
This commit is contained in:
parent
1c5b44f1df
commit
9d870829cb
7 changed files with 502 additions and 78 deletions
98
check.go
98
check.go
|
@ -9,6 +9,8 @@ import (
|
|||
// Result of a Check
|
||||
type Result struct {
|
||||
Failures []Failure // list of any failures in the Check
|
||||
Missing []Entry
|
||||
Extra []Entry
|
||||
}
|
||||
|
||||
// Failure of a particular keyword for a path
|
||||
|
@ -89,3 +91,99 @@ func Check(root string, dh *DirectoryHierarchy, keywords []string) (*Result, err
|
|||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// TarCheck is the tar equivalent of checking a file hierarchy spec against a tar stream to
|
||||
// determine if files have been changed.
|
||||
func TarCheck(tarDH, dh *DirectoryHierarchy, keywords []string) (*Result, error) {
|
||||
var result Result
|
||||
var err error
|
||||
var tarRoot *Entry
|
||||
|
||||
for _, e := range tarDH.Entries {
|
||||
if e.Name == "." {
|
||||
tarRoot = &e
|
||||
break
|
||||
}
|
||||
}
|
||||
tarRoot.Next = &Entry{
|
||||
Name: "seen",
|
||||
Type: CommentType,
|
||||
}
|
||||
curDir := tarRoot
|
||||
creator := dhCreator{DH: dh}
|
||||
sort.Sort(byPos(creator.DH.Entries))
|
||||
|
||||
var outOfTree bool
|
||||
for i, e := range creator.DH.Entries {
|
||||
switch e.Type {
|
||||
case SpecialType:
|
||||
if e.Name == "/set" {
|
||||
creator.curSet = &creator.DH.Entries[i]
|
||||
} else if e.Name == "/unset" {
|
||||
creator.curSet = nil
|
||||
}
|
||||
case RelativeType, FullType:
|
||||
if outOfTree {
|
||||
return &result, fmt.Errorf("No parent node from %s", e.Path())
|
||||
}
|
||||
// TODO: handle the case where "." is not the first Entry to be found
|
||||
tarEntry := curDir.Descend(e.Name)
|
||||
if tarEntry == nil {
|
||||
result.Missing = append(result.Missing, e)
|
||||
continue
|
||||
}
|
||||
|
||||
tarEntry.Next = &Entry{
|
||||
Type: CommentType,
|
||||
Name: "seen",
|
||||
}
|
||||
|
||||
// expected values from file hierarchy spec
|
||||
var kvs KeyVals
|
||||
if creator.curSet != nil {
|
||||
kvs = MergeSet(creator.curSet.Keywords, e.Keywords)
|
||||
} else {
|
||||
kvs = NewKeyVals(e.Keywords)
|
||||
}
|
||||
|
||||
// actual
|
||||
var tarkvs KeyVals
|
||||
if tarEntry.Set != nil {
|
||||
tarkvs = MergeSet(tarEntry.Set.Keywords, tarEntry.Keywords)
|
||||
} else {
|
||||
tarkvs = NewKeyVals(tarEntry.Keywords)
|
||||
}
|
||||
|
||||
for _, kv := range kvs {
|
||||
if _, ok := KeywordFuncs[kv.Keyword()]; !ok {
|
||||
return nil, fmt.Errorf("Unknown keyword %q for file %q", kv.Keyword(), e.Path())
|
||||
}
|
||||
if keywords != nil && !inSlice(kv.Keyword(), keywords) {
|
||||
continue
|
||||
}
|
||||
if tarkv := tarkvs.Has(kv.Keyword()); tarkv != emptyKV {
|
||||
if string(tarkv) != string(kv) {
|
||||
failure := Failure{Path: tarEntry.Path(), Keyword: kv.Keyword(), Expected: kv.Value(), Got: tarkv.Value()}
|
||||
result.Failures = append(result.Failures, failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Step into a directory
|
||||
if tarEntry.Prev != nil {
|
||||
curDir = tarEntry
|
||||
}
|
||||
case DotDotType:
|
||||
if outOfTree {
|
||||
return &result, fmt.Errorf("No parent node.")
|
||||
}
|
||||
curDir = curDir.Ascend()
|
||||
if curDir == nil {
|
||||
outOfTree = true
|
||||
}
|
||||
}
|
||||
}
|
||||
result.Extra = filter(tarRoot, func(e *Entry) bool {
|
||||
return e.Next == nil
|
||||
})
|
||||
return &result, err
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue