chore(kontemplate): Prepare kontemplate for depot-merge
This merge will not yet include moving over to buildGo.nix, as support for testing and such is not present in that library yet.
This commit is contained in:
parent
064f65dec2
commit
795a974665
52 changed files with 0 additions and 195 deletions
|
|
@ -1,236 +0,0 @@
|
|||
// Copyright (C) 2016-2019 Vincent Ambo <mail@tazj.in>
|
||||
//
|
||||
// This file is part of Kontemplate.
|
||||
//
|
||||
// Kontemplate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
package templater
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/Masterminds/sprig"
|
||||
"github.com/tazjin/kontemplate/context"
|
||||
"github.com/tazjin/kontemplate/util"
|
||||
)
|
||||
|
||||
const failOnMissingKeys string = "missingkey=error"
|
||||
|
||||
type RenderedResource struct {
|
||||
Filename string
|
||||
Rendered string
|
||||
}
|
||||
|
||||
type RenderedResourceSet struct {
|
||||
Name string
|
||||
Resources []RenderedResource
|
||||
Args []string
|
||||
}
|
||||
|
||||
func LoadAndApplyTemplates(include *[]string, exclude *[]string, c *context.Context) ([]RenderedResourceSet, error) {
|
||||
limitedResourceSets := applyLimits(&c.ResourceSets, include, exclude)
|
||||
renderedResourceSets := make([]RenderedResourceSet, 0)
|
||||
|
||||
if len(*limitedResourceSets) == 0 {
|
||||
return renderedResourceSets, fmt.Errorf("No valid resource sets included!")
|
||||
}
|
||||
|
||||
for _, rs := range *limitedResourceSets {
|
||||
set, err := processResourceSet(c, &rs)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
renderedResourceSets = append(renderedResourceSets, *set)
|
||||
}
|
||||
|
||||
return renderedResourceSets, nil
|
||||
}
|
||||
|
||||
func processResourceSet(ctx *context.Context, rs *context.ResourceSet) (*RenderedResourceSet, error) {
|
||||
fmt.Fprintf(os.Stderr, "Loading resources for %s\n", rs.Name)
|
||||
|
||||
fileInfo, err := os.Stat(rs.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var files []os.FileInfo
|
||||
var resources []RenderedResource
|
||||
|
||||
// Treat single-file resource paths separately from resource
|
||||
// sets containing multiple templates
|
||||
if fileInfo.IsDir() {
|
||||
// Explicitly discard this error, which will give us an empty
|
||||
// list of files instead.
|
||||
// This will end up printing a warning to the user, but it
|
||||
// won't stop the rest of the process.
|
||||
files, _ = ioutil.ReadDir(rs.Path)
|
||||
resources, err = processFiles(ctx, rs, files)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
resource, err := templateFile(ctx, rs, rs.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resources = []RenderedResource{resource}
|
||||
}
|
||||
|
||||
return &RenderedResourceSet{
|
||||
Name: rs.Name,
|
||||
Resources: resources,
|
||||
Args: rs.Args,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func processFiles(ctx *context.Context, rs *context.ResourceSet, files []os.FileInfo) ([]RenderedResource, error) {
|
||||
resources := make([]RenderedResource, 0)
|
||||
|
||||
for _, file := range files {
|
||||
if !file.IsDir() && isResourceFile(file) {
|
||||
path := path.Join(rs.Path, file.Name())
|
||||
res, err := templateFile(ctx, rs, path)
|
||||
|
||||
if err != nil {
|
||||
return resources, err
|
||||
}
|
||||
|
||||
resources = append(resources, res)
|
||||
}
|
||||
}
|
||||
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
func templateFile(ctx *context.Context, rs *context.ResourceSet, filepath string) (RenderedResource, error) {
|
||||
var resource RenderedResource
|
||||
|
||||
tpl, err := template.New(path.Base(filepath)).Funcs(templateFuncs(ctx, rs)).Option(failOnMissingKeys).ParseFiles(filepath)
|
||||
if err != nil {
|
||||
return resource, fmt.Errorf("Could not load template %s: %v", filepath, err)
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
err = tpl.Execute(&b, rs.Values)
|
||||
if err != nil {
|
||||
return resource, fmt.Errorf("Error while templating %s: %v", filepath, err)
|
||||
}
|
||||
|
||||
resource = RenderedResource{
|
||||
Filename: path.Base(filepath),
|
||||
Rendered: b.String(),
|
||||
}
|
||||
|
||||
return resource, nil
|
||||
}
|
||||
|
||||
// Applies the limits of explicitly included or excluded resources and returns the updated resource set.
|
||||
// Exclude takes priority over include
|
||||
func applyLimits(rs *[]context.ResourceSet, include *[]string, exclude *[]string) *[]context.ResourceSet {
|
||||
if len(*include) == 0 && len(*exclude) == 0 {
|
||||
return rs
|
||||
}
|
||||
|
||||
// Exclude excluded resource sets
|
||||
excluded := make([]context.ResourceSet, 0)
|
||||
for _, r := range *rs {
|
||||
if !matchesResourceSet(exclude, &r) {
|
||||
excluded = append(excluded, r)
|
||||
}
|
||||
}
|
||||
|
||||
// Include included resource sets
|
||||
if len(*include) == 0 {
|
||||
return &excluded
|
||||
}
|
||||
included := make([]context.ResourceSet, 0)
|
||||
for _, r := range excluded {
|
||||
if matchesResourceSet(include, &r) {
|
||||
included = append(included, r)
|
||||
}
|
||||
}
|
||||
|
||||
return &included
|
||||
}
|
||||
|
||||
// Check whether an include/exclude string slice matches a resource set
|
||||
func matchesResourceSet(s *[]string, rs *context.ResourceSet) bool {
|
||||
for _, r := range *s {
|
||||
r = strings.TrimSuffix(r, "/")
|
||||
if r == rs.Name || r == rs.Parent {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func templateFuncs(c *context.Context, rs *context.ResourceSet) template.FuncMap {
|
||||
m := sprig.TxtFuncMap()
|
||||
m["json"] = func(data interface{}) string {
|
||||
b, _ := json.Marshal(data)
|
||||
return string(b)
|
||||
}
|
||||
m["passLookup"] = GetFromPass
|
||||
m["gitHEAD"] = func() (string, error) {
|
||||
out, err := exec.Command("git", "-C", c.BaseDir, "rev-parse", "HEAD").Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
output := strings.TrimSpace(string(out))
|
||||
return output, nil
|
||||
}
|
||||
m["lookupIPAddr"] = GetIPsFromDNS
|
||||
m["insertFile"] = func(file string) (string, error) {
|
||||
data, err := ioutil.ReadFile(path.Join(rs.Path, file))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
}
|
||||
m["insertTemplate"] = func(file string) (string, error) {
|
||||
data, err := templateFile(c, rs, path.Join(rs.Path, file))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return data.Rendered, nil
|
||||
}
|
||||
m["default"] = func(defaultVal interface{}, varName string) interface{} {
|
||||
if val, ok := rs.Values[varName]; ok {
|
||||
return val
|
||||
}
|
||||
|
||||
return defaultVal
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Checks whether a file is a resource file (i.e. is YAML or JSON) and not a default values file.
|
||||
func isResourceFile(f os.FileInfo) bool {
|
||||
for _, defaultFile := range util.DefaultFilenames {
|
||||
if f.Name() == defaultFile {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return strings.HasSuffix(f.Name(), "yaml") ||
|
||||
strings.HasSuffix(f.Name(), "yml") ||
|
||||
strings.HasSuffix(f.Name(), "json")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue