Skip to content

Commit

Permalink
chore: code improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
levkohimins committed Dec 27, 2024
1 parent 0bca787 commit c07d4fe
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 151 deletions.
110 changes: 105 additions & 5 deletions pkg/log/format/options/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,23 @@ package options

import (
"reflect"
"strings"
"unicode"

"github.com/gruntwork-io/terragrunt/internal/errors"
"github.com/gruntwork-io/terragrunt/pkg/log"
)

// Constants for parsing options.
const (
OptNameValueSep = "="
OptSep = ","
OptStartSign = "("
OptEndSign = ")"
)

const splitIntoNameAndValue = 2

// OptionValue contains the value of the option.
type OptionValue[T any] interface {
// Parse parses and sets the value of the option.
Expand All @@ -20,7 +33,7 @@ type Option interface {
// Name returns the name of the option.
Name() string
// Format formats the given string.
Format(data *Data, val any) (any, error)
Format(data *Data, str any) (any, error)
// ParseValue parses and sets the value of the option.
ParseValue(str string) error
}
Expand Down Expand Up @@ -76,15 +89,102 @@ func (opts Options) Merge(withOpts ...Option) Options {
}

// Format returns the formatted value.
func (opts Options) Format(data *Data, val any) (string, error) {
func (opts Options) Format(data *Data, str any) (string, error) {
var err error

for _, opt := range opts {
val, err = opt.Format(data, val)
if val == "" || err != nil {
str, err = opt.Format(data, str)
if str == "" || err != nil {
return "", err
}
}

return toString(val), nil
return toString(str), nil
}

// Parse parsers the given `str` to configure the `opts` and returns the offset index.
func (opts Options) Parse(str string) (string, error) {
str, ok := isNext(str)
if !ok {
return str, nil
}

parts := strings.SplitN(str, OptNameValueSep, splitIntoNameAndValue)
if len(parts) != splitIntoNameAndValue {
return "", errors.Errorf("invalid option %q", str)
}

name := strings.TrimSpace(parts[0])
if name == "" {
return "", errors.New("empty option name")
}

opt := opts.Get(name)
if opt == nil {
return "", errors.Errorf("invalid option name %q, available names: %s", name, strings.Join(opts.Names(), ","))
}

str = parts[1]

var quoted byte

for index := range str {
// Skip quoted text, e.g. `%(content='level()')`.
if isQuoted(str[:index], &quoted) {
continue
}

if !strings.HasSuffix(str[:index+1], OptSep) && !strings.HasSuffix(str[:index+1], OptEndSign) {
continue
}

val := strings.TrimSpace(str[:index])
val = strings.Trim(val, "'")
val = strings.Trim(val, "\"")

if err := opt.ParseValue(val); err != nil {
return "", errors.Errorf("invalid value %q for option %q: %w", val, opt.Name(), err)
}

return opts.Parse(OptStartSign + str[index:])
}

return "", errors.Errorf("invalid option %q", str)
}

func isNext(str string) (string, bool) {
if len(str) == 0 || !strings.HasPrefix(str, OptStartSign) {
return str, false
}

str = strings.TrimLeftFunc(str[1:], unicode.IsSpace)

switch {
case strings.HasPrefix(str, OptEndSign):
return str[1:], false
case strings.HasPrefix(str, OptSep):
return str[1:], true
}

return str, true
}

func isQuoted(str string, quoted *byte) bool {
strlen := len(str)

if strlen == 0 {
return false
}

char := str[strlen-1]

if char == '"' || char == '\'' {
if *quoted == 0 {
*quoted = char
} else if *quoted == char && (strlen < 2 || str[strlen-2] != '\\') {
*quoted = 0
}
}

return *quoted != 0
}
13 changes: 3 additions & 10 deletions pkg/log/format/placeholders/common.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package placeholders

import (
"strings"

"github.com/gruntwork-io/terragrunt/internal/errors"
"github.com/gruntwork-io/terragrunt/pkg/log/format/options"
)

Expand Down Expand Up @@ -39,13 +36,9 @@ func (common *CommonPlaceholder) Name() string {
return common.name
}

// GetOption implements `Placeholder` interface.
func (common *CommonPlaceholder) GetOption(str string) (options.Option, error) {
if opt := common.opts.Get(str); opt != nil {
return opt, nil
}

return nil, errors.Errorf("available values: %s", strings.Join(common.opts.Names(), ","))
// Options implements `Placeholder` interface.
func (common *CommonPlaceholder) Options() options.Options {
return common.opts
}

// Format implements `Placeholder` interface.
Expand Down
Loading

0 comments on commit c07d4fe

Please sign in to comment.