mesh/merge-gate pass: builds distribution, new: modules/artifact-store-tools → novox; no bus step; every machine composes with the change as it did without…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery failed: its walk failed: a gate on a first machine (what it carried put back), a build, a machine
A module that provides the artifact store cannot build an artifact: building publishes to the store, so the store would be needed to create itself, and the module check refuses it. The tools become artifact-store-tools, assigned beside the store, and read manifests from the store's files through its container as they already read the listing, so they need no address for the store's door. Named for the artifact store, because "store" alone is the database server (hq glossary).
130 lines
3.2 KiB
Go
130 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"sort"
|
|
)
|
|
|
|
// View is the store at one moment: its files, and every manifest's content that could be read.
|
|
type View struct {
|
|
L *Listing
|
|
// M is each manifest read, by Key.
|
|
M map[string]*Manifest
|
|
// Unread is each manifest that could not be read, by Key, with why.
|
|
Unread map[string]string
|
|
}
|
|
|
|
// Marks are the blobs one manifest keeps from the store's collector: its own content, its
|
|
// configuration and its layers, and for an index the manifests it lists. A manifest that could not be
|
|
// read marks only itself here, and the answers that rest on it say so.
|
|
func (v *View) Marks(repo, digest string) []string {
|
|
out := []string{digest}
|
|
if m := v.M[Key(repo, digest)]; m != nil {
|
|
out = append(out, m.Refs...)
|
|
out = append(out, m.Children...)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Marked is every blob some manifest marks, leaving out the manifests named in without — the
|
|
// collector's own mark, and the mark it would make once those are gone.
|
|
func (v *View) Marked(without map[string]bool) map[string]bool {
|
|
marked := map[string]bool{}
|
|
for name, r := range v.L.Repos {
|
|
for d := range r.Revisions {
|
|
if without[Key(name, d)] {
|
|
continue
|
|
}
|
|
for _, b := range v.Marks(name, d) {
|
|
marked[b] = true
|
|
}
|
|
}
|
|
}
|
|
return marked
|
|
}
|
|
|
|
// Bytes is the size of these blobs, as the store holds them; a blob the store does not hold counts
|
|
// nothing.
|
|
func (v *View) Bytes(blobs map[string]bool) int64 {
|
|
var n int64
|
|
for b := range blobs {
|
|
n += v.L.Blobs[b]
|
|
}
|
|
return n
|
|
}
|
|
|
|
// Total is the size of every blob the store holds.
|
|
func (v *View) Total() int64 {
|
|
var n int64
|
|
for _, s := range v.L.Blobs {
|
|
n += s
|
|
}
|
|
return n
|
|
}
|
|
|
|
// Unmarked is the bytes and count of the blobs no manifest marks, once the manifests in without are
|
|
// gone: what the nightly collector frees.
|
|
func (v *View) Unmarked(without map[string]bool) (int64, int) {
|
|
marked := v.Marked(without)
|
|
var n int64
|
|
count := 0
|
|
for b, s := range v.L.Blobs {
|
|
if !marked[b] {
|
|
n += s
|
|
count++
|
|
}
|
|
}
|
|
return n, count
|
|
}
|
|
|
|
// RepoBlobs are the blobs one repository's manifests mark.
|
|
func (v *View) RepoBlobs(name string) map[string]bool {
|
|
out := map[string]bool{}
|
|
if r := v.L.Repos[name]; r != nil {
|
|
for d := range r.Revisions {
|
|
for _, b := range v.Marks(name, d) {
|
|
out[b] = true
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Shared are the blobs that the manifests of more than one repository mark.
|
|
func (v *View) Shared() map[string]bool {
|
|
seen := map[string]string{}
|
|
shared := map[string]bool{}
|
|
for _, name := range v.L.RepoNames() {
|
|
for b := range v.RepoBlobs(name) {
|
|
if first, ok := seen[b]; ok && first != name {
|
|
shared[b] = true
|
|
} else {
|
|
seen[b] = name
|
|
}
|
|
}
|
|
}
|
|
return shared
|
|
}
|
|
|
|
// tagsOf is a repository's tags, in order, with what each names.
|
|
func tagsOf(r *Repo) []map[string]string {
|
|
names := make([]string, 0, len(r.Tags))
|
|
for t := range r.Tags {
|
|
names = append(names, t)
|
|
}
|
|
sort.Strings(names)
|
|
out := make([]map[string]string, 0, len(names))
|
|
for _, t := range names {
|
|
out = append(out, map[string]string{"tag": t, "digest": r.Tags[t]})
|
|
}
|
|
return out
|
|
}
|
|
|
|
// taggedDigests are the manifests some tag names, in one repository.
|
|
func taggedDigests(r *Repo) map[string]bool {
|
|
out := map[string]bool{}
|
|
for _, d := range r.Tags {
|
|
out[d] = true
|
|
}
|
|
return out
|
|
}
|