A module names the module its build stands on, not a copy of it
A fingerprint written into a recipe names one particular copy of the base — the copy on whichever machine the person typing it was using. On any other mesh that copy has never existed, so the build stops on its first line with a message about an image nobody can look up. Three modules in the catalogue were in exactly that state, and the line each of them replaced was equally dead. A module now names the module and artifact instead, and the mesh answers with what it holds. The builder is still a thing that clones, builds and answers: the answer travels with the question, because only the mesh knows what it has. A base the mesh has not built is refused before anything is built, naming which module has to exist first.
This commit is contained in:
@@ -184,7 +184,7 @@ func answer(ctx context.Context, channel *amqp.Channel, publisher builder.Publis
|
||||
fmt.Println()
|
||||
|
||||
built, err := builder.Build(ctx, builder.Command, publisher,
|
||||
request.Repository, request.Path, request.Ref, workspace)
|
||||
request.Repository, request.Path, request.Ref, workspace, request.Held)
|
||||
if err != nil {
|
||||
// A failure is a result. A build that fails and says nothing is indistinguishable from a
|
||||
// builder that is not running, and those want completely different responses.
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/novox/mesh-control/internal/builder"
|
||||
)
|
||||
@@ -34,6 +35,8 @@ func buildOnce(ctx context.Context, args []string) error {
|
||||
registry := set.String("registry", "",
|
||||
"host:port to publish to. Without it the artifacts stay in this machine's container runtime, which is the genesis case")
|
||||
workspace := set.String("workspace", "", "where to clone and build (default: a temporary directory)")
|
||||
on := multiple(set, "on",
|
||||
"a base this build stands on, as <module>/<artifact>=<reference>. Repeatable")
|
||||
positionals, err := parseAround(set, args)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -48,6 +51,22 @@ func buildOnce(ctx context.Context, args []string) error {
|
||||
where = os.TempDir() + "/mesh-builder-once"
|
||||
}
|
||||
|
||||
// What this build may stand on, said on the command line because there is no mesh to ask.
|
||||
//
|
||||
// **This is the genesis case and it is meant to be awkward.** On a running mesh the control
|
||||
// plane answers this, because only it knows what this mesh holds. Here nothing has been built
|
||||
// yet, so whoever runs this says what to use — and for the control plane, which is the one
|
||||
// module raised before anything else exists, the answer is ordinarily nothing at all.
|
||||
bases := map[string]string{}
|
||||
for _, pair := range *on {
|
||||
key, reference, found := strings.Cut(pair, "=")
|
||||
if !found || key == "" || reference == "" {
|
||||
return fmt.Errorf(
|
||||
"--on takes <module>/<artifact>=<reference>, and %q is not that", pair)
|
||||
}
|
||||
bases[key] = reference
|
||||
}
|
||||
|
||||
// Local unless told otherwise, because the moment this exists for has nowhere to publish. A
|
||||
// default pointing at a registry would mean genesis failing at a push to something that is not
|
||||
// there yet, one step away from the thing that could explain it.
|
||||
@@ -65,7 +84,7 @@ func buildOnce(ctx context.Context, args []string) error {
|
||||
}
|
||||
fmt.Fprintln(os.Stderr)
|
||||
|
||||
built, buildErr := builder.Build(ctx, builder.Command, publisher, repository, *path, *ref, where)
|
||||
built, buildErr := builder.Build(ctx, builder.Command, publisher, repository, *path, *ref, where, bases)
|
||||
if buildErr != nil {
|
||||
return buildErr
|
||||
}
|
||||
@@ -132,3 +151,15 @@ func parseAround(set *flag.FlagSet, args []string) ([]string, error) {
|
||||
rest = rest[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// multiple is a flag that may be given more than once.
|
||||
type repeated []string
|
||||
|
||||
func (r *repeated) String() string { return strings.Join(*r, ", ") }
|
||||
func (r *repeated) Set(v string) error { *r = append(*r, v); return nil }
|
||||
|
||||
func multiple(set *flag.FlagSet, name, usage string) *[]string {
|
||||
var values repeated
|
||||
set.Var(&values, name, usage)
|
||||
return (*[]string)(&values)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -341,6 +342,7 @@ func buildOne(ctx context.Context, repository, path, ref string, wait time.Durat
|
||||
Repository: repository,
|
||||
Path: path,
|
||||
Ref: ref,
|
||||
Held: heldBy(ctx),
|
||||
}
|
||||
fmt.Printf("asked for %s", request.Repository)
|
||||
if path != "" {
|
||||
@@ -417,6 +419,7 @@ func buildAndShow(ctx context.Context, repository, path, ref string, wait time.D
|
||||
result, err := link.RequestBuild(ctx, server.Channel(), link.BuildRequest{
|
||||
ID: fmt.Sprintf("%s-%d", "build", time.Now().UnixNano()),
|
||||
Repository: repository, Path: path, Ref: ref,
|
||||
Held: heldBy(ctx),
|
||||
}, wait)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -460,3 +463,25 @@ type answers struct {
|
||||
// a mesh whose hub is that node has no hub.
|
||||
network string
|
||||
}
|
||||
|
||||
// heldBy is every artifact this mesh has built, for a build that may need one as its base.
|
||||
//
|
||||
// **A failure here is not a failure to build.** A module that names no base does not need this at
|
||||
// all, and one that does gets a refusal naming exactly what is missing — which is a better sentence
|
||||
// than a build command refusing to start because a query did not run. So the store not opening is
|
||||
// reported and the build goes ahead without it.
|
||||
func heldBy(ctx context.Context) map[string]string {
|
||||
open, err := openStores(ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not read what this mesh has built, so a module naming a "+
|
||||
"base will be told that base is missing: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
defer open.Close()
|
||||
held, err := open.inventory.Held(ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not read what this mesh has built: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
return held
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user