123 lines
2.4 KiB
Go
123 lines
2.4 KiB
Go
|
package target
|
||
|
|
||
|
import (
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// Path reports if any of the sources have been modified more recently
|
||
|
// than the destination. Path does not descend into directories, it literally
|
||
|
// just checks the modtime of each thing you pass to it.
|
||
|
func Path(dst string, sources ...string) (bool, error) {
|
||
|
stat, err := os.Stat(dst)
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
srcTime := stat.ModTime()
|
||
|
dt, err := loadTargets(sources)
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
t := dt.modTime()
|
||
|
if t.After(srcTime) {
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
// Dir reports whether any of the sources have been modified
|
||
|
// more recently than the destination. If a source or destination is
|
||
|
// a directory, modtimes of files under those directories are compared
|
||
|
// instead.
|
||
|
func Dir(dst string, sources ...string) (bool, error) {
|
||
|
stat, err := os.Stat(dst)
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
srcTime := stat.ModTime()
|
||
|
if stat.IsDir() {
|
||
|
srcTime, err = calDirModTimeRecursive(stat)
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
}
|
||
|
dt, err := loadTargets(sources)
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
t, err := dt.modTimeDir()
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
if t.After(srcTime) {
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
func calDirModTimeRecursive(dir os.FileInfo) (time.Time, error) {
|
||
|
t := dir.ModTime()
|
||
|
ferr := filepath.Walk(dir.Name(), func(path string, info os.FileInfo, err error) error {
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if info.ModTime().After(t) {
|
||
|
t = info.ModTime()
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
if ferr != nil {
|
||
|
return time.Time{}, ferr
|
||
|
}
|
||
|
return t, nil
|
||
|
}
|
||
|
|
||
|
type depTargets struct {
|
||
|
src []os.FileInfo
|
||
|
hasdir bool
|
||
|
latest time.Time
|
||
|
}
|
||
|
|
||
|
func loadTargets(targets []string) (*depTargets, error) {
|
||
|
d := &depTargets{}
|
||
|
for _, v := range targets {
|
||
|
stat, err := os.Stat(v)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if stat.IsDir() {
|
||
|
d.hasdir = true
|
||
|
}
|
||
|
d.src = append(d.src, stat)
|
||
|
if stat.ModTime().After(d.latest) {
|
||
|
d.latest = stat.ModTime()
|
||
|
}
|
||
|
}
|
||
|
return d, nil
|
||
|
}
|
||
|
|
||
|
func (d *depTargets) modTime() time.Time {
|
||
|
return d.latest
|
||
|
}
|
||
|
|
||
|
func (d *depTargets) modTimeDir() (time.Time, error) {
|
||
|
if !d.hasdir {
|
||
|
return d.latest, nil
|
||
|
}
|
||
|
var err error
|
||
|
for _, i := range d.src {
|
||
|
t := i.ModTime()
|
||
|
if i.IsDir() {
|
||
|
t, err = calDirModTimeRecursive(i)
|
||
|
if err != nil {
|
||
|
return time.Time{}, err
|
||
|
}
|
||
|
}
|
||
|
if t.After(d.latest) {
|
||
|
d.latest = t
|
||
|
}
|
||
|
}
|
||
|
return d.latest, nil
|
||
|
}
|