Implement shared-root publish execution

This commit is contained in:
2026-06-08 19:02:12 +00:00
parent 89169f810f
commit 9afb3550c4
16 changed files with 541 additions and 52 deletions

View File

@@ -29,6 +29,7 @@ type Backend interface {
Stat(ctx context.Context, path string) (Entry, error)
Walk(ctx context.Context, prefix string, opts WalkOptions, fn WalkFunc) error
HasAny(ctx context.Context, prefix string) (bool, error)
DeleteManagedOutputs(ctx context.Context, bundlePath string, managedOutputPaths []string, opts DeleteOptions) error
DeleteManagedBundle(ctx context.Context, bundlePath string, managedOutputPaths []string, opts DeleteOptions) error
DeletePrefix(ctx context.Context, prefix string, opts DeleteOptions) error
}

View File

@@ -20,18 +20,19 @@ const (
)
const (
OpValidatePath = "validate path"
OpReadFile = "read file"
OpOpenReader = "open reader"
OpWriteFile = "write file"
OpWriteFrom = "write stream"
OpStat = "stat"
OpWalk = "walk"
OpHasAny = "has any"
OpDeleteManagedBundle = "delete managed bundle"
OpDeletePrefix = "delete prefix"
OpRegisterBackend = "register backend"
OpOpenBackend = "open backend"
OpValidatePath = "validate path"
OpReadFile = "read file"
OpOpenReader = "open reader"
OpWriteFile = "write file"
OpWriteFrom = "write stream"
OpStat = "stat"
OpWalk = "walk"
OpHasAny = "has any"
OpDeleteManagedOutputs = "delete managed outputs"
OpDeleteManagedBundle = "delete managed bundle"
OpDeletePrefix = "delete prefix"
OpRegisterBackend = "register backend"
OpOpenBackend = "open backend"
)
type Error struct {

View File

@@ -159,23 +159,35 @@ func (b *Backend) HasAny(ctx context.Context, prefix string) (bool, error) {
}
func (b *Backend) DeleteManagedBundle(ctx context.Context, bundlePath string, managedOutputPaths []string, opts storage.DeleteOptions) error {
return b.deleteManagedTargets(ctx, storage.OpDeleteManagedBundle, func() ([]string, error) {
return storage.ManagedBundleTargets(bundlePath, managedOutputPaths)
}, opts)
}
func (b *Backend) DeleteManagedOutputs(ctx context.Context, bundlePath string, managedOutputPaths []string, opts storage.DeleteOptions) error {
return b.deleteManagedTargets(ctx, storage.OpDeleteManagedOutputs, func() ([]string, error) {
return storage.ManagedOutputTargets(bundlePath, managedOutputPaths)
}, opts)
}
func (b *Backend) deleteManagedTargets(ctx context.Context, op string, targetsFunc func() ([]string, error), opts storage.DeleteOptions) error {
if err := ctx.Err(); err != nil {
return err
}
targets, err := storage.ManagedBundleTargets(bundlePath, managedOutputPaths)
targets, err := targetsFunc()
if err != nil {
return err
}
for _, target := range targets {
if _, ok := b.dirs[target]; ok {
return storage.NewError(storage.OpDeleteManagedBundle, backendName, target, storage.ErrUnsupported, nil)
return storage.NewError(op, backendName, target, storage.ErrUnsupported, nil)
}
if !b.exists(target) {
if opts.IgnoreMissing {
continue
}
return storage.NewError(storage.OpDeleteManagedBundle, backendName, target, storage.ErrNotFound, nil)
return storage.NewError(op, backendName, target, storage.ErrNotFound, nil)
}
delete(b.files, target)
delete(b.symlinks, target)

View File

@@ -50,10 +50,23 @@ func DisplayPath(path string) string {
}
func ManagedBundleTargets(bundlePath string, managedOutputPaths []string) ([]string, error) {
targets, err := ManagedOutputTargets(bundlePath, managedOutputPaths)
if err != nil {
return nil, err
}
statePath, err := StatePath(bundlePath)
if err != nil {
return nil, err
}
targets = append(targets, statePath)
return targets, nil
}
func ManagedOutputTargets(bundlePath string, managedOutputPaths []string) ([]string, error) {
if err := ValidatePrefix(bundlePath); err != nil {
return nil, err
}
targets := make([]string, 0, len(managedOutputPaths)+1)
targets := make([]string, 0, len(managedOutputPaths))
for _, outputPath := range managedOutputPaths {
target, err := Join(bundlePath, outputPath)
if err != nil {
@@ -61,11 +74,6 @@ func ManagedBundleTargets(bundlePath string, managedOutputPaths []string) ([]str
}
targets = append(targets, target)
}
statePath, err := StatePath(bundlePath)
if err != nil {
return nil, err
}
targets = append(targets, statePath)
return targets, nil
}

View File

@@ -132,6 +132,22 @@ func TestManagedBundleTargetsRejectsInvalidOutputPath(t *testing.T) {
}
}
func TestManagedOutputTargetsOmitsStateFile(t *testing.T) {
targets, err := ManagedOutputTargets("bundle", []string{"report.md", "nested/report.html"})
if err != nil {
t.Fatalf("ManagedOutputTargets() error = %v", err)
}
want := []string{"bundle/report.md", "bundle/nested/report.html"}
if len(targets) != len(want) {
t.Fatalf("targets = %v, want %v", targets, want)
}
for index := range want {
if targets[index] != want[index] {
t.Fatalf("targets = %v, want %v", targets, want)
}
}
}
func TestListSortsEntries(t *testing.T) {
backend := walkBackend{
entries: []Entry{
@@ -215,6 +231,10 @@ func (b walkBackend) DeleteManagedBundle(context.Context, string, []string, Dele
return nil
}
func (b walkBackend) DeleteManagedOutputs(context.Context, string, []string, DeleteOptions) error {
return nil
}
func (b walkBackend) DeletePrefix(context.Context, string, DeleteOptions) error {
return nil
}