Skip to content

Commit

Permalink
feat: add configuration pkgs (#36)
Browse files Browse the repository at this point in the history
* feat: add configuration pkgs

* chore: rename util files, remove suffix like `_util`
  • Loading branch information
lwpk110 committed May 16, 2024
1 parent 5a0eb18 commit 6615edc
Show file tree
Hide file tree
Showing 11 changed files with 514 additions and 0 deletions.
45 changes: 45 additions & 0 deletions pkg/config/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package config

// FileContentGenerator
// we can use this interface to generate file config content in config map
// and use GenerateAllFile function to generate configMap data
type FileContentGenerator interface {
Generate() string
FileName() string
}

// EnvGenerator
// we can use this interface to generate env config in config map
// and use GenerateAllEnv function to generate configMap data
type EnvGenerator interface {
Generate() map[string]string
}

// Parser
// config content parser, can get config content by golang-template or create config content self(customize)
// see template_parser.go
type Parser interface {
Parse() (string, error)
}

func GenerateAllFile(confGenerator []FileContentGenerator) map[string]string {
data := make(map[string]string)
for _, generator := range confGenerator {
if generator.Generate() != "" {
data[generator.FileName()] = generator.Generate()
}
}
return data
}

func GenerateAllEnv(confGenerator []EnvGenerator) map[string]string {
data := make(map[string]string)
for _, generator := range confGenerator {
if generator.Generate() != nil {
for k, v := range generator.Generate() {
data[k] = v
}
}
}
return data
}
28 changes: 28 additions & 0 deletions pkg/config/template_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package config

import (
"bytes"
ctrl "sigs.k8s.io/controller-runtime"
"text/template"
)

var logging = ctrl.Log.WithName("template-parser")

type TemplateParser struct {
Value interface{}
Template string
}

func (t *TemplateParser) Parse() (string, error) {
temp, err := template.New("").Parse(t.Template)
if err != nil {
logging.Error(err, "failed to parse template", "template", t.Template)
return t.Template, err
}
var b bytes.Buffer
if err := temp.Execute(&b, t.Value); err != nil {
logging.Error(err, "failed to execute template", "template", t.Template, "data", t.Value)
return t.Template, err
}
return b.String(), nil
}
76 changes: 76 additions & 0 deletions pkg/config/template_parser_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package config

import "testing"

const log4jProperties = `log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
{{- if .LogDir}}
log4j.appender.stdout.File={{.LogDir}}/{{.LogName}}.log
{{- else}}
log4j.appender.stdout.File=logs/app.log
{{- end}}
log4j.appender.stdout.Threshold=INFO
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
{{ range .Loggers }}
log4j.logger.{{.Logger}}={{.Level}}
{{- end}}
`

func TestTemplateParser_Parse(t1 *testing.T) {
type fields struct {
Value interface{}
Template string
}
tests := []struct {
name string
fields fields
want string
wantErr bool
}{
// TODO: Add test cases.
{
name: "parse template simplely",
fields: fields{
Value: map[string]interface{}{
"LogDir": "customLogs",
"LogName": "customApp",
"Loggers": []map[string]string{
{"Logger": "test1", "Level": "WARN"},
{"Logger": "test2", "Level": "DEBUG"},
},
},
Template: log4jProperties,
},
want: `log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.File=customLogs/customApp.log
log4j.appender.stdout.Threshold=INFO
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
log4j.logger.test1=WARN
log4j.logger.test2=DEBUG
`,
wantErr: false,
},
}
for _, tt := range tests {
t1.Run(tt.name, func(t1 *testing.T) {
t := &TemplateParser{
Value: tt.fields.Value,
Template: tt.fields.Template,
}
got, err := t.Parse()
if (err != nil) != tt.wantErr {
t1.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t1.Errorf("Parse() got = %v, want %v", got, tt.want)
}
})
}
}
124 changes: 124 additions & 0 deletions pkg/util/configuration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package util

import (
"bufio"
"fmt"
"strings"
)

type NameValuePair struct {
comment string
Name string
Value string
}

// MakeConfigFileContent returns the content of a configuration file
// content such as:
// ```
// key1 value1
// key2 value2
// ```
func MakeConfigFileContent(config map[string]string) string {
content := ""
if len(config) == 0 {
return content
}
for k, v := range config {
content += fmt.Sprintf("%s %s\n", k, v)
}
return content
}

// MakePropertiesFileContent returns the content of a properties file
// content such as:
// ```properties
// key1=value1
// key2=value2
// ```
func MakePropertiesFileContent(config map[string]string) string {
content := ""
if len(config) == 0 {
return content
}
for k, v := range config {
content += fmt.Sprintf("%s=%s\n", k, v)
}
return content
}

func OverrideConfigFileContent(current string, override string) string {
if current == "" {
return override
}
if override == "" {
return current
}
return current + "\n" + override
}

// OverridePropertiesFileContent use bufio resolve properties
func OverridePropertiesFileContent(current string, override []NameValuePair) (string, error) {
var properties []NameValuePair
//scan current
if err := ScanProperties(current, &properties); err != nil {
logger.Error(err, "failed to scan current properties")
return "", err
}
// override
OverrideProperties(override, &properties)

// to string
var res string
for _, v := range properties {
res += fmt.Sprintf("%s%s=%s\n", v.comment, v.Name, v.Value)
}
return res, nil
}

func ScanProperties(current string, properties *[]NameValuePair) error {
scanner := bufio.NewScanner(strings.NewReader(current))

var comment string
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "#") || len(line) == 0 {
comment += line + "\n"
continue
}

items := strings.Split(line, "=")
if len(items) == 2 {
*properties = append(*properties, NameValuePair{
comment: comment,
Name: items[0],
Value: items[1],
})
comment = ""
} else {
return fmt.Errorf("invalid property line: %s", line)
}
}
return scanner.Err()
}

func OverrideProperties(override []NameValuePair, current *[]NameValuePair) {
if len(override) == 0 {
return
}
var currentKeys = make(map[string]int)
for i, v := range *current {
currentKeys[v.Name] = i
}

for _, v := range override {
if _, ok := currentKeys[v.Name]; ok {
(*current)[currentKeys[v.Name]].Value = v.Value // override
} else {
// append new
*current = append(*current, NameValuePair{
Name: v.Name,
Value: v.Value,
})
}
}
}
53 changes: 53 additions & 0 deletions pkg/util/configuration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package util

import (
"strings"
"testing"
)

func TestOverrideXmlFileContent(t *testing.T) {
const origin = `<?xml version="1.0"?>
<configuration>
<property>
<name>key1</name>
<value>value1</value>
</property>
</configuration>`

type args struct {
current string
override map[string]string
}
tests := []struct {
name string
args args
want string
}{
// TODO: Add test cases.
{
name: "test1",
args: args{
current: origin,
override: map[string]string{"key2": "value2"},
},
want: `<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property>
<name>key1</name>
<value>value1</value>
</property>
<property>
<name>key2</name>
<value>value2</value>
</property>
</configuration>`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := OverrideXmlContent(tt.args.current, tt.args.override); strings.TrimSpace(got) != strings.TrimSpace(tt.want) {
t.Errorf("OverrideXmlContent() = %v, want %v", got, tt.want)
}
})
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 6615edc

Please sign in to comment.