From b22ce59c602efaa830476c5614d15eeaa8953601 Mon Sep 17 00:00:00 2001 From: sam boyer Date: Tue, 10 Jan 2017 19:24:58 -0500 Subject: [PATCH] Add func to print string inputs to hashing Fixes sdboyer/gps#137 --- hash.go | 26 +++++++++++++++++++++----- hash_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++- solver.go | 8 ++++---- 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/hash.go b/hash.go index c8bd4642..5dc51665 100644 --- a/hash.go +++ b/hash.go @@ -16,14 +16,21 @@ import ( // unnecessary. // // (Basically, this is for memoization.) -func (s *solver) HashInputs() []byte { +func (s *solver) HashInputs() (digest []byte) { + buf := new(bytes.Buffer) + s.writeHashingInputs(buf) + + hd := sha256.Sum256(buf.Bytes()) + digest = hd[:] + return +} + +func (s *solver) writeHashingInputs(buf *bytes.Buffer) { // Apply overrides to the constraints from the root. Otherwise, the hash // would be computed on the basis of a constraint from root that doesn't // actually affect solving. p := s.ovr.overrideAll(s.rm.DependencyConstraints().merge(s.rm.TestDependencyConstraints())) - // Build up a buffer of all the inputs. - buf := new(bytes.Buffer) for _, pd := range p { buf.WriteString(string(pd.Ident.ProjectRoot)) buf.WriteString(pd.Ident.Source) @@ -103,9 +110,18 @@ func (s *solver) HashInputs() []byte { an, av := s.b.AnalyzerInfo() buf.WriteString(an) buf.WriteString(av.String()) +} - hd := sha256.Sum256(buf.Bytes()) - return hd[:] +// HashingInputsAsString returns the raw input data used by Solver.HashInputs() +// as a string. +// +// This is primarily intended for debugging purposes. +func HashingInputsAsString(s Solver) string { + ts := s.(*solver) + buf := new(bytes.Buffer) + ts.writeHashingInputs(buf) + + return buf.String() } type sortPackageOrErr []PackageOrErr diff --git a/hash_test.go b/hash_test.go index 2aa8fb9d..d55f2de4 100644 --- a/hash_test.go +++ b/hash_test.go @@ -3,6 +3,7 @@ package gps import ( "bytes" "crypto/sha256" + "strings" "testing" ) @@ -42,7 +43,12 @@ func TestHashInputs(t *testing.T) { correct := h.Sum(nil) if !bytes.Equal(dig, correct) { - t.Errorf("Hashes are not equal") + t.Error("Hashes are not equal") + } + + fixstr, hisstr := strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) } } @@ -94,6 +100,11 @@ func TestHashInputsReqsIgs(t *testing.T) { t.Errorf("Hashes are not equal") } + fixstr, hisstr := strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) + } + // Add requires rm.req = map[string]bool{ "baz": true, @@ -137,6 +148,11 @@ func TestHashInputsReqsIgs(t *testing.T) { t.Errorf("Hashes are not equal") } + fixstr, hisstr = strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) + } + // remove ignores, just test requires alone rm.ig = nil params.Manifest = rm @@ -173,6 +189,11 @@ func TestHashInputsReqsIgs(t *testing.T) { if !bytes.Equal(dig, correct) { t.Errorf("Hashes are not equal") } + + fixstr, hisstr = strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) + } } func TestHashInputsOverrides(t *testing.T) { @@ -224,6 +245,11 @@ func TestHashInputsOverrides(t *testing.T) { t.Errorf("Hashes are not equal") } + fixstr, hisstr := strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) + } + // Override not in root, just with constraint rm.ovr["d"] = ProjectProperties{ Constraint: NewBranch("foobranch"), @@ -257,6 +283,11 @@ func TestHashInputsOverrides(t *testing.T) { t.Errorf("Hashes are not equal") } + fixstr, hisstr = strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) + } + // Override not in root, both constraint and network name rm.ovr["e"] = ProjectProperties{ Source: "groucho", @@ -294,6 +325,11 @@ func TestHashInputsOverrides(t *testing.T) { t.Errorf("Hashes are not equal") } + fixstr, hisstr = strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) + } + // Override in root, just constraint rm.ovr["a"] = ProjectProperties{ Constraint: NewVersion("fluglehorn"), @@ -332,6 +368,11 @@ func TestHashInputsOverrides(t *testing.T) { t.Errorf("Hashes are not equal") } + fixstr, hisstr = strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) + } + // Override in root, only network name rm.ovr["a"] = ProjectProperties{ Source: "nota", @@ -371,6 +412,11 @@ func TestHashInputsOverrides(t *testing.T) { t.Errorf("Hashes are not equal") } + fixstr, hisstr = strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) + } + // Override in root, network name and constraint rm.ovr["a"] = ProjectProperties{ Source: "nota", @@ -411,4 +457,9 @@ func TestHashInputsOverrides(t *testing.T) { if !bytes.Equal(dig, correct) { t.Errorf("Hashes are not equal") } + + fixstr, hisstr = strings.Join(elems, ""), HashingInputsAsString(s) + if fixstr != hisstr { + t.Errorf("Hashing inputs not equal:\n\t(GOT) %s\n\t(WNT) %s", hisstr, fixstr) + } } diff --git a/solver.go b/solver.go index e855f063..c74e104c 100644 --- a/solver.go +++ b/solver.go @@ -173,10 +173,10 @@ type solver struct { // a "lock file" - and/or use it to write out a directory tree of dependencies, // suitable to be a vendor directory, via CreateVendorTree. type Solver interface { - // HashInputs produces a hash digest representing the unique inputs to this - // solver. It is guaranteed that, if the hash digest is equal to the digest - // from a previous Solution.InputHash(), that that Solution is valid for - // this Solver's inputs. + // HashInputs hashes the unique inputs to this solver, returning the hash + // digest. It is guaranteed that, if the resulting digest is equal to the + // digest returned from a previous Solution.InputHash(), that that Solution + // is valid for this Solver's inputs. // // In such a case, it may not be necessary to run Solve() at all. HashInputs() []byte