pkg/tasks/template/fs.go (77 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package template
import (
"context"
"fmt"
"io/fs"
"github.com/psanford/memfs"
"github.com/elastic/harp/pkg/sdk/fsutil"
"github.com/elastic/harp/pkg/template/engine"
)
// FileSystemTask implements filesystem template rendering task.
type FileSystemTask struct {
InputPath string
OutputPath string
ValueFiles []string
SecretLoaders []string
Values []string
StringValues []string
FileValues []string
LeftDelims string
RightDelims string
AltDelims bool
FileLoaderRootPath string
DryRun bool
}
// Run the task.
//
//nolint:revive // refactor use of ctx
func (t *FileSystemTask) Run(ctx context.Context) error {
// Prepare input filesystem
inFS, err := fsutil.From(t.InputPath)
if err != nil {
return fmt.Errorf("unable to prepare input filesystem: %w", err)
}
// Prepare embedded files
var (
fileRootFS fs.FS
)
if t.FileLoaderRootPath != "" {
var errRootFS error
fileRootFS, errRootFS = fsutil.From(t.FileLoaderRootPath)
if errRootFS != nil {
return fmt.Errorf("unable load files filesystem: %w", errRootFS)
}
}
// Prepare render context
renderCtx, err := prepareRenderContext(&renderContextConfig{
ValueFiles: t.ValueFiles,
SecretLoaders: t.SecretLoaders,
Values: t.Values,
StringValues: t.StringValues,
FileValues: t.FileValues,
LeftDelims: t.LeftDelims,
RightDelims: t.RightDelims,
AltDelims: t.AltDelims,
FileRootPath: fileRootFS,
})
if err != nil {
return fmt.Errorf("unable to prepare rendering context: %w", err)
}
// Memory filesystem
outFs := memfs.New()
// Generate all files from input filesystem.
if err := fs.WalkDir(inFS, ".", func(path string, d fs.DirEntry, errWalk error) error {
if errWalk != nil {
return errWalk
}
if d.IsDir() {
return outFs.MkdirAll(path, 0o755)
}
// Get file content.
body, err := fs.ReadFile(inFS, path)
if err != nil {
return fmt.Errorf("unable to retrieve file content %q: %w", path, err)
}
// Compile and execute template
out, err := engine.RenderContext(renderCtx, string(body))
if err != nil {
return fmt.Errorf("unable to produce output content for file %q: %w", path, err)
}
// Create output file.
return outFs.WriteFile(path, []byte(out), 0o444)
}); err != nil {
return fmt.Errorf("unable to render filesytem: %w", err)
}
// Skip copy if no output is defined.
if t.DryRun || t.OutputPath == "" {
return nil
}
// Dump filesystem
return fsutil.Dump(outFs, t.OutputPath)
}