83 lines
1.9 KiB
Go
83 lines
1.9 KiB
Go
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", storage.DisplayPath(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", storage.DisplayPath(candidate), storage.DisplayPath(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+"/")
|
|
}
|