func ruleHash(target *core.BuildTarget, runtime bool) []byte { h := sha1.New() h.Write([]byte(target.Label.String())) for _, dep := range target.DeclaredDependencies() { h.Write([]byte(dep.String())) } for _, vis := range target.Visibility { h.Write([]byte(vis.String())) // Doesn't strictly affect the output, but best to be safe. } for _, hsh := range target.Hashes { h.Write([]byte(hsh)) } for _, source := range target.AllSources() { h.Write([]byte(source.String())) } for _, out := range target.DeclaredOutputs() { h.Write([]byte(out)) } for _, licence := range target.Licences { h.Write([]byte(licence)) } for _, output := range target.TestOutputs { h.Write([]byte(output)) } for _, output := range target.OptionalOutputs { h.Write([]byte(output)) } for _, label := range target.Labels { h.Write([]byte(label)) } hashBool(h, target.IsBinary) hashBool(h, target.IsTest) // Note that we only hash the current command here; whatever's set in commands that we're not going // to run is uninteresting to us. h.Write([]byte(target.GetCommand())) if runtime { // Similarly, we only hash the current command here again. h.Write([]byte(target.GetTestCommand())) for _, datum := range target.Data { h.Write([]byte(datum.String())) } hashBool(h, target.Containerise) if target.ContainerSettings != nil { e := gob.NewEncoder(h) if err := e.Encode(target.ContainerSettings); err != nil { panic(err) } } if target.Containerise { h.Write(core.State.Hashes.Containerisation) } } hashBool(h, target.NeedsTransitiveDependencies) hashBool(h, target.OutputIsComplete) // Should really not be conditional here, but we don't want adding the new flag to // change the hash of every single other target everywhere. // Might consider removing this the next time we peturb the hashing strategy. if target.Stamp { hashBool(h, target.Stamp) } for _, require := range target.Requires { h.Write([]byte(require)) } // Indeterminate iteration order, yay... languages := []string{} for k := range target.Provides { languages = append(languages, k) } sort.Strings(languages) for _, lang := range languages { h.Write([]byte(lang)) h.Write([]byte(target.Provides[lang].String())) } // Obviously we don't include the code pointer because it's a pointer. h.Write(target.PreBuildHash) h.Write(target.PostBuildHash) return h.Sum(nil) }