118 lines
3.2 KiB
Go
118 lines
3.2 KiB
Go
package component
|
|
|
|
import (
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/FAU-CDI/wisski-distillery/internal/fsx"
|
|
"github.com/FAU-CDI/wisski-distillery/internal/unpack"
|
|
"github.com/pkg/errors"
|
|
"github.com/tkw1536/goprogram/stream"
|
|
)
|
|
|
|
// TODO: Move this package into components
|
|
|
|
// Installable represents a Stack that can be automatically installed from a set of resources
|
|
// See the [Install] method.
|
|
type Installable struct {
|
|
Stack
|
|
|
|
// Installable enabled installing several resources from a (potentially embedded) filesystem.
|
|
//
|
|
// The Resources holds these, with appropriate resources specified below.
|
|
// These all refer to paths within the Resource filesystem.
|
|
Resources fs.FS
|
|
ContextPath string // the 'docker compose' stack context, containing e.g. 'docker-compose.yml'.
|
|
EnvPath string // the '.env' template, will be installed using [unpack.InstallTemplate].
|
|
EnvContext map[string]string // context when instantiating the '.env' template
|
|
|
|
CopyContextFiles []string // Files to copy from the installation context
|
|
|
|
MakeDirsPerm fs.FileMode // permission for diretories, defaults to fs.ModeDir
|
|
MakeDirs []string // directories to ensure that exist
|
|
|
|
TouchFiles []string // Files to 'touch', i.e. ensure that exist; guaranteed to be run after MakeDirs
|
|
}
|
|
|
|
// InstallationContext is a context to install data in
|
|
type InstallationContext map[string]string
|
|
|
|
// Install installs or updates this stack into the directory specified by stack.Stack().
|
|
//
|
|
// Installation is non-interactive, but will provide debugging output onto io.
|
|
// InstallationContext
|
|
func (is Installable) Install(io stream.IOStream, context InstallationContext) error {
|
|
if is.ContextPath != "" {
|
|
// setup the base files
|
|
if err := unpack.InstallDir(
|
|
is.Dir,
|
|
is.ContextPath,
|
|
is.Resources,
|
|
func(dst, src string) {
|
|
io.Printf("[install] %s\n", dst)
|
|
},
|
|
); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// configure .env
|
|
envDest := filepath.Join(is.Dir, ".env")
|
|
if is.EnvPath != "" && is.EnvContext != nil {
|
|
io.Printf("[config] %s\n", envDest)
|
|
if err := unpack.InstallTemplate(
|
|
envDest,
|
|
is.EnvContext,
|
|
is.EnvPath,
|
|
is.Resources,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// make sure that certain dirs exist
|
|
for _, name := range is.MakeDirs {
|
|
// find the destination!
|
|
dst := filepath.Join(is.Dir, name)
|
|
|
|
io.Printf("[make] %s\n", dst)
|
|
if is.MakeDirsPerm == fs.FileMode(0) {
|
|
is.MakeDirsPerm = fs.ModeDir
|
|
}
|
|
if err := os.MkdirAll(dst, is.MakeDirsPerm); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// copy files from the context!
|
|
for _, name := range is.CopyContextFiles {
|
|
// find the source!
|
|
src, ok := context[name]
|
|
if !ok {
|
|
return errors.Errorf("Missing file from context: %s", src)
|
|
}
|
|
|
|
// find the destination!
|
|
dst := filepath.Join(is.Dir, name)
|
|
|
|
// copy over file from context
|
|
io.Printf("[copy] %s (from %s)\n", dst, src)
|
|
if err := fsx.CopyFile(dst, src); err != nil {
|
|
return errors.Wrapf(err, "Unable to copy file %s", src)
|
|
}
|
|
}
|
|
|
|
// make sure that certain files exist
|
|
for _, name := range is.TouchFiles {
|
|
// find the destination!
|
|
dst := filepath.Join(is.Dir, name)
|
|
|
|
io.Printf("[touch] %s\n", dst)
|
|
if err := fsx.Touch(dst); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|