From d1aa217f2e58fa40ef6907637e6f98cb69ffc178 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 22 Jul 2016 18:01:54 -0400 Subject: [PATCH] *: 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 --- check.go | 11 +++++++++- check_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++++ cmd/gomtree/main.go | 6 +++++- keywords.go | 22 ++++++++++++++----- tar_test.go | 7 +++--- walk.go | 18 +++++++++++++--- 6 files changed, 102 insertions(+), 14 deletions(-) diff --git a/check.go b/check.go index 793c6db..79fe8fa 100644 --- a/check.go +++ b/check.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "sort" + "strings" ) // Result of a Check @@ -65,7 +66,15 @@ func Check(root string, dh *DirectoryHierarchy, keywords []string) (*Result, err } 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 { return nil, fmt.Errorf("Unknown keyword %q for file %q", kv.Keyword(), e.Path()) } diff --git a/check_test.go b/check_test.go index d1ad6de..fa0368a 100644 --- a/check_test.go +++ b/check_test.go @@ -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) { dir, err := ioutil.TempDir("", "test-comments.") if err != nil { diff --git a/cmd/gomtree/main.go b/cmd/gomtree/main.go index 090e608..29c581b 100644 --- a/cmd/gomtree/main.go +++ b/cmd/gomtree/main.go @@ -54,7 +54,11 @@ func main() { currentKeywords = append([]string{"type"}, currentKeywords...) } } else { - currentKeywords = mtree.DefaultKeywords[:] + if *flTar != "" { + currentKeywords = mtree.DefaultTarKeywords[:] + } else { + currentKeywords = mtree.DefaultKeywords[:] + } } // -K if *flAddKeywords != "" { diff --git a/keywords.go b/keywords.go index 7bf199c..4119fc0 100644 --- a/keywords.go +++ b/keywords.go @@ -59,6 +59,11 @@ func (kv KeyVal) Value() string { 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 func keywordSelector(keyval, words []string) []string { retList := []string{} @@ -129,6 +134,17 @@ var ( "nlink", "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 = []string{ "uid", @@ -213,11 +229,7 @@ var ( } } tartimeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) { - t := info.ModTime().Unix() - if t == 0 { - return "tar_time=0.000000000", nil - } - return fmt.Sprintf("tar_time=%d.000000000", t), nil + return fmt.Sprintf("tar_time=%d.000000000", info.ModTime().Unix()), nil } timeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) { t := info.ModTime().UnixNano() diff --git a/tar_test.go b/tar_test.go index 4e940b2..38b8dd5 100644 --- a/tar_test.go +++ b/tar_test.go @@ -3,7 +3,6 @@ package mtree import ( "archive/tar" "bytes" - "fmt" "io" "io/ioutil" "os" @@ -115,17 +114,17 @@ func TestTar(t *testing.T) { switch { case len(res.Failures) > 0: for _, f := range res.Failures { - fmt.Printf("%s\n", f) + t.Errorf("%s\n", f) } errors += "Keyword validation errors\n" case len(res.Missing) > 0: 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" case len(res.Extra) > 0: 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" } diff --git a/walk.go b/walk.go index 804050e..3814c6d 100644 --- a/walk.go +++ b/walk.go @@ -80,7 +80,11 @@ func Walk(root string, exlcudes []ExcludeFunc, keywords []string) (*DirectoryHie defer fh.Close() 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) } else if err != nil { return err @@ -107,7 +111,11 @@ func Walk(root string, exlcudes []ExcludeFunc, keywords []string) (*DirectoryHie defer fh.Close() 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 { return err } @@ -158,7 +166,11 @@ func Walk(root string, exlcudes []ExcludeFunc, keywords []string) (*DirectoryHie defer fh.Close() 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 { return err }