package main import ( "context" "fmt" "strconv" "strings" "github.com/novox/mesh-controller/internal/catalogue" ) // where a build's repository is (novox/hq ADR 0111). // // A repository is on the mesh's own forge, or it is anywhere else. The first is recorded as its path // on the forge holding the git seat, and cloned from wherever that forge runs at the moment of // building; the second is a URL, recorded and cloned exactly as given. The build machine is not told // the difference — it is handed a URL either way — because only the control plane knows where the // seat's holder runs. // gitSeat is the seat a self-hosted repository lives on. const gitSeat = "git" // buildSource is where a build's repository is: a URL, or a path on a seat's holder. type buildSource struct { Repository string Seat string } // String is the source as a person reads it, which for one on a seat is not the URL: the URL is a // fact about where the forge happens to run today. func (s buildSource) String() string { if s.Seat == "" { return s.Repository } return fmt.Sprintf("%s on the %s seat", s.Repository, s.Seat) } // onASeat refuses an address given as a path on the forge. // // **A URL here would be recorded as a path**, and then composed onto the forge's address as one — // cloning `http://forge:3000/https://github.com/…`. Refused by what an address plainly looks like, // not repaired: `--self` promises a path, and something that is not one is a mistake to name. func onASeat(repository string) error { if strings.Contains(repository, ":") || strings.HasPrefix(repository, "/") || strings.Trim(repository, "/") == "" { return fmt.Errorf("--self takes the repository's path on the forge, such as novox/mesh-catalog, "+ "and %q is not one — without --self it is built from exactly what is given", repository) } return nil } // cloneFrom is the URL a build machine clones for a source. // // A URL is itself. A path on a seat is composed from the seat's holder as the mesh sees it now — // the same view planning takes of every machine, so the forge a build clones from is the forge the // mesh says holds the seat. func cloneFrom(ctx context.Context, source buildSource) (string, error) { if source.Seat == "" { return source.Repository, nil } open, err := openStores(ctx) if err != nil { return "", err } defer open.Close() shelf, err := open.inventory.Catalogue(ctx) if err != nil { return "", err } world, err := theRestOfTheMesh(ctx, open.inventory, shelf, "") if err != nil { return "", err } return clonedFromSeat(world, source.Seat, source.Repository) } // clonedFromSeat composes the clone URL for a repository on a seat's holder. // // **Refused, never defaulted, at every step that has no answer.** Nobody holding the seat is a mesh // without a forge of its own: it builds from external repositories and must say so rather than fail // to clone. A holder off the private network cannot be reached by any build machine. A holder that // serves no scheme or port has nothing to compose from — a default port here would be the forge's // address guessed, which is the thing this exists to stop. func clonedFromSeat(world catalogue.World, seatName, repository string) (string, error) { seat, known := catalogue.SeatNamed(seatName) if !known || seat.Delivers == "" { return "", fmt.Errorf("%q is not a seat a repository can live on", seatName) } var holder *catalogue.Held for i, h := range world.Held { if h.Claim == seat.Name && h.Scope == seat.Scope { holder = &world.Held[i] break } } if holder == nil { return "", fmt.Errorf("nobody holds the %s seat, so %s cannot be cloned from this mesh's "+ "forge — assign a module that claims it, or build from the repository's URL without --self", seat.Name, repository) } var provider *catalogue.Provider for i, p := range world.Offered[seat.Delivers] { if p.Node == holder.Node && p.Module == holder.Module { provider = &world.Offered[seat.Delivers][i] } } if provider == nil { return "", fmt.Errorf("%s on %s holds the %s seat and offers no %q to clone from", holder.Module, holder.Node, seat.Name, seat.Delivers) } if provider.At == "" { return "", fmt.Errorf("%s on %s holds the %s seat and is not on the private network, so no "+ "build machine can reach it", holder.Module, holder.Node, seat.Name) } scheme, _ := provider.Serves["scheme"].(string) port := servedPort(provider.Serves["port"]) if scheme == "" || port == "" { return "", fmt.Errorf("%s on %s holds the %s seat and does not serve a scheme and a port for %q", holder.Module, holder.Node, seat.Name, seat.Delivers) } path := strings.TrimSuffix(strings.Trim(repository, "/"), ".git") return fmt.Sprintf("%s://%s:%s/%s.git", scheme, provider.At, port, path), nil } // servedPort is a served port as text, however the manifest and the node's settings carried it. func servedPort(v any) string { switch p := v.(type) { case float64: return strconv.Itoa(int(p)) case int: return strconv.Itoa(p) case string: return p } return "" }