diff --git a/internal/dockerclient/docker_cli.go b/internal/dockerclient/docker_cli.go index 2abbed48..77ced399 100644 --- a/internal/dockerclient/docker_cli.go +++ b/internal/dockerclient/docker_cli.go @@ -121,10 +121,10 @@ func parseHost(addr string) (string, string, error) { func SplitDockerImage(img string) (string, string, string) { var registry, tag string repository := img - if i := strings.Index(img, "/"); i != -1 { - if first := img[:i]; strings.ContainsAny(first, ".:") || first == "localhost" { + if before, after, ok := strings.Cut(img, "/"); ok { + if first := before; strings.ContainsAny(first, ".:") || first == "localhost" { registry = first - repository = img[i+1:] + repository = after } } diff --git a/internal/generator/generator.go b/internal/generator/generator.go index 43ccd9e9..6f078d43 100644 --- a/internal/generator/generator.go +++ b/internal/generator/generator.go @@ -106,9 +106,7 @@ func (g *generator) generateFromSignals() { return } - g.wg.Add(1) - go func() { - defer g.wg.Done() + g.wg.Go(func() { sigChan, cleanup := newSignalChannel() defer cleanup() @@ -123,7 +121,7 @@ func (g *generator) generateFromSignals() { return } } - }() + }) } func (g *generator) generateFromContainers() { @@ -338,7 +336,7 @@ func (g *generator) runNotifyCmd(config config.Config) { log.Printf("Error running notify command: %s, %s\n", config.NotifyCmd, err) } if config.NotifyOutput { - for _, line := range strings.Split(string(out), "\n") { + for line := range strings.SplitSeq(string(out), "\n") { if line != "" { log.Printf("[%s]: %s", config.NotifyCmd, line) } diff --git a/internal/template/functions.go b/internal/template/functions.go index 191846d9..3677ead2 100644 --- a/internal/template/functions.go +++ b/internal/template/functions.go @@ -9,7 +9,7 @@ import ( "strings" ) -func keys(input interface{}) (interface{}, error) { +func keys(input any) (any, error) { if input == nil { return nil, nil } @@ -20,7 +20,7 @@ func keys(input interface{}) (interface{}, error) { } vk := val.MapKeys() - k := make([]interface{}, val.Len()) + k := make([]any, val.Len()) for i := range k { k[i] = vk[i].Interface() } @@ -60,7 +60,7 @@ func comment(delimiter string, source string) string { return regexPattern.ReplaceAllString(source, delimiter) } -func contains(input interface{}, key interface{}) bool { +func contains(input any, key any) bool { if input == nil { return false } @@ -104,7 +104,7 @@ func dirList(path string) ([]string, error) { } // coalesce returns the first non nil argument -func coalesce(input ...interface{}) interface{} { +func coalesce(input ...any) any { for _, v := range input { if v != nil { return v @@ -114,7 +114,7 @@ func coalesce(input ...interface{}) interface{} { } // when returns the trueValue when the condition is true and the falseValue otherwise -func when(condition bool, trueValue, falseValue interface{}) interface{} { +func when(condition bool, trueValue, falseValue any) any { if condition { return trueValue } else { diff --git a/internal/template/functions_test.go b/internal/template/functions_test.go index 66aba771..dba03152 100644 --- a/internal/template/functions_test.go +++ b/internal/template/functions_test.go @@ -47,7 +47,7 @@ func TestContainsInteger(t *testing.T) { } func TestContainsNilInput(t *testing.T) { - var env interface{} = nil + var env any = nil assert.False(t, contains(env, 0)) assert.False(t, contains(env, "")) diff --git a/internal/template/groupby.go b/internal/template/groupby.go index 6b4f988d..5ebd127e 100644 --- a/internal/template/groupby.go +++ b/internal/template/groupby.go @@ -8,14 +8,14 @@ import ( ) // Generalized groupBy function -func generalizedGroupBy(funcName string, entries interface{}, getValue func(interface{}) (interface{}, error), addEntry func(map[string][]interface{}, interface{}, interface{})) (map[string][]interface{}, error) { +func generalizedGroupBy(funcName string, entries any, getValue func(any) (any, error), addEntry func(map[string][]any, any, any)) (map[string][]any, error) { entriesVal, err := getArrayValues(funcName, entries) if err != nil { return nil, err } - groups := make(map[string][]interface{}) + groups := make(map[string][]any) for i := 0; i < entriesVal.Len(); i++ { v := entriesVal.Index(i).Interface() value, err := getValue(v) @@ -29,46 +29,46 @@ func generalizedGroupBy(funcName string, entries interface{}, getValue func(inte return groups, nil } -func generalizedGroupByKey(funcName string, entries interface{}, key string, addEntry func(map[string][]interface{}, interface{}, interface{})) (map[string][]interface{}, error) { - getKey := func(v interface{}) (interface{}, error) { +func generalizedGroupByKey(funcName string, entries any, key string, addEntry func(map[string][]any, any, any)) (map[string][]any, error) { + getKey := func(v any) (any, error) { return deepGet(v, key), nil } return generalizedGroupBy(funcName, entries, getKey, addEntry) } -func groupByMulti(entries interface{}, key, sep string) (map[string][]interface{}, error) { - return generalizedGroupByKey("groupByMulti", entries, key, func(groups map[string][]interface{}, value interface{}, v interface{}) { - items := strings.Split(value.(string), sep) - for _, item := range items { +func groupByMulti(entries any, key, sep string) (map[string][]any, error) { + return generalizedGroupByKey("groupByMulti", entries, key, func(groups map[string][]any, value any, v any) { + items := strings.SplitSeq(value.(string), sep) + for item := range items { groups[item] = append(groups[item], v) } }) } // groupBy groups a generic array or slice by the path property key -func groupBy(entries interface{}, key string) (map[string][]interface{}, error) { - return generalizedGroupByKey("groupBy", entries, key, func(groups map[string][]interface{}, value interface{}, v interface{}) { +func groupBy(entries any, key string) (map[string][]any, error) { + return generalizedGroupByKey("groupBy", entries, key, func(groups map[string][]any, value any, v any) { groups[value.(string)] = append(groups[value.(string)], v) }) } // groupByWithDefault is the same as groupBy but allows a default value to be set -func groupByWithDefault(entries interface{}, key string, defaultValue string) (map[string][]interface{}, error) { - getValueWithDefault := func(v interface{}) (interface{}, error) { +func groupByWithDefault(entries any, key string, defaultValue string) (map[string][]any, error) { + getValueWithDefault := func(v any) (any, error) { value := deepGet(v, key) if value == nil { return defaultValue, nil } return value, nil } - return generalizedGroupBy("groupByWithDefault", entries, getValueWithDefault, func(groups map[string][]interface{}, value interface{}, v interface{}) { + return generalizedGroupBy("groupByWithDefault", entries, getValueWithDefault, func(groups map[string][]any, value any, v any) { groups[value.(string)] = append(groups[value.(string)], v) }) } // groupByKeys is the same as groupBy but only returns a list of keys -func groupByKeys(entries interface{}, key string) ([]string, error) { - keys, err := generalizedGroupByKey("groupByKeys", entries, key, func(groups map[string][]interface{}, value interface{}, v interface{}) { +func groupByKeys(entries any, key string) ([]string, error) { + keys, err := generalizedGroupByKey("groupByKeys", entries, key, func(groups map[string][]any, value any, v any) { groups[value.(string)] = append(groups[value.(string)], v) }) @@ -84,8 +84,8 @@ func groupByKeys(entries interface{}, key string) ([]string, error) { } // groupByLabel is the same as groupBy but over a given label -func groupByLabel(entries interface{}, label string) (map[string][]interface{}, error) { - getLabel := func(v interface{}) (interface{}, error) { +func groupByLabel(entries any, label string) (map[string][]any, error) { + getLabel := func(v any) (any, error) { if container, ok := v.(*context.RuntimeContainer); ok { if value, ok := container.Labels[label]; ok { return value, nil @@ -94,14 +94,14 @@ func groupByLabel(entries interface{}, label string) (map[string][]interface{}, } return nil, fmt.Errorf("must pass an array or slice of *RuntimeContainer to 'groupByLabel'; received %v", v) } - return generalizedGroupBy("groupByLabel", entries, getLabel, func(groups map[string][]interface{}, value interface{}, v interface{}) { + return generalizedGroupBy("groupByLabel", entries, getLabel, func(groups map[string][]any, value any, v any) { groups[value.(string)] = append(groups[value.(string)], v) }) } // groupByLabelWithDefault is the same as groupByLabel but allows a default value to be set -func groupByLabelWithDefault(entries interface{}, label string, defaultValue string) (map[string][]interface{}, error) { - getLabel := func(v interface{}) (interface{}, error) { +func groupByLabelWithDefault(entries any, label string, defaultValue string) (map[string][]any, error) { + getLabel := func(v any) (any, error) { if container, ok := v.(*context.RuntimeContainer); ok { if value, ok := container.Labels[label]; ok { return value, nil @@ -110,7 +110,7 @@ func groupByLabelWithDefault(entries interface{}, label string, defaultValue str } return nil, fmt.Errorf("must pass an array or slice of *RuntimeContainer to 'groupByLabel'; received %v", v) } - return generalizedGroupBy("groupByLabelWithDefault", entries, getLabel, func(groups map[string][]interface{}, value interface{}, v interface{}) { + return generalizedGroupBy("groupByLabelWithDefault", entries, getLabel, func(groups map[string][]any, value any, v any) { groups[value.(string)] = append(groups[value.(string)], v) }) } diff --git a/internal/template/reflect.go b/internal/template/reflect.go index 47e76eed..d131b04e 100644 --- a/internal/template/reflect.go +++ b/internal/template/reflect.go @@ -23,7 +23,7 @@ func parseAllocateInt(desired string) (int, error) { return math.MaxInt32, nil } -func deepGetImpl(v reflect.Value, path []string) interface{} { +func deepGetImpl(v reflect.Value, path []string) any { if !v.IsValid() { return nil } @@ -81,7 +81,7 @@ func deepGetImpl(v reflect.Value, path []string) interface{} { } } -func deepGet(item interface{}, path string) interface{} { +func deepGet(item any, path string) any { var parts []string if path != "" { parts = strings.Split(strings.TrimPrefix(path, "."), ".") diff --git a/internal/template/reflect_test.go b/internal/template/reflect_test.go index dac9c4ee..64b18f93 100644 --- a/internal/template/reflect_test.go +++ b/internal/template/reflect_test.go @@ -58,9 +58,9 @@ func TestDeepGet(t *testing.T) { for _, tc := range []struct { desc string - item interface{} + item any path string - want interface{} + want any }{ { "map of string", diff --git a/internal/template/sort.go b/internal/template/sort.go index b4efd4c9..a1c101d8 100644 --- a/internal/template/sort.go +++ b/internal/template/sort.go @@ -21,15 +21,15 @@ func sortStringsDesc(values []string) []string { type sortable interface { sort.Interface - set(string, interface{}) error - get() []interface{} + set(string, any) error + get() []any } type sortableData struct { - data []interface{} + data []any } -func (s sortableData) get() []interface{} { +func (s sortableData) get() []any { return s.data } @@ -42,19 +42,19 @@ type sortableByKey struct { key string } -func (s *sortableByKey) set(funcName string, entries interface{}) (err error) { +func (s *sortableByKey) set(funcName string, entries any) (err error) { entriesVal, err := getArrayValues(funcName, entries) if err != nil { return } - s.data = make([]interface{}, entriesVal.Len()) + s.data = make([]any, entriesVal.Len()) for i := 0; i < entriesVal.Len(); i++ { s.data[i] = entriesVal.Index(i).Interface() } return } -func getFieldAsString(item interface{}, path string) string { +func getFieldAsString(item any, path string) string { // Mostly inspired by https://stackoverflow.com/a/47739620 e := deepGet(item, path) r := reflect.ValueOf(e) @@ -102,7 +102,7 @@ func (s sortableByKey) Less(i, j int) bool { } // Generalized SortBy function -func generalizedSortBy(funcName string, entries interface{}, s sortable, reverse bool) (sorted []interface{}, err error) { +func generalizedSortBy(funcName string, entries any, s sortable, reverse bool) (sorted []any, err error) { err = s.set(funcName, entries) if err != nil { return nil, err @@ -116,13 +116,13 @@ func generalizedSortBy(funcName string, entries interface{}, s sortable, reverse } // sortObjectsByKeysAsc returns a sorted array of objects, sorted by object's key field in ascending order -func sortObjectsByKeysAsc(objs interface{}, key string) ([]interface{}, error) { +func sortObjectsByKeysAsc(objs any, key string) ([]any, error) { s := &sortableByKey{key: key} return generalizedSortBy("sortObjsByKeys", objs, s, false) } // sortObjectsByKeysDesc returns a sorted array of objects, sorted by object's key field in descending order -func sortObjectsByKeysDesc(objs interface{}, key string) ([]interface{}, error) { +func sortObjectsByKeysDesc(objs any, key string) ([]any, error) { s := &sortableByKey{key: key} return generalizedSortBy("sortObjsByKey", objs, s, true) } diff --git a/internal/template/sort_test.go b/internal/template/sort_test.go index b541fcdf..8e10bb01 100644 --- a/internal/template/sort_test.go +++ b/internal/template/sort_test.go @@ -90,18 +90,18 @@ func TestSortObjectsByKeys(t *testing.T) { for _, tc := range []struct { desc string - fn func(interface{}, string) ([]interface{}, error) + fn func(any, string) ([]any, error) key string - want []interface{} + want []any }{ - {"Asc simple", sortObjectsByKeysAsc, "ID", []interface{}{o1, o2, o3, o0}}, - {"Desc simple", sortObjectsByKeysDesc, "ID", []interface{}{o0, o3, o2, o1}}, - {"Asc complex", sortObjectsByKeysAsc, "Env.VIRTUAL_HOST", []interface{}{o3, o0, o2, o1}}, - {"Desc complex", sortObjectsByKeysDesc, "Env.VIRTUAL_HOST", []interface{}{o1, o2, o0, o3}}, - {"Asc complex w/ dots in key name", sortObjectsByKeysAsc, "Labels.com.docker.compose.container_number", []interface{}{o2, o0, o3, o1}}, - {"Desc complex w/ dots in key name", sortObjectsByKeysDesc, "Labels.com.docker.compose.container_number", []interface{}{o1, o3, o0, o2}}, - {"Asc time", sortObjectsByKeysAsc, "Created", []interface{}{o3, o0, o2, o1}}, - {"Desc time", sortObjectsByKeysDesc, "Created", []interface{}{o1, o2, o0, o3}}, + {"Asc simple", sortObjectsByKeysAsc, "ID", []any{o1, o2, o3, o0}}, + {"Desc simple", sortObjectsByKeysDesc, "ID", []any{o0, o3, o2, o1}}, + {"Asc complex", sortObjectsByKeysAsc, "Env.VIRTUAL_HOST", []any{o3, o0, o2, o1}}, + {"Desc complex", sortObjectsByKeysDesc, "Env.VIRTUAL_HOST", []any{o1, o2, o0, o3}}, + {"Asc complex w/ dots in key name", sortObjectsByKeysAsc, "Labels.com.docker.compose.container_number", []any{o2, o0, o3, o1}}, + {"Desc complex w/ dots in key name", sortObjectsByKeysDesc, "Labels.com.docker.compose.container_number", []any{o1, o3, o0, o2}}, + {"Asc time", sortObjectsByKeysAsc, "Created", []any{o3, o0, o2, o1}}, + {"Desc time", sortObjectsByKeysDesc, "Created", []any{o1, o2, o0, o3}}, } { t.Run(tc.desc, func(t *testing.T) { got, err := tc.fn(containers, tc.key) diff --git a/internal/template/template.go b/internal/template/template.go index f1198ebd..8a89b27f 100644 --- a/internal/template/template.go +++ b/internal/template/template.go @@ -23,12 +23,12 @@ import ( "github.com/nginx-proxy/docker-gen/internal/utils" ) -func getArrayValues(funcName string, entries interface{}) (*reflect.Value, error) { +func getArrayValues(funcName string, entries any) (*reflect.Value, error) { entriesVal := reflect.ValueOf(entries) kind := entriesVal.Kind() - if kind == reflect.Ptr { + if kind == reflect.Pointer { entriesVal = entriesVal.Elem() kind = entriesVal.Kind() } diff --git a/internal/template/template_test.go b/internal/template/template_test.go index 3fc2805c..7f094084 100644 --- a/internal/template/template_test.go +++ b/internal/template/template_test.go @@ -13,13 +13,12 @@ import ( type templateTestList []struct { tmpl string - context interface{} - expected interface{} + context any + expected any } func (tests templateTestList) run(t *testing.T) { for n, test := range tests { - test := test t.Run(strconv.Itoa(n), func(t *testing.T) { t.Parallel() wantErr, _ := test.expected.(error) diff --git a/internal/template/where.go b/internal/template/where.go index ac95fc0f..8875d1bb 100644 --- a/internal/template/where.go +++ b/internal/template/where.go @@ -9,14 +9,14 @@ import ( ) // Generalized where function -func generalizedWhere(funcName string, entries interface{}, key string, test func(interface{}) bool) (interface{}, error) { +func generalizedWhere(funcName string, entries any, key string, test func(any) bool) (any, error) { entriesVal, err := getArrayValues(funcName, entries) if err != nil { return nil, err } - selection := make([]interface{}, 0) + selection := make([]any, 0) for i := 0; i < entriesVal.Len(); i++ { v := entriesVal.Index(i).Interface() @@ -30,36 +30,36 @@ func generalizedWhere(funcName string, entries interface{}, key string, test fun } // selects entries based on key -func where(entries interface{}, key string, cmp interface{}) (interface{}, error) { - return generalizedWhere("where", entries, key, func(value interface{}) bool { +func where(entries any, key string, cmp any) (any, error) { + return generalizedWhere("where", entries, key, func(value any) bool { return reflect.DeepEqual(value, cmp) }) } // select entries where a key is not equal to a value -func whereNot(entries interface{}, key string, cmp interface{}) (interface{}, error) { - return generalizedWhere("whereNot", entries, key, func(value interface{}) bool { +func whereNot(entries any, key string, cmp any) (any, error) { + return generalizedWhere("whereNot", entries, key, func(value any) bool { return !reflect.DeepEqual(value, cmp) }) } // selects entries where a key exists -func whereExist(entries interface{}, key string) (interface{}, error) { - return generalizedWhere("whereExist", entries, key, func(value interface{}) bool { +func whereExist(entries any, key string) (any, error) { + return generalizedWhere("whereExist", entries, key, func(value any) bool { return value != nil }) } // selects entries where a key does not exist -func whereNotExist(entries interface{}, key string) (interface{}, error) { - return generalizedWhere("whereNotExist", entries, key, func(value interface{}) bool { +func whereNotExist(entries any, key string) (any, error) { + return generalizedWhere("whereNotExist", entries, key, func(value any) bool { return value == nil }) } // selects entries based on key. Assumes key is delimited and breaks it apart before comparing -func whereAny(entries interface{}, key, sep string, cmp []string) (interface{}, error) { - return generalizedWhere("whereAny", entries, key, func(value interface{}) bool { +func whereAny(entries any, key, sep string, cmp []string) (any, error) { + return generalizedWhere("whereAny", entries, key, func(value any) bool { if value == nil { return false } else { @@ -70,9 +70,9 @@ func whereAny(entries interface{}, key, sep string, cmp []string) (interface{}, } // selects entries based on key. Assumes key is delimited and breaks it apart before comparing -func whereAll(entries interface{}, key, sep string, cmp []string) (interface{}, error) { +func whereAll(entries any, key, sep string, cmp []string) (any, error) { req_count := len(cmp) - return generalizedWhere("whereAll", entries, key, func(value interface{}) bool { + return generalizedWhere("whereAll", entries, key, func(value any) bool { if value == nil { return false } else { @@ -83,10 +83,10 @@ func whereAll(entries interface{}, key, sep string, cmp []string) (interface{}, } // generalized whereLabel function -func generalizedWhereLabel(funcName string, containers context.Context, label string, test func(string, bool) bool) (context.Context, error) { +func generalizedWhereLabel(containers context.Context, label string, test func(string, bool) bool) (context.Context, error) { selection := make([]*context.RuntimeContainer, 0) - for i := 0; i < len(containers); i++ { + for i := range containers { container := containers[i] value, ok := container.Labels[label] @@ -100,14 +100,14 @@ func generalizedWhereLabel(funcName string, containers context.Context, label st // selects containers that have a particular label func whereLabelExists(containers context.Context, label string) (context.Context, error) { - return generalizedWhereLabel("whereLabelExists", containers, label, func(_ string, ok bool) bool { + return generalizedWhereLabel(containers, label, func(_ string, ok bool) bool { return ok }) } // selects containers that have don't have a particular label func whereLabelDoesNotExist(containers context.Context, label string) (context.Context, error) { - return generalizedWhereLabel("whereLabelDoesNotExist", containers, label, func(_ string, ok bool) bool { + return generalizedWhereLabel(containers, label, func(_ string, ok bool) bool { return !ok }) } @@ -119,7 +119,7 @@ func whereLabelValueMatches(containers context.Context, label, pattern string) ( return nil, err } - return generalizedWhereLabel("whereLabelValueMatches", containers, label, func(value string, ok bool) bool { + return generalizedWhereLabel(containers, label, func(value string, ok bool) bool { return ok && rx.MatchString(value) }) } diff --git a/internal/template/yaml.go b/internal/template/yaml.go index 18a3a3c9..afa2a31c 100644 --- a/internal/template/yaml.go +++ b/internal/template/yaml.go @@ -3,26 +3,26 @@ package template import "go.yaml.in/yaml/v3" // fromYaml decodes YAML into a structured value, ignoring errors. -func fromYaml(v string) interface{} { +func fromYaml(v string) any { output, _ := mustFromYaml(v) return output } // mustFromYaml decodes YAML into a structured value, returning errors. -func mustFromYaml(v string) (interface{}, error) { - var output interface{} +func mustFromYaml(v string) (any, error) { + var output any err := yaml.Unmarshal([]byte(v), &output) return output, err } // toYaml encodes an item into a YAML string -func toYaml(v interface{}) string { +func toYaml(v any) string { output, _ := mustToYaml(v) return string(output) } // toYaml encodes an item into a YAML string, returning errors -func mustToYaml(v interface{}) (string, error) { +func mustToYaml(v any) (string, error) { output, err := yaml.Marshal(v) if err != nil { return "", err diff --git a/internal/template/yaml_test.go b/internal/template/yaml_test.go index f8e47aed..c96df45d 100644 --- a/internal/template/yaml_test.go +++ b/internal/template/yaml_test.go @@ -16,11 +16,11 @@ string: test var testJson = `{"bool":true,"list":["foo","bar"],"number":42,"string":"test"}` -var testDict = map[string]interface{}{ +var testDict = map[string]any{ "bool": true, "number": 42, "string": "test", - "list": []interface{}{ + "list": []any{ "foo", "bar", },