Fixed #396: Don't update the lock file if nothing has changed
diff --git a/action/update.go b/action/update.go index 4b0da7b..defaf07 100644 --- a/action/update.go +++ b/action/update.go
@@ -1,6 +1,7 @@ package action import ( + "io/ioutil" "path/filepath" "github.com/Masterminds/glide/cfg" @@ -85,9 +86,27 @@ msg.Die("Failed to generate config hash. Unable to generate lock file.") } lock := cfg.NewLockfile(confcopy.Imports, hash) - if err := lock.WriteFile(filepath.Join(base, gpath.LockFile)); err != nil { - msg.Err("Could not write lock file to %s: %s", base, err) - return + wl := true + if gpath.HasLock(base) { + yml, err := ioutil.ReadFile(filepath.Join(base, gpath.LockFile)) + if err == nil { + l2, err := cfg.LockfileFromYaml(yml) + if err == nil { + f1, err := l2.Fingerprint() + f2, err2 := lock.Fingerprint() + if err == nil && err2 == nil && f1 == f2 { + wl = false + } + } + } + } + if wl { + if err := lock.WriteFile(filepath.Join(base, gpath.LockFile)); err != nil { + msg.Err("Could not write lock file to %s: %s", base, err) + return + } + } else { + msg.Info("Versions did not change. Skipping glide.lock update.") } msg.Info("Project relies on %d dependencies.", len(confcopy.Imports))
diff --git a/cfg/lock.go b/cfg/lock.go index 46f0753..8fdbf37 100644 --- a/cfg/lock.go +++ b/cfg/lock.go
@@ -1,6 +1,8 @@ package cfg import ( + "crypto/sha256" + "fmt" "io/ioutil" "sort" "strings" @@ -45,9 +47,46 @@ return ioutil.WriteFile(lockpath, o, 0666) } +// Clone returns a clone of Lockfile +func (lf *Lockfile) Clone() *Lockfile { + n := &Lockfile{} + n.Hash = lf.Hash + n.Updated = lf.Updated + n.Imports = lf.Imports.Clone() + n.DevImports = lf.DevImports.Clone() + + return n +} + +// Fingerprint returns a hash of the contents minus the date. This allows for +// two lockfiles to be compared irrespective of their updated times. +func (lf *Lockfile) Fingerprint() (string, error) { + c := lf.Clone() + c.Updated = time.Time{} // Set the time to be the nil equivalent + sort.Sort(c.Imports) + sort.Sort(c.DevImports) + yml, err := c.Marshal() + if err != nil { + return "", err + } + + hash := sha256.New() + hash.Write(yml) + return fmt.Sprintf("%x", hash.Sum(nil)), nil +} + // Locks is a slice of locked dependencies. type Locks []*Lock +// Clone returns a Clone of Locks. +func (l Locks) Clone() Locks { + n := make(Locks, 0, len(l)) + for _, v := range l { + n = append(n, v.Clone()) + } + return n +} + // Len returns the length of the Locks. This is needed for sorting with // the sort package. func (l Locks) Len() int { @@ -81,6 +120,19 @@ Os []string `yaml:"os,omitempty"` } +// Clone creates a clone of a Lock. +func (l *Lock) Clone() *Lock { + return &Lock{ + Name: l.Name, + Version: l.Version, + Repository: l.Repository, + VcsType: l.VcsType, + Subpackages: l.Subpackages, + Arch: l.Arch, + Os: l.Os, + } +} + // NewLockfile is used to create an instance of Lockfile. func NewLockfile(ds Dependencies, hash string) *Lockfile { lf := &Lockfile{