Add source bundle validation and inspection
This commit is contained in:
82
internal/bundle/discover.go
Normal file
82
internal/bundle/discover.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package bundle
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"gitea.maximumdirect.net/eric/distributor/internal/storage"
|
||||
)
|
||||
|
||||
func Discover(ctx context.Context, backend storage.Backend, sourceRoot string) ([]Bundle, error) {
|
||||
if err := storage.ValidatePrefix(sourceRoot); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries, err := storage.List(ctx, backend, sourceRoot, storage.WalkOptions{Recursive: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var roots []string
|
||||
for _, entry := range entries {
|
||||
if entry.Type == storage.EntryTypeDirectory {
|
||||
continue
|
||||
}
|
||||
if path.Base(entry.Path) == ManifestName {
|
||||
roots = append(roots, path.Dir(entry.Path))
|
||||
}
|
||||
}
|
||||
for index, root := range roots {
|
||||
if root == "." {
|
||||
roots[index] = ""
|
||||
}
|
||||
}
|
||||
sort.Strings(roots)
|
||||
if len(roots) == 0 {
|
||||
return nil, fmt.Errorf("no bundles found under %q", displayRoot(sourceRoot))
|
||||
}
|
||||
if err := rejectNestedRoots(roots); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bundles := make([]Bundle, 0, len(roots))
|
||||
for _, root := range roots {
|
||||
relativeRoot := relativeToSource(sourceRoot, root)
|
||||
sourceBundle, err := validateAt(ctx, backend, root, relativeRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bundles = append(bundles, sourceBundle)
|
||||
}
|
||||
return bundles, nil
|
||||
}
|
||||
|
||||
func rejectNestedRoots(roots []string) error {
|
||||
for index, root := range roots {
|
||||
for _, candidate := range roots[index+1:] {
|
||||
if isAncestor(root, candidate) {
|
||||
return fmt.Errorf("nested manifest %q under bundle %q", displayRoot(candidate), displayRoot(root))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isAncestor(root, candidate string) bool {
|
||||
if root == "" {
|
||||
return candidate != ""
|
||||
}
|
||||
return strings.HasPrefix(candidate, root+"/")
|
||||
}
|
||||
|
||||
func relativeToSource(sourceRoot, bundleRoot string) string {
|
||||
if sourceRoot == "" {
|
||||
return bundleRoot
|
||||
}
|
||||
if bundleRoot == sourceRoot {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimPrefix(bundleRoot, sourceRoot+"/")
|
||||
}
|
||||
Reference in New Issue
Block a user