forked from sdboyer/gps
/
hash.go
101 lines (90 loc) · 3.08 KB
/
hash.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package gps
import (
"crypto/sha256"
"fmt"
"sort"
)
// HashInputs computes a hash digest of all data in SolveParams and the
// RootManifest that act as function inputs to Solve().
//
// The digest returned from this function is the same as the digest that would
// be included with a Solve() Result. As such, it's appropriate for comparison
// against the digest stored in a lock file, generated by a previous Solve(): if
// the digests match, then manifest and lock are in sync, and a Solve() is
// unnecessary.
//
// (Basically, this is for memoization.)
func (s *solver) HashInputs() ([]byte, error) {
// Do these checks up front before any other work is needed, as they're the
// only things that can cause errors
// Pass in magic root values, and the bridge will analyze the right thing
ptree, err := s.b.ListPackages(ProjectIdentifier{ProjectRoot: s.params.ImportRoot}, nil)
if err != nil {
return nil, badOptsFailure(fmt.Sprintf("Error while parsing packages under %s: %s", s.params.RootDir, err.Error()))
}
c, tc := s.rm.DependencyConstraints(), s.rm.TestDependencyConstraints()
// 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(pcSliceToMap(c, tc).asSortedSlice())
// We have everything we need; now, compute the hash.
h := sha256.New()
for _, pd := range p {
h.Write([]byte(pd.Ident.ProjectRoot))
h.Write([]byte(pd.Ident.NetworkName))
// FIXME Constraint.String() is a surjective-only transformation - tags
// and branches with the same name are written out as the same string.
// This could, albeit rarely, result in input collisions when a real
// change has occurred.
h.Write([]byte(pd.Constraint.String()))
}
// The stdlib and old appengine packages play the same functional role in
// solving as ignores. Because they change, albeit quite infrequently, we
// have to include them in the hash.
h.Write([]byte(stdlibPkgs))
h.Write([]byte(appenginePkgs))
// Write each of the packages, or the errors that were found for a
// particular subpath, into the hash.
for _, perr := range ptree.Packages {
if perr.Err != nil {
h.Write([]byte(perr.Err.Error()))
} else {
h.Write([]byte(perr.P.Name))
h.Write([]byte(perr.P.CommentPath))
h.Write([]byte(perr.P.ImportPath))
for _, imp := range perr.P.Imports {
h.Write([]byte(imp))
}
for _, imp := range perr.P.TestImports {
h.Write([]byte(imp))
}
}
}
// Add the package ignores, if any.
if len(s.ig) > 0 {
// Dump and sort the ignores
ig := make([]string, len(s.ig))
k := 0
for pkg := range s.ig {
ig[k] = pkg
k++
}
sort.Strings(ig)
for _, igp := range ig {
h.Write([]byte(igp))
}
}
for _, pc := range s.ovr.asSortedSlice() {
h.Write([]byte(pc.Ident.ProjectRoot))
if pc.Ident.NetworkName != "" {
h.Write([]byte(pc.Ident.NetworkName))
}
if pc.Constraint != nil {
h.Write([]byte(pc.Constraint.String()))
}
}
an, av := s.b.AnalyzerInfo()
h.Write([]byte(an))
h.Write([]byte(av.String()))
return h.Sum(nil), nil
}