Skip to content

Commit

Permalink
fix: add special handling for {cmd}
Browse files Browse the repository at this point in the history
  • Loading branch information
mrexox committed Dec 2, 2024
1 parent 7750ad1 commit 1ad2903
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 195 deletions.
73 changes: 0 additions & 73 deletions internal/config/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package config

import (
"errors"
"strings"

"github.com/knadh/koanf/v2"

"github.com/evilmartians/lefthook/internal/git"
"github.com/evilmartians/lefthook/internal/system"
Expand Down Expand Up @@ -34,10 +31,6 @@ type Command struct {
StageFixed bool `json:"stage_fixed,omitempty" koanf:"stage_fixed" mapstructure:"stage_fixed" toml:"stage_fixed,omitempty" yaml:"stage_fixed,omitempty"`
}

type commandRunReplace struct {
Run string `mapstructure:"run"`
}

func (c Command) Validate() error {
if !isRunnerFilesCompatible(c.Run) {
return errFilesIncompatible
Expand All @@ -54,69 +47,3 @@ func (c Command) DoSkip(state func() git.State) bool {
func (c Command) ExecutionPriority() int {
return c.Priority
}

func mergeCommands(base, extra *koanf.Koanf) (map[string]*Command, error) {
if base == nil && extra == nil {
return nil, nil
}

if base == nil {
return unmarshalCommands(extra.Cut("commands"))
}

if extra == nil {
return unmarshalCommands(base.Cut("commands"))
}

commandsOrigin := base.Cut("commands")
commandsOverride := extra.Cut("commands")
if commandsOrigin == nil {
return unmarshalCommands(commandsOverride)
}
if commandsOverride == nil {
return unmarshalCommands(commandsOrigin)
}

runReplaces := make(map[string]*commandRunReplace)
for key := range commandsOrigin.Raw() {
var replace commandRunReplace

substructure := commandsOrigin.Cut(key)
if substructure == nil {
continue
}

if err := substructure.Unmarshal("", &replace); err != nil {
return nil, err
}

runReplaces[key] = &replace
}

err := commandsOrigin.Merge(commandsOverride)
if err != nil {
return nil, err
}

commands, err := unmarshalCommands(commandsOrigin)
if err != nil {
return nil, err
}

for key, replace := range runReplaces {
if replace.Run != "" {
commands[key].Run = strings.ReplaceAll(commands[key].Run, CMD, replace.Run)
}
}

return commands, nil
}

func unmarshalCommands(k *koanf.Koanf) (map[string]*Command, error) {
commands := make(map[string]*Command)
if err := k.Unmarshal("", &commands); err != nil {
return nil, err
}

return commands, nil
}
80 changes: 40 additions & 40 deletions internal/config/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,48 @@ func addHook(name string, main, secondary *koanf.Koanf, c *Config) error {
mainHook := main.Cut(name)
overrideHook := secondary.Cut(name)

// Special merge func to support merging {cmd} templates
options := koanf.WithMergeFunc(func(src, dest map[string]interface{}) error {
// TODO: merge dest to src replacing {cmd} properly
// perf: allocate with len of src commands here
destCommands := make(map[string]string)

switch commands := dest["commands"].(type) {
case map[string]interface{}:
for cmdName, command := range commands {
switch cmd := command.(type) {
case map[string]interface{}:
switch run := cmd["run"].(type) {
case string:
destCommands[cmdName] = run
default:
}
default:
}
}
default:
}

maps.Merge(src, dest)

if len(destCommands) > 0 {
switch commands := dest["commands"].(type) {
case map[string]interface{}:
for cmdName, command := range commands {
switch cmd := command.(type) {
case map[string]interface{}:
switch run := cmd["run"].(type) {
case string:
newRun := strings.ReplaceAll(run, CMD, destCommands[cmdName])
command.(map[string]interface{})["run"] = newRun
default:
}
default:
}
}
default:
}
}

return nil
})

Expand All @@ -328,45 +367,6 @@ func addHook(name string, main, secondary *koanf.Koanf, c *Config) error {
return nil
}

// func unmarshalHook(main, override *koanf.Koanf) (*Hook, error) {
// if main == nil && override == nil {
// return nil, nil
// }

// commands, err := mergeCommands(main, override)
// if err != nil {
// return nil, err
// }

// scripts, err := mergeScripts(main, override)
// if err != nil {
// return nil, err
// }

// hook := Hook{
// Commands: commands,
// Scripts: scripts,
// }

// if main == nil {
// main = override
// } else if override != nil {
// if err = main.Merge(override); err != nil {
// return nil, err
// }
// }

// if err := main.Unmarshal("", &hook); err != nil {
// return nil, err
// }

// if tags := os.Getenv("LEFTHOOK_EXCLUDE"); tags != "" {
// hook.ExcludeTags = append(hook.ExcludeTags, strings.Split(tags, ",")...)
// }

// return &hook, nil
// }

// Rewritten from afero.NewIOFS to support opening paths starting with '/'.

type iofs struct {
Expand Down
85 changes: 3 additions & 82 deletions internal/config/script.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
package config

import (
"strings"

"github.com/knadh/koanf/v2"
"github.com/mitchellh/mapstructure"

"github.com/evilmartians/lefthook/internal/git"
"github.com/evilmartians/lefthook/internal/system"
)
Expand All @@ -25,10 +20,6 @@ type Script struct {
StageFixed bool `json:"stage_fixed,omitempty" mapstructure:"stage_fixed" toml:"stage_fixed,omitempty" yaml:"stage_fixed,omitempty"`
}

type scriptRunnerReplace struct {
Runner string `mapstructure:"runner"`
}

func (s Script) DoSkip(state func() git.State) bool {
skipChecker := NewSkipChecker(system.Cmd)
return skipChecker.check(state, s.Skip, s.Only)
Expand All @@ -38,76 +29,6 @@ func (s Script) ExecutionPriority() int {
return s.Priority
}

func mergeScripts(base, extra *koanf.Koanf) (map[string]*Script, error) {
if base == nil && extra == nil {
return nil, nil
}

if base == nil {
return unmarshalScripts(extra.Cut("scripts").Raw())
}

if extra == nil {
return unmarshalScripts(base.Cut("scripts").Raw())
}

scriptsOrigin := base.Cut("scripts").Raw()
scriptsOverride := extra.Cut("scripts").Raw()
if scriptsOrigin == nil {
return unmarshalScripts(scriptsOverride)
}
if scriptsOverride == nil {
return unmarshalScripts(scriptsOrigin)
}

runReplaces := make(map[string]*scriptRunnerReplace)
for key, originConfig := range scriptsOrigin {
var runReplace scriptRunnerReplace

if err := unmarshal(originConfig, &runReplace); err != nil {
return nil, err
}

runReplaces[key] = &runReplace
}

if err := base.Set("scripts", scriptsOverride); err != nil {
return nil, err
}

scripts, err := unmarshalScripts(base.Cut("scripts").Raw())
if err != nil {
return nil, err
}

for key, replace := range runReplaces {
if replace.Runner != "" {
scripts[key].Runner = strings.ReplaceAll(scripts[key].Runner, CMD, replace.Runner)
}
}

return scripts, nil
}

func unmarshalScripts(s map[string]interface{}) (map[string]*Script, error) {
if len(s) == 0 {
return nil, nil
}

scripts := make(map[string]*Script)
for name, scriptConfig := range s {
var script Script

if err := unmarshal(scriptConfig, &script); err != nil {
return nil, err
}

scripts[name] = &script
}

return scripts, nil
}

// `scripts` are unmarshalled manually because viper
// uses "." as a key delimiter. So, this definition:
//
Expand All @@ -132,6 +53,6 @@ func unmarshalScripts(s map[string]interface{}) (map[string]*Script, error) {
//
// This is not an expected behavior and cannot be controlled yet
// Working with GetStringMap is the only way to get the structure "as is".
func unmarshal(input, output interface{}) error {
return mapstructure.WeakDecode(input, &output)
}
// func unmarshal(input, output interface{}) error {
// return mapstructure.WeakDecode(input, &output)
// }

0 comments on commit 1ad2903

Please sign in to comment.