diff --git a/resolver/berkshelf/resolver.go b/resolver/berkshelf/resolver.go index 20c7174..7919cda 100644 --- a/resolver/berkshelf/resolver.go +++ b/resolver/berkshelf/resolver.go @@ -39,3 +39,8 @@ func (r Resolver) Resolve(dst string) error { func (r Resolver) Name() string { return "Berkshelf" } + +// InputFiles returns a list of files Berkshelf uses as input. +func (r Resolver) InputFiles() []string { + return []string{"Berksfile", "Berksfile.lock"} +} diff --git a/resolver/dir/resolver.go b/resolver/dir/resolver.go index 0b7bf34..b7309d9 100644 --- a/resolver/dir/resolver.go +++ b/resolver/dir/resolver.go @@ -41,3 +41,8 @@ func (r Resolver) Resolve(dst string) error { func (r Resolver) Name() string { return "Directory" } + +// InputFiles returns a list of files the directory resolver uses as input. +func (r Resolver) InputFiles() []string { + return []string{} +} diff --git a/resolver/librarian/resolver.go b/resolver/librarian/resolver.go index a1475d1..6036670 100644 --- a/resolver/librarian/resolver.go +++ b/resolver/librarian/resolver.go @@ -25,3 +25,8 @@ func (r Resolver) Resolve(dst string) error { func (r Resolver) Name() string { return "Librarian-Chef" } + +// InputFiles returns a list of files Librarian-Chef uses as input. +func (r Resolver) InputFiles() []string { + return []string{"Cheffile", "Cheffile.lock"} +} diff --git a/resolver/resolver.go b/resolver/resolver.go index 5c6f0d1..3d6566a 100644 --- a/resolver/resolver.go +++ b/resolver/resolver.go @@ -20,6 +20,7 @@ import ( type Resolver interface { Resolve(dst string) error Name() string + InputFiles() []string } func findResolverByName(name string) (Resolver, error) { @@ -41,23 +42,26 @@ func findResolver(name, dst string) (Resolver, error) { return findResolverByName(name) } - cb, _ := cookbook.NewCookbook(".") + tsFile := path.Join(dst, "action_resolve") + ts, _ := util.ReadTimestampFile(tsFile) - // If the current folder is a cookbook and its dependencies have - // already been resolved, only update this cookbook with rsync. - // TODO: improve this check by comparing timestamps etc. - if cb.Name != "" && util.FileExist(dst) { - return dir.Resolver{}, nil - } - - if util.FileExist("Berksfile") { - return berkshelf.Resolver{}, nil + for _, name := range berkshelf.InputFiles { + mt, err := util.FileModTime(name) + if err == nil && mt >= ts { + log.Debugf("%s was updated, using Berkshelf\n", name) + return berkshelf.Resolver{}, nil + } } - if util.FileExist("Cheffile") { - return librarian.Resolver{}, nil + for _, name := range librarian.InputFiles { + mt, err := util.FileModTime(name) + if err == nil && mt >= ts { + log.Debugf("%s was updated, using Librarian\n", name) + return librarian.Resolver{}, nil + } } + cb, _ := cookbook.NewCookbook(".") if cb.Name != "" { return dir.Resolver{}, nil } @@ -102,6 +106,11 @@ func Resolve(name, dst string) error { return err } + tsFile := path.Join(dst, "action_resolve") + if err := util.WriteTimestampFile(tsFile); err != nil { + return err + } + log.Info("Stripping non-cookbook files") return stripCookbooks(dst) diff --git a/util/util.go b/util/util.go index 6af4e6c..ec35a99 100644 --- a/util/util.go +++ b/util/util.go @@ -5,7 +5,9 @@ import ( "io/ioutil" "os" "path/filepath" + "strconv" "strings" + "time" ) // FileExist reports whether a file or directory exists. @@ -57,3 +59,28 @@ func InTestDir(f func()) { defer os.RemoveAll(testDir) InDir(testDir, f) } + +// WriteTimestampFile writes the current time as Unix timestamp to a file. +func WriteTimestampFile(filename string) error { + ts := strconv.FormatInt(time.Now().Unix(), 10) + return ioutil.WriteFile(filename, []byte(ts), 0644) +} + +// ReadTimestampFile reads the Unix timestamp from a file created with +// WriteTimestampFile. +func ReadTimestampFile(filename string) (int64, error) { + data, err := ioutil.ReadFile(filename) + if err != nil { + return 0, err + } + return strconv.ParseInt(string(data), 10, 64) +} + +// FileModTime returns a file's modification time as Unix timestamp. +func FileModTime(filename string) (int64, error) { + info, err := os.Stat(filename) + if err != nil { + return 0, err + } + return info.ModTime().Unix(), nil +} diff --git a/util/util_test.go b/util/util_test.go index eaa1889..47b2995 100644 --- a/util/util_test.go +++ b/util/util_test.go @@ -6,6 +6,7 @@ import ( "path/filepath" "strings" "testing" + "time" . "github.com/mlafeldt/chef-runner/util" "github.com/stretchr/testify/assert" @@ -76,3 +77,15 @@ func TestInTestDir(t *testing.T) { assert.Equal(t, wd, wd2) assert.False(t, FileExist(testDir)) } + +func TestWriteAndReadTimestampFile(t *testing.T) { + tsFile := "some-timestamp" + defer os.Remove(tsFile) + + err := WriteTimestampFile(tsFile) + assert.NoError(t, err) + + ts, err := ReadTimestampFile(tsFile) + assert.NoError(t, err) + assert.True(t, ts >= time.Now().Unix()) +}