engine

package
v1.0.0-beta.21....-a45bd0b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 15, 2025 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package engine provides functions to create and generate a project layout.

It contains two main functions, Initialize and Generate which split project initialization and project generation in two parts.

Initialize example:

type config struct { ... }

func main() {
	ctx := t.Context()
	destdir, _ := os.Getwd()

	config, err := engine.Initialize(ctx, destdir, engine.WithFormGroups(License))
	// handle err
}

func License(c *config) *huh.Group {
	var license bool
	return huh.NewGroup(
		huh.NewConfirm().
			Title("Would you like to specify a license (optional) ?").
			Value(&license),

		huh.NewSelect[string]().
			Title("Which one ?").
			OptionsFunc(func() []huh.Option[string] {
				if !license {
					return nil
				}
				return huh.NewOptions(licenses...)
			}, &license).
			Validate(func(s string) error {
				if s != "" {
					config.License = &s
				}
				return nil
			}),
	)
}

Generate example:

type config struct { ... }

func main() {
	ctx := t.Context()
	destdir, _ := os.Getwd()

	// run generation
	engine.SetLogger(logger)
	config, err := engine.Generate(ctx, destdir, config,
		[]engine.Parser[config]{ParserGit},
		[]engine.Generator[config]{engine.GeneratorTemplates(os.DirFS("path/to/templates"), Templates())})
	// handle err
}

func ParserGit(ctx context.Context, destdir string, config *config) error {
	vcs, err := parser.Git(destdir)
	if err != nil {
		engine.GetLogger().Warnf("failed to retrieve git vcs configuration: %v", err)
		return nil // a repository may not be a git repository
	}
	engine.GetLogger().Infof("git repository detected")

	config.VCS = vcs
	return nil
}

func Templates() []engine.Templates[config] {
	name := ".gitignore"
	return []engine.Template[config]{
		{
			Delimiters: engine.DelimitersBracket(),
			Globs:      engine.Globs(name),
			Out:        name,
			// Remove can be given to remove a specific file in some specific case instead of generating it
			Remove: func (config) bool { return false },
			// GeneratePolicy can be given to tune generation, see the appropriate documentation
			GeneratePolicy: engine.PolicyAlways,
		},
	}
}

Index

Constants

View Source
const (
	// TmplExtension is the extension for templates file.
	TmplExtension = ".tmpl"

	// PartExtension is the extension for templates files' subparts.
	//
	// It must be used with TmplExtension
	// and as such files with only templates parts (define) can be created.
	PartExtension = ".part"

	// PatchExtension is the extension for templates files patches.
	//
	// It will be used in the future to patch altered files by users to follow updates with less generation issues.
	PatchExtension = ".patch"
)

Variables

View Source
var ErrFailedGeneration = errors.New("some error(s) occurred during generation")

ErrFailedGeneration is returned when at least one file couldn't be properly generated.

Every generation error is logged during processing to avoid a big aggregated error at the end.

View Source
var ErrRequiredField = errors.New("required field")

ErrRequiredField is the error that can be used with huh.Validate(f func(string) error) to specify to the user that the field is required.

Functions

func ApplyPatches

func ApplyPatches[T any](fsys fs.FS, destdir string, tmpl Template[T], data any) error

ApplyPatches apply patches defined in input tmpl. Each patch is templatized using Go template and then patched on provided tmpl file.

It's the continuance function of ApplyTemplate (which only generates - if necessary - the initial template).

func ApplyTemplate

func ApplyTemplate[T any](fsys fs.FS, destdir string, tmpl Template[T], config T) error

ApplyTemplate writes or deletes an input Template with associated data.

func ExecuteTemplate

func ExecuteTemplate(tmpl *template.Template, data any, out string) error

ExecuteTemplate runs tmpl.ExecuteTemplate with input data and write result into given out.

When ExecuteTemplate is called, it truncates out in case it already exists and reevaluate its rights (specific to linux).

func FuncMap

func FuncMap(root string) template.FuncMap

FuncMap returns a minimal template.FuncMap.

It can be extended with MergeMaps.

func Generate

func Generate[T any](ctx context.Context, destdir string, config T, parsers []Parser[T], generators []Generator[T]) (T, error)

Generate is the main function from generate package. It takes a configuration and various options.

It executes all parsers given in options (or default ones) and then iterates over provided templates to apply or remove those.

func GlobsWithPart

func GlobsWithPart(src string) []string

GlobsWithPart returns a slice of two elements, one with src + TmplExtension and the other with a real glob, corresponding to all part files of into src template.

Example:

GlobsWithPart("path/to/file.yml") -> []string{"path/to/file.yml.tmpl", "path/to/file-*.part.tmpl"}

func Initialize

func Initialize[T any](ctx context.Context, opts ...InitializeOption[T]) (T, error)

Initialize initializes a new project an returns resulting configuration.

All user inputs are configured through WithFormGroups option, by default the main maintainer and chart generation will be asked.

func SetLogger

func SetLogger(l Logger)

SetLogger sets the global logger only if the input one is not nil.

func ShouldGenerate

func ShouldGenerate(out string, policy Policy) (bool, error)

ShouldGenerate returns true if the file should be generated.

A file is expected to be generated if:

  • it contains the generated notice
  • it does not exist
  • it is empty
  • the policy is set to PolicyAlways

Types

type Delimiters

type Delimiters struct {
	// EndDelim is the end delimiter of a go template statement, i.e. >> or }} or ]], etc.
	EndDelim string

	// StartDelim is the start delimiter of a go template statement, i.e. << or {{ or [[, etc.
	StartDelim string
}

Delimiters represents the pair of start and end delimiter for go template substitution.

func DelimitersBracket

func DelimitersBracket() Delimiters

DelimitersBracket returns go template delimiter {{ and }}.

func DelimitersChevron

func DelimitersChevron() Delimiters

DelimitersChevron returns go template delimiter << and >>.

func DelimitersSquareBracket

func DelimitersSquareBracket() Delimiters

DelimitersSquareBracket returns go template delimiter [[ and ]].

type FormGroup

type FormGroup[T any] func(config *T) *huh.Group

FormGroup is the signature function for functions reading user inputs. Inspiration can be found with ReadMaintainer and ReadChart functions.

type Generator

type Generator[T any] func(ctx context.Context, destdir string, config T) error

Generator is the function to generate a specific part of target repository.

Generators are called after all parsers were called with an aggregated configuration.

Returned error by generators is only logged to avoid a big aggregated error at the end of Generate. In case returned error is ErrFailedGeneration, then the error isn't logged, this may be used when an error must be returned by Generate but is already logged by the generator itself.

func GeneratorTemplates

func GeneratorTemplates[T any](fsys fs.FS, templates []Template[T]) Generator[T]

GeneratorTemplates is a simple generator taking as input a filesystem and all templates to apply.

Errors encountered during templates generation are logged, in that case a final error being ErrFailedGeneration is returned.

type InitializeOption

type InitializeOption[T any] func(initializeOptions[T]) initializeOptions[T]

InitializeOption represents an option to be given to Initialize function.

func WithFormGroups

func WithFormGroups[T any](inputs ...FormGroup[T]) InitializeOption[T]

WithFormGroups sets (it overrides the previously defined functions everytime it's called) the functions reading user inputs in Initialize function.

func WithTeaOptions

func WithTeaOptions[T any](opts ...tea.ProgramOption) InitializeOption[T]

WithTeaOptions sets the slice of tea.ProgramOption for huh form tuning.

type Logger

type Logger interface {
	// Debugf logs with the DEBUG level.
	Debugf(format string, args ...any)

	// Errorf logs with the ERROR level.
	Errorf(format string, args ...any)

	// Infof logs with the INFO level.
	Infof(format string, args ...any)

	// Warnf logs with the WARN level.
	Warnf(format string, args ...any)
}

Logger is a simplified interface for logging purposes.

func GetLogger

func GetLogger() Logger

GetLogger returns global logger if it exists or a noop logger.

func NewTestLogger

func NewTestLogger(writer io.Writer) Logger

NewTestLogger creates a new logger with the input writer.

This logger is expected to be used in tests. In no way it should be used in production since it's unoptimized.

type Parser

type Parser[T any] func(ctx context.Context, destdir string, config *T) error

Parser is the function to parse a specific part of target repository.

Parsers are the first functions to be executed during generation process to get as much information as possible into the configuration (that's why it's a pointer).

type Policy

type Policy int

Policy defines the policy for generating a given file.

By default, the policy is set to PolicyNone, meaning that a given file will be generated if it doesn't exist or if the notice "Code generated by [\w\-\/]+; DO NOT EDIT." is present.

const (
	// PolicyAlways always generates the file.
	PolicyAlways Policy = iota + 1

	// PolicyNone will use default behavior.
	PolicyNone
)

type Template

type Template[T any] struct {
	// Delimiters is the pair of delimiters used to parse template file(s).
	Delimiters

	// GeneratePolicy is the generation policy of the current file.
	GeneratePolicy Policy

	// Globs is the slice of globs or specific files to parse during go templating.
	//
	// It allows the current file to be split into multiple template files
	// with "define" go template statements to help readability (use Globs function to help generate globs easily).
	//
	// Note that the first element must be the raw path to main template file.
	//
	// Example:
	// 	[]string{"path/to/file.yml.tmpl", "path/to/file-*.part.tmpl"}
	Globs []string

	// Out is the output file path.
	//
	// It must be the full path to destination directory with the filename.
	Out string

	// Patches is the slice of patches to apply on the file in addition to globs.
	//
	// Patches are applied in the slice order after the initial file is generated with globs.
	// Additionally, patches are also templatized with Go template.
	//
	// A patch should have a name of the form "path/to/file.patch.tmpl" or "path/to/file.diff.tmpl"
	// (but it doesn't really matter since the name is given is the slice)
	// and should be a git diff file.
	//
	// Example:
	//
	//	diff --git a/<path/to/file> b/<path/to/file>
	//	index <some hash>..<some hash> 100644
	// 	--- a/<path/to/file>
	// 	+++ b/<path/to/file>
	// 	@@ -R,r +R,r @@
	//	+...
	//	-...
	//	+...
	//	...
	//
	// See https://en.wikipedia.org/wiki/Diff#Unified_format
	Patches []string

	// Remove function is run (if not nil) to verify whether the out file should be removed or not.
	Remove func(config T) bool
}

Template represents a template file to be parsed and generated.

Directories

Path Synopsis
Package files provides various features to read, write and validate files with JSON schema.
Package files provides various features to read, write and validate files with JSON schema.
Package generator exposes a bunch of functions to be wrapped with generate.Generator function signature.
Package generator exposes a bunch of functions to be wrapped with generate.Generator function signature.
Package parser provides a bunch of functions to be wrapped with generate.Parser function signature.
Package parser provides a bunch of functions to be wrapped with generate.Parser function signature.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL