*: have gomtree always evaluate tar_time if it is present
if the keyword "tar_time" is present when evaluating an Entry, gomtree should use the tar_time when evaluating the "time" keyword as well. This commit also adds a test that makes sure "tar_time" wins against "time" if both are present. Some minor clean-ups as well, such as checking if KeywordFunc[keyword] actually retrieves a function. Signed-off-by: Stephen Chung <schung@redhat.com>
This commit is contained in:
parent
bc6f3bf902
commit
656e577ecc
7 changed files with 106 additions and 25 deletions
11
check.go
11
check.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Result of a Check
|
// Result of a Check
|
||||||
|
@ -66,7 +67,15 @@ func Check(root string, dh *DirectoryHierarchy, keywords []string) (*Result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, kv := range kvs {
|
for _, kv := range kvs {
|
||||||
keywordFunc, ok := KeywordFuncs[kv.Keyword()]
|
kw := kv.Keyword()
|
||||||
|
// 'tar_time' keyword evaluation wins against 'time' keyword evaluation
|
||||||
|
if kv.Keyword() == "time" && inSlice("tar_time", keywords) {
|
||||||
|
kw = "tar_time"
|
||||||
|
tartime := fmt.Sprintf("%s.%s", (strings.Split(kv.Value(), ".")[0]), "000000000")
|
||||||
|
kv = KeyVal(KeyVal(kw).ChangeValue(tartime))
|
||||||
|
}
|
||||||
|
|
||||||
|
keywordFunc, ok := KeywordFuncs[kw]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("Unknown keyword %q for file %q", kv.Keyword(), e.Path())
|
return nil, fmt.Errorf("Unknown keyword %q for file %q", kv.Keyword(), e.Path())
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,58 @@ func TestTimeComparison(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTarTime(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "test-tar-time.")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
// This is the format of time from FreeBSD
|
||||||
|
spec := `
|
||||||
|
/set type=file time=5.454353132
|
||||||
|
. type=dir time=5.123456789
|
||||||
|
file time=5.911134111
|
||||||
|
..
|
||||||
|
`
|
||||||
|
|
||||||
|
fh, err := os.Create(filepath.Join(dir, "file"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// This is what mode we're checking for. Round integer of epoch seconds
|
||||||
|
epoch := time.Unix(5, 0)
|
||||||
|
if err := os.Chtimes(fh.Name(), epoch, epoch); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.Chtimes(dir, epoch, epoch); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := fh.Close(); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dh, err := ParseSpec(bytes.NewBufferString(spec))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure "time" keyword works
|
||||||
|
_, err = Check(dir, dh, DefaultKeywords)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure tar_time wins
|
||||||
|
res, err := Check(dir, dh, append(DefaultKeywords, "tar_time"))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if len(res.Failures) > 0 {
|
||||||
|
t.Fatal(res.Failures)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIgnoreComments(t *testing.T) {
|
func TestIgnoreComments(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "test-comments.")
|
dir, err := ioutil.TempDir("", "test-comments.")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -93,9 +93,13 @@ func main() {
|
||||||
if !inSlice("type", currentKeywords) {
|
if !inSlice("type", currentKeywords) {
|
||||||
currentKeywords = append([]string{"type"}, currentKeywords...)
|
currentKeywords = append([]string{"type"}, currentKeywords...)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if *flTar != "" {
|
||||||
|
currentKeywords = mtree.DefaultTarKeywords[:]
|
||||||
} else {
|
} else {
|
||||||
currentKeywords = mtree.DefaultKeywords[:]
|
currentKeywords = mtree.DefaultKeywords[:]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// -K <keywords>
|
// -K <keywords>
|
||||||
if *flAddKeywords != "" {
|
if *flAddKeywords != "" {
|
||||||
currentKeywords = append(currentKeywords, splitKeywordsArg(*flAddKeywords)...)
|
currentKeywords = append(currentKeywords, splitKeywordsArg(*flAddKeywords)...)
|
||||||
|
@ -192,13 +196,9 @@ func main() {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
isErr = true
|
isErr = true
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
if res != nil {
|
if res != nil {
|
||||||
if len(res.Failures) > 0 {
|
|
||||||
defer os.Exit(1)
|
|
||||||
for _, failure := range res.Failures {
|
|
||||||
fmt.Println(failure)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(res.Extra) > 0 {
|
if len(res.Extra) > 0 {
|
||||||
defer os.Exit(1)
|
defer os.Exit(1)
|
||||||
for _, extra := range res.Extra {
|
for _, extra := range res.Extra {
|
||||||
|
|
22
keywords.go
22
keywords.go
|
@ -59,6 +59,11 @@ func (kv KeyVal) Value() string {
|
||||||
return strings.SplitN(strings.TrimSpace(string(kv)), "=", 2)[1]
|
return strings.SplitN(strings.TrimSpace(string(kv)), "=", 2)[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChangeValue changes the value of a KeyVal
|
||||||
|
func (kv KeyVal) ChangeValue(newval string) string {
|
||||||
|
return fmt.Sprintf("%s=%s", kv.Keyword(), newval)
|
||||||
|
}
|
||||||
|
|
||||||
// keywordSelector takes an array of "keyword=value" and filters out that only the set of words
|
// keywordSelector takes an array of "keyword=value" and filters out that only the set of words
|
||||||
func keywordSelector(keyval, words []string) []string {
|
func keywordSelector(keyval, words []string) []string {
|
||||||
retList := []string{}
|
retList := []string{}
|
||||||
|
@ -129,6 +134,17 @@ var (
|
||||||
"nlink",
|
"nlink",
|
||||||
"time",
|
"time",
|
||||||
}
|
}
|
||||||
|
// DefaultTarKeywords has keywords that should be used when creating a manifest from
|
||||||
|
// an archive. Currently, evaluating the # of hardlinks has not been implemented yet
|
||||||
|
DefaultTarKeywords = []string{
|
||||||
|
"size",
|
||||||
|
"type",
|
||||||
|
"uid",
|
||||||
|
"gid",
|
||||||
|
"mode",
|
||||||
|
"link",
|
||||||
|
"tar_time",
|
||||||
|
}
|
||||||
// SetKeywords is the default set of keywords calculated for a `/set` SpecialType
|
// SetKeywords is the default set of keywords calculated for a `/set` SpecialType
|
||||||
SetKeywords = []string{
|
SetKeywords = []string{
|
||||||
"uid",
|
"uid",
|
||||||
|
@ -213,11 +229,7 @@ var (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tartimeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
|
tartimeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
|
||||||
t := info.ModTime().Unix()
|
return fmt.Sprintf("tar_time=%d.000000000", info.ModTime().Unix()), nil
|
||||||
if t == 0 {
|
|
||||||
return "tar_time=0.000000000", nil
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("tar_time=%d.000000000", t), nil
|
|
||||||
}
|
}
|
||||||
timeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
|
timeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
|
||||||
t := info.ModTime().UnixNano()
|
t := info.ModTime().UnixNano()
|
||||||
|
|
7
tar.go
7
tar.go
|
@ -93,6 +93,8 @@ func (ts *tarStream) readHeaders() {
|
||||||
ts.pipeReader.CloseWithError(err)
|
ts.pipeReader.CloseWithError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer tmpFile.Close()
|
||||||
|
defer os.Remove(tmpFile.Name())
|
||||||
|
|
||||||
// Alright, it's either file or directory
|
// Alright, it's either file or directory
|
||||||
e := Entry{
|
e := Entry{
|
||||||
|
@ -119,7 +121,6 @@ func (ts *tarStream) readHeaders() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ts.setErr(err)
|
ts.setErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// for good measure, check that we actually get a value for a keyword
|
// for good measure, check that we actually get a value for a keyword
|
||||||
if val != "" {
|
if val != "" {
|
||||||
e.Keywords = append(e.Keywords, val)
|
e.Keywords = append(e.Keywords, val)
|
||||||
|
@ -134,7 +135,6 @@ func (ts *tarStream) readHeaders() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect meta-set keywords for a directory so that we can build the
|
// collect meta-set keywords for a directory so that we can build the
|
||||||
// actual sets in `flatten`
|
// actual sets in `flatten`
|
||||||
if hdr.FileInfo().IsDir() {
|
if hdr.FileInfo().IsDir() {
|
||||||
|
@ -168,9 +168,6 @@ func (ts *tarStream) readHeaders() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
populateTree(&root, &e, hdr, ts)
|
populateTree(&root, &e, hdr, ts)
|
||||||
|
|
||||||
tmpFile.Close()
|
|
||||||
os.Remove(tmpFile.Name())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package mtree
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
@ -115,17 +114,17 @@ func TestTar(t *testing.T) {
|
||||||
switch {
|
switch {
|
||||||
case len(res.Failures) > 0:
|
case len(res.Failures) > 0:
|
||||||
for _, f := range res.Failures {
|
for _, f := range res.Failures {
|
||||||
fmt.Printf("%s\n", f)
|
t.Errorf("%s\n", f)
|
||||||
}
|
}
|
||||||
errors += "Keyword validation errors\n"
|
errors += "Keyword validation errors\n"
|
||||||
case len(res.Missing) > 0:
|
case len(res.Missing) > 0:
|
||||||
for _, m := range res.Missing {
|
for _, m := range res.Missing {
|
||||||
fmt.Printf("Missing file: %s\n", m.Path())
|
t.Errorf("Missing file: %s\n", m.Path())
|
||||||
}
|
}
|
||||||
errors += "Missing files not expected for this test\n"
|
errors += "Missing files not expected for this test\n"
|
||||||
case len(res.Extra) > 0:
|
case len(res.Extra) > 0:
|
||||||
for _, e := range res.Extra {
|
for _, e := range res.Extra {
|
||||||
fmt.Printf("Extra file: %s\n", e.Path())
|
t.Errorf("Extra file: %s\n", e.Path())
|
||||||
}
|
}
|
||||||
errors += "Extra files not expected for this test\n"
|
errors += "Extra files not expected for this test\n"
|
||||||
}
|
}
|
||||||
|
|
18
walk.go
18
walk.go
|
@ -80,7 +80,11 @@ func Walk(root string, exlcudes []ExcludeFunc, keywords []string) (*DirectoryHie
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
r = fh
|
r = fh
|
||||||
}
|
}
|
||||||
if str, err := KeywordFuncs[keyword](path, info, r); err == nil && str != "" {
|
keywordFunc, ok := KeywordFuncs[keyword]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Unknown keyword %q for file %q", keyword, path)
|
||||||
|
}
|
||||||
|
if str, err := keywordFunc(path, info, r); err == nil && str != "" {
|
||||||
e.Keywords = append(e.Keywords, str)
|
e.Keywords = append(e.Keywords, str)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -107,7 +111,11 @@ func Walk(root string, exlcudes []ExcludeFunc, keywords []string) (*DirectoryHie
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
r = fh
|
r = fh
|
||||||
}
|
}
|
||||||
str, err := KeywordFuncs[keyword](path, info, r)
|
keywordFunc, ok := KeywordFuncs[keyword]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Unknown keyword %q for file %q", keyword, path)
|
||||||
|
}
|
||||||
|
str, err := keywordFunc(path, info, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -158,7 +166,11 @@ func Walk(root string, exlcudes []ExcludeFunc, keywords []string) (*DirectoryHie
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
r = fh
|
r = fh
|
||||||
}
|
}
|
||||||
str, err := KeywordFuncs[keyword](path, info, r)
|
keywordFunc, ok := KeywordFuncs[keyword]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Unknown keyword %q for file %q", keyword, path)
|
||||||
|
}
|
||||||
|
str, err := keywordFunc(path, info, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue