delivery.NamedTree hashes the manifest digest with each named path's git object; catalogue.Manifest.NamedPaths gives the union of the paths, only when every artifact names some. The named: prefix keeps the value apart from a git tree id.
48 lines
2.2 KiB
Go
48 lines
2.2 KiB
Go
package delivery
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"path"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// NamedTreePrefix opens the tree input of a module whose every artifact names its paths, so such a value is never read
|
|
// as a git tree id and a reader of a kept Tree can tell the two apart.
|
|
const NamedTreePrefix = "named:"
|
|
|
|
// NamedTree is the tree input of the new-form fingerprint of a module whose every artifact names the paths it is built
|
|
// from (novox/hq ADR 0499 clause 2): `named:` and the hex sha256 of the lines "manifest <digest>" and, sorted,
|
|
// "path <path> <object>", joined by a newline. manifest is the module's ManifestDigest (the sha256 of its module.json's
|
|
// exact bytes, as Module.Manifest and the merge preview carry it); paths are the named paths, each clean and relative to
|
|
// the module's directory as the manifest names them (catalogue.Manifest.NamedPaths), with the git object id each has at
|
|
// the commit (a blob for a file, a tree for a directory).
|
|
//
|
|
// **One function computes it** (clause 2): the indexer, its merge preview (buildstep.ModuleTrees) and the build modules
|
|
// call this one, and no second computation exists. It refuses no path, a named path with no object (absent at the
|
|
// commit), a path that is not clean, and a manifest that is not a digest, naming them: the indexer then gives the
|
|
// module none, with that reason (clause 3).
|
|
func NamedTree(manifest string, paths map[string]string) (string, error) {
|
|
if _, err := ManifestsKey(manifest); err != nil {
|
|
return "", err
|
|
}
|
|
if len(paths) == 0 {
|
|
return "", fmt.Errorf("delivery: the module names no path, so it has no named tree")
|
|
}
|
|
lines := make([]string, 0, len(paths))
|
|
for p, object := range paths {
|
|
if p == "" || p != path.Clean(p) || strings.HasPrefix(p, "/") || p == ".." || strings.HasPrefix(p, "../") {
|
|
return "", fmt.Errorf("delivery: the named path %q is not a clean path inside the module's directory", p)
|
|
}
|
|
if object == "" {
|
|
return "", fmt.Errorf("delivery: the named path %q has no git object at the commit", p)
|
|
}
|
|
lines = append(lines, "path "+p+" "+object)
|
|
}
|
|
sort.Strings(lines)
|
|
sum := sha256.Sum256([]byte("manifest " + manifest + "\n" + strings.Join(lines, "\n")))
|
|
return NamedTreePrefix + hex.EncodeToString(sum[:]), nil
|
|
}
|