Say what a build was made from, and hand an image compiling Go only that (hq ADR 0267, issue 363)
A merge to the controller's repository moved the route proxy and the build seat's holder whatever it changed, because nothing said which files their builds read. A build of a trunk commit now says its build source per repository: a Go program's import closure, an archive's directory, an image's recipe and the package it names in the new 'compiles' field. That image is built from its build source alone, so a recipe reading past it fails by name, and its fingerprint is over what it was handed.
This commit is contained in:
+125
-1
@@ -9,6 +9,8 @@ import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/catalogue"
|
||||
)
|
||||
|
||||
// A build's source fingerprint: what it was made from, hashed (novox/hq issue 280).
|
||||
@@ -49,10 +51,132 @@ type sourceInputs struct {
|
||||
toolchains map[string]string
|
||||
// unpinned is why this build has no fingerprint: empty when it has one.
|
||||
unpinned string
|
||||
|
||||
// prefix is the module's directory within its repository, empty at the root.
|
||||
prefix string
|
||||
// own is the module's build source in its own repository, relative to the module's directory, and
|
||||
// whole when an artifact's is not known (novox/hq ADR 0267).
|
||||
own map[string]bool
|
||||
ownIsAll bool
|
||||
// read is, per context (repository and ref), the build source read there; nil for one read whole.
|
||||
read map[string]map[string]bool
|
||||
readAs map[string]catalogue.ArtifactContext
|
||||
}
|
||||
|
||||
func newSourceInputs(module string) *sourceInputs {
|
||||
return &sourceInputs{module: module, contexts: map[string]string{}, toolchains: map[string]string{}}
|
||||
return &sourceInputs{module: module, contexts: map[string]string{}, toolchains: map[string]string{},
|
||||
own: map[string]bool{}, read: map[string]map[string]bool{}, readAs: map[string]catalogue.ArtifactContext{}}
|
||||
}
|
||||
|
||||
// ownHas adds entries, relative to the module's directory, to its build source in its own repository.
|
||||
func (s *sourceInputs) ownHas(entries ...string) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
for _, e := range entries {
|
||||
s.own[e] = true
|
||||
}
|
||||
}
|
||||
|
||||
// ownWhole says an artifact's build source in the module's own repository is not known: the module's
|
||||
// whole directory is its source, as it was before.
|
||||
func (s *sourceInputs) ownWhole() {
|
||||
if s != nil {
|
||||
s.ownIsAll = true
|
||||
}
|
||||
}
|
||||
|
||||
func contextKey(c catalogue.ArtifactContext) string { return c.Repository + "#" + c.Ref }
|
||||
|
||||
// readIn adds entries to the build source read in a context; one read whole stays whole.
|
||||
func (s *sourceInputs) readIn(c catalogue.ArtifactContext, entries []string) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
key := contextKey(c)
|
||||
s.readAs[key] = c
|
||||
set, known := s.read[key]
|
||||
if known && set == nil {
|
||||
return
|
||||
}
|
||||
if set == nil {
|
||||
set = map[string]bool{}
|
||||
s.read[key] = set
|
||||
}
|
||||
for _, e := range entries {
|
||||
set[e] = true
|
||||
}
|
||||
}
|
||||
|
||||
// readWhole says a context is read whole by an artifact.
|
||||
func (s *sourceInputs) readWhole(c catalogue.ArtifactContext) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
key := contextKey(c)
|
||||
s.readAs[key] = c
|
||||
s.read[key] = nil
|
||||
}
|
||||
|
||||
// buildSources is what the build says it was made from, per repository: its own (module.json always,
|
||||
// and every artifact's) unless an artifact's is not known, and each context not read whole.
|
||||
func (s *sourceInputs) buildSources() []BuildSource {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
var out []BuildSource
|
||||
if !s.ownIsAll {
|
||||
own := []string{withPrefix(s.prefix, ManifestName)}
|
||||
for e := range s.own {
|
||||
own = append(own, withPrefix(s.prefix, e))
|
||||
}
|
||||
sort.Strings(own)
|
||||
out = append(out, BuildSource{Paths: compactSorted(own)})
|
||||
}
|
||||
var keys []string
|
||||
for k := range s.read {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
set := s.read[k]
|
||||
if set == nil {
|
||||
continue
|
||||
}
|
||||
var paths []string
|
||||
for e := range set {
|
||||
paths = append(paths, e)
|
||||
}
|
||||
sort.Strings(paths)
|
||||
c := s.readAs[k]
|
||||
out = append(out, BuildSource{Repository: c.Repository, Ref: c.Ref, Paths: paths})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// withPrefix is an entry relative to the module's directory made relative to its repository's root.
|
||||
func withPrefix(prefix, entry string) string {
|
||||
entry = strings.TrimPrefix(entry, "./")
|
||||
if prefix == "" {
|
||||
if entry == "" {
|
||||
return "./"
|
||||
}
|
||||
return entry
|
||||
}
|
||||
if entry == "" {
|
||||
return prefix + "/"
|
||||
}
|
||||
return prefix + "/" + entry
|
||||
}
|
||||
|
||||
func compactSorted(in []string) []string {
|
||||
var out []string
|
||||
for i, e := range in {
|
||||
if i == 0 || e != in[i-1] {
|
||||
out = append(out, e)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// notPinned marks the build as one its source does not pin; the first reason stands.
|
||||
|
||||
Reference in New Issue
Block a user