wisski-cloud-distillery/internal/dis/component/backup.go
Tom Wiesing 3263920d6b
fsx: Remove environment references
This commit removes the reference to the environment from the fsx
package.
2023-03-02 11:51:51 +01:00

198 lines
4.9 KiB
Go

package component
import (
"context"
"io"
"path/filepath"
"github.com/FAU-CDI/wisski-distillery/internal/models"
"github.com/FAU-CDI/wisski-distillery/pkg/environment"
"github.com/FAU-CDI/wisski-distillery/pkg/fsx"
"github.com/FAU-CDI/wisski-distillery/pkg/logging"
"github.com/pkg/errors"
)
// Backupable represents a component with a Backup method
type Backupable interface {
Component
// BackupName returns a new name to be used as an argument for path.
BackupName() string
// Backup backs up this component into the destination path path
Backup(context StagingContext) error
}
// Snapshotable represents a component with a Snapshot method.
type Snapshotable interface {
Component
// SnapshotNeedsRunning returns if this Snapshotable requires a running instance.
SnapshotNeedsRunning() bool
// SnapshotName returns a new name to be used as an argument for path.
SnapshotName() string
// Snapshot snapshots a part of the instance
Snapshot(wisski models.Instance, context StagingContext) error
}
// StagingContext represents a context for [Backupable] and [Snapshotable]
type StagingContext interface {
// Progress returns a writer to write progress information to.
Progress() io.Writer
// Name creates a new directory inside the destination.
// Passing the empty path creates the destination as a directory.
//
// It then allows op to fill the file.
AddDirectory(path string, op func(context.Context) error) error
// CopyFile copies a file from src to dst.
CopyFile(dst, src string) error
// CopyDirectory copies a directory from src to dst.
CopyDirectory(dst, src string) error
// AddFile creates a new file at the provided path inside the destination.
// Passing the empty path creates the destination as a file.
//
// It then allows op to write to the file.
//
// The op function must not retain file.
// The underlying file does not need to be closed.
// AddFile will not return before op has returned.
AddFile(path string, op func(ctx context.Context, file io.Writer) error) error
}
// NewStagingContext returns a new [StagingContext]
func NewStagingContext(ctx context.Context, env environment.Environment, progress io.Writer, path string, manifest chan<- string) StagingContext {
return &stagingContext{
ctx: ctx,
env: env,
progress: progress,
path: path,
manifest: manifest,
}
}
// stagingContext implements [components.StagingContext]
type stagingContext struct {
ctx context.Context
env environment.Environment // environment
progress io.Writer // writer to direct progress to
path string // path to send files to
manifest chan<- string // channel the manifest is sent to
}
func (bc *stagingContext) sendPath(path string) {
// resolve the path, or bail out!
// TODO: Use the relative path here!
dst, err := bc.resolve(path)
if err != nil {
return
}
logging.Progress(bc.progress, bc.ctx, dst)
bc.manifest <- dst
}
func (bc *stagingContext) Progress() io.Writer {
return bc.progress
}
var errResolveAbsolute = errors.New("resolve: path must be relative")
func (bc *stagingContext) resolve(path string) (dest string, err error) {
if path == "" {
return bc.path, nil
}
if filepath.IsAbs(path) {
return "", errResolveAbsolute
}
return filepath.Join(bc.path, path), nil
}
func (sc *stagingContext) AddDirectory(path string, op func(context.Context) error) error {
// check if we are already done
if err, ok := sc.ctxdone(); ok {
return err
}
// resolve the path!
dst, err := sc.resolve(path)
if err != nil {
return err
}
// run the make directory
if err := fsx.Mkdir(dst, fsx.DefaultDirPerm); err != nil {
return err
}
// tell the files that we are creating it!
sc.sendPath(path)
// and run the files!
return op(sc.ctx)
}
func (sc *stagingContext) CopyFile(dst, src string) error {
if err, ok := sc.ctxdone(); ok {
return err
}
dstPath, err := sc.resolve(dst)
if err != nil {
return err
}
sc.sendPath(dst)
return fsx.CopyFile(sc.ctx, dstPath, src)
}
func (sc *stagingContext) CopyDirectory(dst, src string) error {
if err, ok := sc.ctxdone(); ok {
return err
}
dstPath, err := sc.resolve(dst)
if err != nil {
return err
}
return fsx.CopyDirectory(sc.ctx, dstPath, src, func(dst, src string) {
sc.sendPath(dst)
})
}
func (sc *stagingContext) AddFile(path string, op func(ctx context.Context, file io.Writer) error) error {
// check if we're already done
if err, ok := sc.ctxdone(); ok {
return err
}
// resolve the path!
dst, err := sc.resolve(path)
if err != nil {
return err
}
// create the file
file, err := fsx.Create(dst, fsx.DefaultFilePerm)
if err != nil {
return err
}
defer file.Close()
// tell them that we are creating it!
sc.sendPath(path)
// and do whatever they wanted to do
return op(sc.ctx, file)
}
func (sc *stagingContext) ctxdone() (err error, done bool) {
err = sc.ctx.Err()
done = (err != nil)
return
}