func filterExistingValues(content string, codeFragmentsMap CodeFragmentsMap) error {
	for marker, codeFragments := range codeFragmentsMap {
		codeFragmentsOut := codeFragments[:0]
		for _, codeFragment := range codeFragments {
			exists, err := codeFragmentExists(content, codeFragment)
			if err != nil {
				return err
			}
			if !exists {
				codeFragmentsOut = append(codeFragmentsOut, codeFragment)
			}
		}
		if len(codeFragmentsOut) == 0 {
			delete(codeFragmentsMap, marker)
		} else {
			codeFragmentsMap[marker] = codeFragmentsOut
		}
	}
	return nil
}
filterExistingValues removes code fragments that already exist in the content.
package machinery
import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"github.com/spf13/afero"
	"golang.org/x/tools/imports"
	"sigs.k8s.io/kubebuilder/v3/pkg/config"
	"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
)
const (
	createOrUpdate = os.O_WRONLY | os.O_CREATE | os.O_TRUNC
	defaultDirectoryPermission os.FileMode = 0700
	defaultFilePermission      os.FileMode = 0600
)
var options = imports.Options{
	Comments:   true,
	TabIndent:  true,
	TabWidth:   8,
	FormatOnly: true,
}
type Scaffold struct {
	fs afero.Fs
	dirPerm  os.FileMode
	filePerm os.FileMode
	injector injector
}
type ScaffoldOption func(*Scaffold)
func NewScaffold(fs Filesystem, options ...ScaffoldOption) *Scaffold {
	s := &Scaffold{
		fs:       fs.FS,
		dirPerm:  defaultDirectoryPermission,
		filePerm: defaultFilePermission,
	}
	for _, option := range options {
		option(s)
	}
	return s
}
func WithDirectoryPermissions(dirPerm os.FileMode) ScaffoldOption {
	return func(s *Scaffold) {
		s.dirPerm = dirPerm
	}
}
func WithFilePermissions(filePerm os.FileMode) ScaffoldOption {
	return func(s *Scaffold) {
		s.filePerm = filePerm
	}
}
func WithConfig(cfg config.Config) ScaffoldOption {
	return func(s *Scaffold) {
		s.injector.config = cfg
		if cfg != nil && cfg.GetRepository() != "" {
			imports.LocalPrefix = cfg.GetRepository()
		}
	}
}
func WithBoilerplate(boilerplate string) ScaffoldOption {
	return func(s *Scaffold) {
		s.injector.boilerplate = boilerplate
	}
}
func WithResource(resource *resource.Resource) ScaffoldOption {
	return func(s *Scaffold) {
		s.injector.resource = resource
	}
}
func (s *Scaffold) Execute(builders ...Builder) error {
	files := make(map[string]*File, len(builders))
	for _, builder := range builders {
		s.injector.injectInto(builder)
		if reqValBuilder, requiresValidation := builder.(RequiresValidation); requiresValidation {
			if err := reqValBuilder.Validate(); err != nil {
				return ValidateError{err}
			}
		}
		if t, isTemplate := builder.(Template); isTemplate {
			if err := s.buildFileModel(t, files); err != nil {
				return err
			}
		}
		if i, isInserter := builder.(Inserter); isInserter {
			if err := s.updateFileModel(i, files); err != nil {
				return err
			}
		}
	}
	for _, f := range files {
		if err := s.writeFile(f); err != nil {
			return err
		}
	}
	return nil
}
func (Scaffold) buildFileModel(t Template, models map[string]*File) error {
	if err := t.SetTemplateDefaults(); err != nil {
		return SetTemplateDefaultsError{err}
	}
	path := t.GetPath()
	if _, found := models[path]; found {
		switch t.GetIfExistsAction() {
		case SkipFile:
			return nil
		case Error:
			return ModelAlreadyExistsError{path}
		case OverwriteFile:
		default:
			return UnknownIfExistsActionError{path, t.GetIfExistsAction()}
		}
	}
	b, err := doTemplate(t)
	if err != nil {
		return err
	}
	models[path] = &File{
		Path:           path,
		Contents:       string(b),
		IfExistsAction: t.GetIfExistsAction(),
	}
	return nil
}
func doTemplate(t Template) ([]byte, error) {
	temp := template.New(fmt.Sprintf("%T", t))
	fm := DefaultFuncMap()
	if templateWithFuncMap, hasCustomFuncMap := t.(UseCustomFuncMap); hasCustomFuncMap {
		fm = templateWithFuncMap.GetFuncMap()
	}
	temp.Funcs(fm)
	if _, err := temp.Parse(t.GetBody()); err != nil {
		return nil, err
	}
	out := &bytes.Buffer{}
	if err := temp.Execute(out, t); err != nil {
		return nil, err
	}
	b := out.Bytes()
	if filepath.Ext(t.GetPath()) == ".go" {
		var err error
		if b, err = imports.Process(t.GetPath(), b, &options); err != nil {
			return nil, err
		}
	}
	return b, nil
}
func (s Scaffold) updateFileModel(i Inserter, models map[string]*File) error {
	m, err := s.loadPreviousModel(i, models)
	if err != nil {
		return err
	}
	codeFragments := getValidCodeFragments(i)
	err = filterExistingValues(m.Contents, codeFragments)
	if err != nil {
		return err
	}
	if len(codeFragments) == 0 {
		return nil
	}
	content, err := insertStrings(m.Contents, codeFragments)
	if err != nil {
		return err
	}
	formattedContent := content
	if ext := filepath.Ext(i.GetPath()); ext == ".go" {
		formattedContent, err = imports.Process(i.GetPath(), content, nil)
		if err != nil {
			return err
		}
	}
	m.Contents = string(formattedContent)
	m.IfExistsAction = OverwriteFile
	models[m.Path] = m
	return nil
}
func (s Scaffold) loadPreviousModel(i Inserter, models map[string]*File) (*File, error) {
	path := i.GetPath()
	if m, found := models[path]; found {
		exists, err := afero.Exists(s.fs, path)
		if err != nil {
			return nil, ExistsFileError{err}
		}
		if !exists {
			return m, nil
		}
		switch m.IfExistsAction {
		case SkipFile:
			fromFile, err := s.loadModelFromFile(path)
			if err != nil {
				return m, nil
			}
			return fromFile, nil
		case Error:
			return nil, FileAlreadyExistsError{path}
		case OverwriteFile:
			return m, nil
		default:
			return nil, UnknownIfExistsActionError{path, m.IfExistsAction}
		}
	}
	return s.loadModelFromFile(path)
}
func (s Scaffold) loadModelFromFile(path string) (f *File, err error) {
	reader, err := s.fs.Open(path)
	if err != nil {
		return nil, OpenFileError{err}
	}
	defer func() {
		if closeErr := reader.Close(); err == nil && closeErr != nil {
			err = CloseFileError{closeErr}
		}
	}()
	content, err := afero.ReadAll(reader)
	if err != nil {
		return nil, ReadFileError{err}
	}
	return &File{Path: path, Contents: string(content)}, nil
}
func getValidCodeFragments(i Inserter) CodeFragmentsMap {
	codeFragments := i.GetCodeFragments()
	validMarkers := i.GetMarkers()
	for marker := range codeFragments {
		valid := false
		for _, validMarker := range validMarkers {
			if marker == validMarker {
				valid = true
				break
			}
		}
		if !valid {
			delete(codeFragments, marker)
		}
	}
	return codeFragments
}