Files
soft_quay/core/installer/durability.go
T

100 lines
2.4 KiB
Go

package installer
import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"sort"
)
var ErrDurability = errors.New("install durability fence failed")
type durabilityFence interface {
syncFile(file *os.File) error
syncDirectory(path string) error
}
type filesystemDurability struct{}
func (filesystemDurability) syncFile(file *os.File) error {
return file.Sync()
}
func (filesystemDurability) syncDirectory(path string) error {
return syncDirectoryPath(path)
}
func defaultDurability() durabilityFence {
return filesystemDurability{}
}
func effectiveDurability(fence durabilityFence) durabilityFence {
if fence == nil {
return defaultDurability()
}
return fence
}
func syncFileWithFence(fence durabilityFence, file *os.File, description string) error {
if err := effectiveDurability(fence).syncFile(file); err != nil {
return fmt.Errorf("%w: sync %s: %v", ErrDurability, description, err)
}
return nil
}
func syncDirectoryWithFence(fence durabilityFence, path, description string) error {
if err := effectiveDurability(fence).syncDirectory(path); err != nil {
return fmt.Errorf("%w: sync %s: %v", ErrDurability, description, err)
}
return nil
}
func syncStagingTree(fence durabilityFence, root string) error {
directories := make([]string, 0)
err := filepath.WalkDir(root, func(path string, entry fs.DirEntry, err error) error {
if err != nil {
return err
}
if entry.Type()&os.ModeSymlink != 0 {
return fmt.Errorf("%w: staging tree contains a symbolic link", ErrUnsafeInstallLayout)
}
if entry.IsDir() {
directories = append(directories, path)
}
return nil
})
if err != nil {
return fmt.Errorf("%w: walk staging tree: %w", ErrDurability, err)
}
sort.Slice(directories, func(left, right int) bool {
return len(directories[left]) > len(directories[right])
})
for _, directory := range directories {
if err := syncDirectoryWithFence(fence, directory, "staging directory"); err != nil {
return err
}
}
parent := filepath.Dir(root)
if parent != root {
if err := syncDirectoryWithFence(fence, parent, "staging parent directory"); err != nil {
return err
}
}
return nil
}
func renameManagedDirectory(
layout appLayout,
source string,
target string,
fence durabilityFence,
description string,
) error {
if err := os.Rename(source, target); err != nil {
return err
}
return syncDirectoryWithFence(fence, layout.root, description)
}