pkg/util/template.go (190 lines of code) (raw):
package util
import (
"context"
"errors"
"fmt"
"os"
"path"
"text/template"
ctrl "sigs.k8s.io/controller-runtime"
"github.com/epam/edp-codebase-operator/v2/pkg/model"
)
const (
logDirCreatedMessage = "directory is created"
logPathKey = "path"
fileLogKey = "file"
)
func CopyHelmChartTemplates(deploymentScript, templatesDest, assetsDir string, config *model.ConfigGoTemplating) error {
log.Info("start handling Helm Chart templates", logCodebaseNameKey, config.Name)
templateBasePath := path.Join(assetsDir, "templates/applications", deploymentScript, config.PlatformType)
log.Info("Paths", "templatesDest", templatesDest, "templateBasePath", templateBasePath)
err := CreateDirectory(templatesDest)
if err != nil {
return err
}
log.Info(logDirCreatedMessage, logPathKey, templateBasePath)
valuesFileName := path.Join(templatesDest, "values.yaml")
valuesFile, err := os.Create(valuesFileName)
if err != nil {
return fmt.Errorf("failed to create Values file %q: %w", valuesFileName, err)
}
log.Info("file is created", fileLogKey, valuesFileName)
chartFileName := path.Join(templatesDest, "Chart.yaml")
chartFile, err := os.Create(chartFileName)
if err != nil {
return fmt.Errorf("failed to create chart file %q: %w", chartFileName, err)
}
log.Info("file is created", fileLogKey, chartFileName)
readmeFileName := path.Join(templatesDest, "README.md")
readmeFile, err := os.Create(readmeFileName)
if err != nil {
return fmt.Errorf("failed to create chart file %q: %w", readmeFileName, err)
}
log.Info("file is created", fileLogKey, readmeFileName)
templateFolder := path.Join(templatesDest, TemplateFolder)
err = CreateDirectory(templateFolder)
if err != nil {
return err
}
log.Info(logDirCreatedMessage, logPathKey, templateFolder)
testFolder := path.Join(templatesDest, TemplateFolder, TestFolder)
err = CreateDirectory(testFolder)
if err != nil {
return err
}
log.Info(logDirCreatedMessage, logPathKey, testFolder)
templateSourceFolder := path.Join(templateBasePath, TemplateFolder)
err = CopyFiles(templateSourceFolder, templateFolder)
if err != nil {
return err
}
log.Info("files were copied", "from", templateSourceFolder, "to", templateFolder)
readmegoFileName := path.Join(templateBasePath, "README.md.gotmpl")
bytesRead, err := os.ReadFile(readmegoFileName)
if err != nil {
return fmt.Errorf("failed to read file %q: %w", readmegoFileName, err)
}
readmeFileNameCopy := path.Join(templatesDest, "README.md.gotmpl")
if err = os.WriteFile(readmeFileNameCopy, bytesRead, readWriteMode); err != nil {
return fmt.Errorf("failed to write file %q: %w", readmeFileNameCopy, err)
}
log.Info("file is copied", fileLogKey, readmeFileNameCopy)
testsSourceFolder := path.Join(templateBasePath, TemplateFolder, TestFolder)
err = CopyFiles(testsSourceFolder, testFolder)
if err != nil {
return err
}
log.Info("files were copied", "from", testsSourceFolder, "to", testFolder)
helmIgnoreSource := path.Join(templateBasePath, HelmIgnoreFile)
helmIgnoreFile := path.Join(templatesDest, HelmIgnoreFile)
err = CopyFile(helmIgnoreSource, helmIgnoreFile)
if err != nil {
return err
}
log.Info("file were copied", "from", helmIgnoreFile, "to", templatesDest)
err = renderTemplate(valuesFile, path.Join(templateBasePath, ChartValuesTemplate), ChartValuesTemplate, config)
if err != nil {
return err
}
err = renderTemplate(chartFile, path.Join(templateBasePath, ChartTemplate), ChartTemplate, config)
if err != nil {
return err
}
err = renderTemplate(readmeFile, path.Join(templateBasePath, ReadmeTemplate), ReadmeTemplate, config)
if err != nil {
return err
}
templateFolderFilesList, err := GetListFilesInDirectory(path.Join(templatesDest, TemplateFolder))
if err != nil {
return fmt.Errorf("failed to GetListFilesInDirectory: %w", err)
}
for _, file := range templateFolderFilesList {
if file.IsDir() {
continue
}
err = ReplaceStringInFile(path.Join(templatesDest, TemplateFolder, file.Name()), "REPLACE_IT", config.Name)
if err != nil {
return err
}
}
err = ReplaceStringInFile(path.Join(templatesDest, TemplateFolder, TestFolder, TestFile), "REPLACE_IT", config.Name)
if err != nil {
return err
}
log.Info("end handling Helm Chart templates", logCodebaseNameKey, config.Name)
return nil
}
func CopyRpmPackageTemplates(ctx context.Context, templatesDest, assetsDir string, config *model.ConfigGoTemplating) error {
l := ctrl.LoggerFrom(ctx)
l.Info("Start handling RPM Package templates")
// Define template paths
makefileTemplatePath := path.Join(assetsDir, "templates/applications/rpm-package/Makefile.tmpl")
rpmlintTemplatePath := path.Join(assetsDir, "templates/applications/rpm-package/.rpmlintrc.toml")
specTemplatePath := path.Join(assetsDir, fmt.Sprintf("templates/applications/rpm-package/%s/spec.tmpl", config.Lang))
serviceTemplatePath := path.Join(assetsDir, fmt.Sprintf("templates/applications/rpm-package/%s/service.tmpl", config.Lang))
if _, err := os.Stat(specTemplatePath); os.IsNotExist(err) {
specTemplatePath = path.Join(assetsDir, "templates/applications/rpm-package/default/spec.tmpl")
serviceTemplatePath = path.Join(assetsDir, "templates/applications/rpm-package/default/service.tmpl")
} else if err != nil {
return fmt.Errorf("failed to check if %q exists: %w", specTemplatePath, err)
}
// Define destination paths
makefileDestPath := path.Join(templatesDest, "Makefile")
if _, err := os.Stat(makefileDestPath); err == nil {
makefileDestPath = path.Join(templatesDest, "Makefile.kuberocketci")
}
specDestPath := path.Join(templatesDest, fmt.Sprintf("%s.spec", config.Name))
serviceDestPath := path.Join(templatesDest, fmt.Sprintf("%s.service", config.Name))
rpmlintDestPath := path.Join(templatesDest, ".rpmlintrc.toml")
// Create and render templates
if err := createAndRenderTemplate(makefileDestPath, makefileTemplatePath, "Makefile.tmpl", config); err != nil {
return err
}
if err := createAndRenderTemplate(specDestPath, specTemplatePath, "spec.tmpl", config); err != nil {
return err
}
if err := createAndRenderTemplate(serviceDestPath, serviceTemplatePath, "service.tmpl", config); err != nil {
return err
}
if err := CopyFile(rpmlintTemplatePath, rpmlintDestPath); err != nil {
return err
}
l.Info("RPM Package templates have been copied and rendered")
return nil
}
func createAndRenderTemplate(destPath, templatePath, templateName string, config *model.ConfigGoTemplating) error {
destFile, err := os.Create(destPath)
if err != nil {
return fmt.Errorf("failed to create destination file %q: %w", destPath, err)
}
defer func() {
if cerr := destFile.Close(); cerr != nil {
log.Error(cerr, "failed to close destination file", "file", destPath)
}
}()
return renderTemplate(destFile, templatePath, templateName, config)
}
func CopyTemplate(ctx context.Context, deploymentScript, workDir, assetsDir string, cf *model.ConfigGoTemplating) error {
switch deploymentScript {
case HelmChartDeploymentScriptType:
templatesDest := path.Join(workDir, "deploy-templates")
if DoesDirectoryExist(templatesDest) {
ctrl.LoggerFrom(ctx).Info("Deploy-templates folder already exists")
return nil
}
return CopyHelmChartTemplates(deploymentScript, templatesDest, assetsDir, cf)
case RpmPackageDeploymentScriptType:
return CopyRpmPackageTemplates(ctx, workDir, assetsDir, cf)
default:
return errors.New("unsupported deployment type")
}
}
func renderTemplate(file *os.File, templateBasePath, templateName string, config *model.ConfigGoTemplating) error {
log.Info("start rendering deploy template", logPathKey, templateBasePath)
tmpl, err := template.New(templateName).ParseFiles(templateBasePath)
if err != nil {
return fmt.Errorf("failed to parse codebase deploy template: %w", err)
}
if err := tmpl.Execute(file, config); err != nil {
return fmt.Errorf("failed to render codebase deploy template: %w", err)
}
log.Info("template has been rendered", "codebase", config.Name)
return nil
}