From b92bfb53d259b7f8acf6ec025d94f3780e859eb5 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Fri, 12 Jul 2024 20:56:58 -0700 Subject: [PATCH 1/4] update errors handling allocations and comparison Signed-off-by: Tonis Tiigi --- bake/hclparser/hclparser.go | 17 +++++++++++------ build/build.go | 5 ----- build/opt.go | 4 ++-- driver/docker/driver.go | 4 ++-- driver/driver.go | 15 ++++++++++++--- driver/kubernetes/manifest/manifest.go | 20 +++++++++++++------- 6 files changed, 40 insertions(+), 25 deletions(-) diff --git a/bake/hclparser/hclparser.go b/bake/hclparser/hclparser.go index eee3a67017c..fe7dc772dd7 100644 --- a/bake/hclparser/hclparser.go +++ b/bake/hclparser/hclparser.go @@ -75,7 +75,12 @@ type WithGetName interface { GetName(ectx *hcl.EvalContext, block *hcl.Block, loadDeps func(hcl.Expression) hcl.Diagnostics) (string, error) } -var errUndefined = errors.New("undefined") +// errUndefined is returned when a variable or function is not defined. +type errUndefined struct{} + +func (errUndefined) Error() string { + return "undefined" +} func (p *parser) loadDeps(ectx *hcl.EvalContext, exp hcl.Expression, exclude map[string]struct{}, allowMissing bool) hcl.Diagnostics { fns, hcldiags := funcCalls(exp) @@ -85,7 +90,7 @@ func (p *parser) loadDeps(ectx *hcl.EvalContext, exp hcl.Expression, exclude map for _, fn := range fns { if err := p.resolveFunction(ectx, fn); err != nil { - if allowMissing && errors.Is(err, errUndefined) { + if allowMissing && errors.Is(err, errUndefined{}) { continue } return wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr()) @@ -139,7 +144,7 @@ func (p *parser) loadDeps(ectx *hcl.EvalContext, exp hcl.Expression, exclude map } for _, block := range blocks { if err := p.resolveBlock(block, target); err != nil { - if allowMissing && errors.Is(err, errUndefined) { + if allowMissing && errors.Is(err, errUndefined{}) { continue } return wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr()) @@ -147,7 +152,7 @@ func (p *parser) loadDeps(ectx *hcl.EvalContext, exp hcl.Expression, exclude map } } else { if err := p.resolveValue(ectx, v.RootName()); err != nil { - if allowMissing && errors.Is(err, errUndefined) { + if allowMissing && errors.Is(err, errUndefined{}) { continue } return wrapErrorDiagnostic("Invalid expression", err, exp.Range().Ptr(), exp.Range().Ptr()) @@ -169,7 +174,7 @@ func (p *parser) resolveFunction(ectx *hcl.EvalContext, name string) error { } f, ok := p.funcs[name] if !ok { - return errors.Wrapf(errUndefined, "function %q does not exist", name) + return errors.Wrapf(errUndefined{}, "function %q does not exist", name) } if _, ok := p.progressF[key(ectx, name)]; ok { return errors.Errorf("function cycle not allowed for %s", name) @@ -259,7 +264,7 @@ func (p *parser) resolveValue(ectx *hcl.EvalContext, name string) (err error) { if _, builtin := p.opt.Vars[name]; !ok && !builtin { vr, ok := p.vars[name] if !ok { - return errors.Wrapf(errUndefined, "variable %q does not exist", name) + return errors.Wrapf(errUndefined{}, "variable %q does not exist", name) } def = vr.Default ectx = p.ectx diff --git a/build/build.go b/build/build.go index 34a895d4c35..3dec9588f57 100644 --- a/build/build.go +++ b/build/build.go @@ -48,11 +48,6 @@ import ( "golang.org/x/sync/errgroup" ) -var ( - errStdinConflict = errors.New("invalid argument: can't use stdin for both build context and dockerfile") - errDockerfileConflict = errors.New("ambiguous Dockerfile source: both stdin and flag correspond to Dockerfiles") -) - const ( printFallbackImage = "docker/dockerfile:1.5@sha256:dbbd5e059e8a07ff7ea6233b213b36aa516b4c53c645f1817a4dd18b83cbea56" printLintFallbackImage = "docker.io/docker/dockerfile-upstream:1.8.1@sha256:e87caa74dcb7d46cd820352bfea12591f3dba3ddc4285e19c7dcd13359f7cefd" diff --git a/build/opt.go b/build/opt.go index 0d6dfbeff3e..a830e698e5d 100644 --- a/build/opt.go +++ b/build/opt.go @@ -379,7 +379,7 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp Inputs, addVCSL target.FrontendInputs["dockerfile"] = *inp.ContextState case inp.ContextPath == "-": if inp.DockerfilePath == "-" { - return nil, errStdinConflict + return nil, errors.Errorf("invalid argument: can't use stdin for both build context and dockerfile") } buf := bufio.NewReader(inp.InStream) @@ -395,7 +395,7 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp Inputs, addVCSL target.Session = append(target.Session, up) } else { if inp.DockerfilePath != "" { - return nil, errDockerfileConflict + return nil, errors.Errorf("ambiguous Dockerfile source: both stdin and flag correspond to Dockerfiles") } // stdin is dockerfile dockerfileReader = buf diff --git a/driver/docker/driver.go b/driver/docker/driver.go index 2b1481f6e60..d9d278e7efa 100644 --- a/driver/docker/driver.go +++ b/driver/docker/driver.go @@ -29,7 +29,7 @@ func (d *Driver) Bootstrap(ctx context.Context, l progress.Logger) error { func (d *Driver) Info(ctx context.Context) (*driver.Info, error) { _, err := d.DockerAPI.ServerVersion(ctx) if err != nil { - return nil, errors.Wrapf(driver.ErrNotConnecting, err.Error()) + return nil, errors.Wrapf(driver.ErrNotConnecting{}, err.Error()) } return &driver.Info{ Status: driver.Running, @@ -39,7 +39,7 @@ func (d *Driver) Info(ctx context.Context) (*driver.Info, error) { func (d *Driver) Version(ctx context.Context) (string, error) { v, err := d.DockerAPI.ServerVersion(ctx) if err != nil { - return "", errors.Wrapf(driver.ErrNotConnecting, err.Error()) + return "", errors.Wrapf(driver.ErrNotConnecting{}, err.Error()) } if bkversion, _ := resolveBuildKitVersion(v.Version); bkversion != "" { return bkversion, nil diff --git a/driver/driver.go b/driver/driver.go index ec88f1a4eab..c82852cd8fc 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -14,8 +14,17 @@ import ( "github.com/pkg/errors" ) -var ErrNotRunning = errors.Errorf("driver not running") -var ErrNotConnecting = errors.Errorf("driver not connecting") +type ErrNotRunning struct{} + +func (ErrNotRunning) Error() string { + return "driver not running" +} + +type ErrNotConnecting struct{} + +func (ErrNotConnecting) Error() string { + return "driver not connecting" +} type Status int @@ -105,7 +114,7 @@ func Boot(ctx, clientContext context.Context, d *DriverHandle, pw progress.Write c, err := d.Client(clientContext) if err != nil { - if errors.Cause(err) == ErrNotRunning && try <= 2 { + if errors.Is(err, ErrNotRunning{}) && try <= 2 { continue } return nil, err diff --git a/driver/kubernetes/manifest/manifest.go b/driver/kubernetes/manifest/manifest.go index 7424d88edc7..1137badb7f2 100644 --- a/driver/kubernetes/manifest/manifest.go +++ b/driver/kubernetes/manifest/manifest.go @@ -7,7 +7,6 @@ import ( "github.com/docker/buildx/util/platformutil" v1 "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -53,10 +52,17 @@ const ( LabelApp = "app" ) -var ( - ErrReservedAnnotationPlatform = errors.Errorf("the annotation \"%s\" is reserved and cannot be customized", AnnotationPlatform) - ErrReservedLabelApp = errors.Errorf("the label \"%s\" is reserved and cannot be customized", LabelApp) -) +type ErrReservedAnnotationPlatform struct{} + +func (ErrReservedAnnotationPlatform) Error() string { + return fmt.Sprintf("the annotation %q is reserved and cannot be customized", AnnotationPlatform) +} + +type ErrReservedLabelApp struct{} + +func (ErrReservedLabelApp) Error() string { + return fmt.Sprintf("the label %q is reserved and cannot be customized", LabelApp) +} func NewDeployment(opt *DeploymentOpt) (d *appsv1.Deployment, c []*corev1.ConfigMap, err error) { labels := map[string]string{ @@ -73,14 +79,14 @@ func NewDeployment(opt *DeploymentOpt) (d *appsv1.Deployment, c []*corev1.Config for k, v := range opt.CustomAnnotations { if k == AnnotationPlatform { - return nil, nil, ErrReservedAnnotationPlatform + return nil, nil, ErrReservedAnnotationPlatform{} } annotations[k] = v } for k, v := range opt.CustomLabels { if k == LabelApp { - return nil, nil, ErrReservedLabelApp + return nil, nil, ErrReservedLabelApp{} } labels[k] = v } From 85cf3bace9b13782963be13c19d691fd3e8b95c6 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 15 Jul 2024 13:35:04 -0700 Subject: [PATCH 2/4] hclparser: avoid unnecessary allocations in init Signed-off-by: Tonis Tiigi --- bake/hclparser/stdlib.go | 306 ++++++++++++++++++---------------- bake/hclparser/stdlib_test.go | 2 +- 2 files changed, 161 insertions(+), 147 deletions(-) diff --git a/bake/hclparser/stdlib.go b/bake/hclparser/stdlib.go index e0cd9b5f661..bbe4a748bb5 100644 --- a/bake/hclparser/stdlib.go +++ b/bake/hclparser/stdlib.go @@ -1,6 +1,7 @@ package hclparser import ( + "errors" "time" "github.com/hashicorp/go-cty-funcs/cidr" @@ -9,174 +10,187 @@ import ( "github.com/hashicorp/go-cty-funcs/uuid" "github.com/hashicorp/hcl/v2/ext/tryfunc" "github.com/hashicorp/hcl/v2/ext/typeexpr" - "github.com/pkg/errors" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" "github.com/zclconf/go-cty/cty/function/stdlib" ) -var stdlibFunctions = map[string]function.Function{ - "absolute": stdlib.AbsoluteFunc, - "add": stdlib.AddFunc, - "and": stdlib.AndFunc, - "base64decode": encoding.Base64DecodeFunc, - "base64encode": encoding.Base64EncodeFunc, - "bcrypt": crypto.BcryptFunc, - "byteslen": stdlib.BytesLenFunc, - "bytesslice": stdlib.BytesSliceFunc, - "can": tryfunc.CanFunc, - "ceil": stdlib.CeilFunc, - "chomp": stdlib.ChompFunc, - "chunklist": stdlib.ChunklistFunc, - "cidrhost": cidr.HostFunc, - "cidrnetmask": cidr.NetmaskFunc, - "cidrsubnet": cidr.SubnetFunc, - "cidrsubnets": cidr.SubnetsFunc, - "coalesce": stdlib.CoalesceFunc, - "coalescelist": stdlib.CoalesceListFunc, - "compact": stdlib.CompactFunc, - "concat": stdlib.ConcatFunc, - "contains": stdlib.ContainsFunc, - "convert": typeexpr.ConvertFunc, - "csvdecode": stdlib.CSVDecodeFunc, - "distinct": stdlib.DistinctFunc, - "divide": stdlib.DivideFunc, - "element": stdlib.ElementFunc, - "equal": stdlib.EqualFunc, - "flatten": stdlib.FlattenFunc, - "floor": stdlib.FloorFunc, - "format": stdlib.FormatFunc, - "formatdate": stdlib.FormatDateFunc, - "formatlist": stdlib.FormatListFunc, - "greaterthan": stdlib.GreaterThanFunc, - "greaterthanorequalto": stdlib.GreaterThanOrEqualToFunc, - "hasindex": stdlib.HasIndexFunc, - "indent": stdlib.IndentFunc, - "index": stdlib.IndexFunc, - "indexof": indexOfFunc, - "int": stdlib.IntFunc, - "join": stdlib.JoinFunc, - "jsondecode": stdlib.JSONDecodeFunc, - "jsonencode": stdlib.JSONEncodeFunc, - "keys": stdlib.KeysFunc, - "length": stdlib.LengthFunc, - "lessthan": stdlib.LessThanFunc, - "lessthanorequalto": stdlib.LessThanOrEqualToFunc, - "log": stdlib.LogFunc, - "lookup": stdlib.LookupFunc, - "lower": stdlib.LowerFunc, - "max": stdlib.MaxFunc, - "md5": crypto.Md5Func, - "merge": stdlib.MergeFunc, - "min": stdlib.MinFunc, - "modulo": stdlib.ModuloFunc, - "multiply": stdlib.MultiplyFunc, - "negate": stdlib.NegateFunc, - "not": stdlib.NotFunc, - "notequal": stdlib.NotEqualFunc, - "or": stdlib.OrFunc, - "parseint": stdlib.ParseIntFunc, - "pow": stdlib.PowFunc, - "range": stdlib.RangeFunc, - "regex_replace": stdlib.RegexReplaceFunc, - "regex": stdlib.RegexFunc, - "regexall": stdlib.RegexAllFunc, - "replace": stdlib.ReplaceFunc, - "reverse": stdlib.ReverseFunc, - "reverselist": stdlib.ReverseListFunc, - "rsadecrypt": crypto.RsaDecryptFunc, - "sethaselement": stdlib.SetHasElementFunc, - "setintersection": stdlib.SetIntersectionFunc, - "setproduct": stdlib.SetProductFunc, - "setsubtract": stdlib.SetSubtractFunc, - "setsymmetricdifference": stdlib.SetSymmetricDifferenceFunc, - "setunion": stdlib.SetUnionFunc, - "sha1": crypto.Sha1Func, - "sha256": crypto.Sha256Func, - "sha512": crypto.Sha512Func, - "signum": stdlib.SignumFunc, - "slice": stdlib.SliceFunc, - "sort": stdlib.SortFunc, - "split": stdlib.SplitFunc, - "strlen": stdlib.StrlenFunc, - "substr": stdlib.SubstrFunc, - "subtract": stdlib.SubtractFunc, - "timeadd": stdlib.TimeAddFunc, - "timestamp": timestampFunc, - "title": stdlib.TitleFunc, - "trim": stdlib.TrimFunc, - "trimprefix": stdlib.TrimPrefixFunc, - "trimspace": stdlib.TrimSpaceFunc, - "trimsuffix": stdlib.TrimSuffixFunc, - "try": tryfunc.TryFunc, - "upper": stdlib.UpperFunc, - "urlencode": encoding.URLEncodeFunc, - "uuidv4": uuid.V4Func, - "uuidv5": uuid.V5Func, - "values": stdlib.ValuesFunc, - "zipmap": stdlib.ZipmapFunc, +type funcDef struct { + name string + fn function.Function + factory func() function.Function +} + +var stdlibFunctions = []funcDef{ + {name: "absolute", fn: stdlib.AbsoluteFunc}, + {name: "add", fn: stdlib.AddFunc}, + {name: "and", fn: stdlib.AndFunc}, + {name: "base64decode", fn: encoding.Base64DecodeFunc}, + {name: "base64encode", fn: encoding.Base64EncodeFunc}, + {name: "bcrypt", fn: crypto.BcryptFunc}, + {name: "byteslen", fn: stdlib.BytesLenFunc}, + {name: "bytesslice", fn: stdlib.BytesSliceFunc}, + {name: "can", fn: tryfunc.CanFunc}, + {name: "ceil", fn: stdlib.CeilFunc}, + {name: "chomp", fn: stdlib.ChompFunc}, + {name: "chunklist", fn: stdlib.ChunklistFunc}, + {name: "cidrhost", fn: cidr.HostFunc}, + {name: "cidrnetmask", fn: cidr.NetmaskFunc}, + {name: "cidrsubnet", fn: cidr.SubnetFunc}, + {name: "cidrsubnets", fn: cidr.SubnetsFunc}, + {name: "coalesce", fn: stdlib.CoalesceFunc}, + {name: "coalescelist", fn: stdlib.CoalesceListFunc}, + {name: "compact", fn: stdlib.CompactFunc}, + {name: "concat", fn: stdlib.ConcatFunc}, + {name: "contains", fn: stdlib.ContainsFunc}, + {name: "convert", fn: typeexpr.ConvertFunc}, + {name: "csvdecode", fn: stdlib.CSVDecodeFunc}, + {name: "distinct", fn: stdlib.DistinctFunc}, + {name: "divide", fn: stdlib.DivideFunc}, + {name: "element", fn: stdlib.ElementFunc}, + {name: "equal", fn: stdlib.EqualFunc}, + {name: "flatten", fn: stdlib.FlattenFunc}, + {name: "floor", fn: stdlib.FloorFunc}, + {name: "format", fn: stdlib.FormatFunc}, + {name: "formatdate", fn: stdlib.FormatDateFunc}, + {name: "formatlist", fn: stdlib.FormatListFunc}, + {name: "greaterthan", fn: stdlib.GreaterThanFunc}, + {name: "greaterthanorequalto", fn: stdlib.GreaterThanOrEqualToFunc}, + {name: "hasindex", fn: stdlib.HasIndexFunc}, + {name: "indent", fn: stdlib.IndentFunc}, + {name: "index", fn: stdlib.IndexFunc}, + {name: "indexof", factory: indexOfFunc}, + {name: "int", fn: stdlib.IntFunc}, + {name: "join", fn: stdlib.JoinFunc}, + {name: "jsondecode", fn: stdlib.JSONDecodeFunc}, + {name: "jsonencode", fn: stdlib.JSONEncodeFunc}, + {name: "keys", fn: stdlib.KeysFunc}, + {name: "length", fn: stdlib.LengthFunc}, + {name: "lessthan", fn: stdlib.LessThanFunc}, + {name: "lessthanorequalto", fn: stdlib.LessThanOrEqualToFunc}, + {name: "log", fn: stdlib.LogFunc}, + {name: "lookup", fn: stdlib.LookupFunc}, + {name: "lower", fn: stdlib.LowerFunc}, + {name: "max", fn: stdlib.MaxFunc}, + {name: "md5", fn: crypto.Md5Func}, + {name: "merge", fn: stdlib.MergeFunc}, + {name: "min", fn: stdlib.MinFunc}, + {name: "modulo", fn: stdlib.ModuloFunc}, + {name: "multiply", fn: stdlib.MultiplyFunc}, + {name: "negate", fn: stdlib.NegateFunc}, + {name: "not", fn: stdlib.NotFunc}, + {name: "notequal", fn: stdlib.NotEqualFunc}, + {name: "or", fn: stdlib.OrFunc}, + {name: "parseint", fn: stdlib.ParseIntFunc}, + {name: "pow", fn: stdlib.PowFunc}, + {name: "range", fn: stdlib.RangeFunc}, + {name: "regex_replace", fn: stdlib.RegexReplaceFunc}, + {name: "regex", fn: stdlib.RegexFunc}, + {name: "regexall", fn: stdlib.RegexAllFunc}, + {name: "replace", fn: stdlib.ReplaceFunc}, + {name: "reverse", fn: stdlib.ReverseFunc}, + {name: "reverselist", fn: stdlib.ReverseListFunc}, + {name: "rsadecrypt", fn: crypto.RsaDecryptFunc}, + {name: "sethaselement", fn: stdlib.SetHasElementFunc}, + {name: "setintersection", fn: stdlib.SetIntersectionFunc}, + {name: "setproduct", fn: stdlib.SetProductFunc}, + {name: "setsubtract", fn: stdlib.SetSubtractFunc}, + {name: "setsymmetricdifference", fn: stdlib.SetSymmetricDifferenceFunc}, + {name: "setunion", fn: stdlib.SetUnionFunc}, + {name: "sha1", fn: crypto.Sha1Func}, + {name: "sha256", fn: crypto.Sha256Func}, + {name: "sha512", fn: crypto.Sha512Func}, + {name: "signum", fn: stdlib.SignumFunc}, + {name: "slice", fn: stdlib.SliceFunc}, + {name: "sort", fn: stdlib.SortFunc}, + {name: "split", fn: stdlib.SplitFunc}, + {name: "strlen", fn: stdlib.StrlenFunc}, + {name: "substr", fn: stdlib.SubstrFunc}, + {name: "subtract", fn: stdlib.SubtractFunc}, + {name: "timeadd", fn: stdlib.TimeAddFunc}, + {name: "timestamp", factory: timestampFunc}, + {name: "title", fn: stdlib.TitleFunc}, + {name: "trim", fn: stdlib.TrimFunc}, + {name: "trimprefix", fn: stdlib.TrimPrefixFunc}, + {name: "trimspace", fn: stdlib.TrimSpaceFunc}, + {name: "trimsuffix", fn: stdlib.TrimSuffixFunc}, + {name: "try", fn: tryfunc.TryFunc}, + {name: "upper", fn: stdlib.UpperFunc}, + {name: "urlencode", fn: encoding.URLEncodeFunc}, + {name: "uuidv4", fn: uuid.V4Func}, + {name: "uuidv5", fn: uuid.V5Func}, + {name: "values", fn: stdlib.ValuesFunc}, + {name: "zipmap", fn: stdlib.ZipmapFunc}, } // indexOfFunc constructs a function that finds the element index for a given // value in a list. -var indexOfFunc = function.New(&function.Spec{ - Params: []function.Parameter{ - { - Name: "list", - Type: cty.DynamicPseudoType, - }, - { - Name: "value", - Type: cty.DynamicPseudoType, +func indexOfFunc() function.Function { + return function.New(&function.Spec{ + Params: []function.Parameter{ + { + Name: "list", + Type: cty.DynamicPseudoType, + }, + { + Name: "value", + Type: cty.DynamicPseudoType, + }, }, - }, - Type: function.StaticReturnType(cty.Number), - Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { - if !(args[0].Type().IsListType() || args[0].Type().IsTupleType()) { - return cty.NilVal, errors.New("argument must be a list or tuple") - } - - if !args[0].IsKnown() { - return cty.UnknownVal(cty.Number), nil - } - - if args[0].LengthInt() == 0 { // Easy path - return cty.NilVal, errors.New("cannot search an empty list") - } - - for it := args[0].ElementIterator(); it.Next(); { - i, v := it.Element() - eq, err := stdlib.Equal(v, args[1]) - if err != nil { - return cty.NilVal, err + Type: function.StaticReturnType(cty.Number), + Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { + if !(args[0].Type().IsListType() || args[0].Type().IsTupleType()) { + return cty.NilVal, errors.New("argument must be a list or tuple") } - if !eq.IsKnown() { + + if !args[0].IsKnown() { return cty.UnknownVal(cty.Number), nil } - if eq.True() { - return i, nil + + if args[0].LengthInt() == 0 { // Easy path + return cty.NilVal, errors.New("cannot search an empty list") } - } - return cty.NilVal, errors.New("item not found") - }, -}) + for it := args[0].ElementIterator(); it.Next(); { + i, v := it.Element() + eq, err := stdlib.Equal(v, args[1]) + if err != nil { + return cty.NilVal, err + } + if !eq.IsKnown() { + return cty.UnknownVal(cty.Number), nil + } + if eq.True() { + return i, nil + } + } + return cty.NilVal, errors.New("item not found") + + }, + }) +} // timestampFunc constructs a function that returns a string representation of the current date and time. // // This function was imported from terraform's datetime utilities. -var timestampFunc = function.New(&function.Spec{ - Params: []function.Parameter{}, - Type: function.StaticReturnType(cty.String), - Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { - return cty.StringVal(time.Now().UTC().Format(time.RFC3339)), nil - }, -}) +func timestampFunc() function.Function { + return function.New(&function.Spec{ + Params: []function.Parameter{}, + Type: function.StaticReturnType(cty.String), + Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { + return cty.StringVal(time.Now().UTC().Format(time.RFC3339)), nil + }, + }) +} func Stdlib() map[string]function.Function { funcs := make(map[string]function.Function, len(stdlibFunctions)) - for k, v := range stdlibFunctions { - funcs[k] = v + for _, v := range stdlibFunctions { + if v.factory != nil { + funcs[v.name] = v.factory() + } else { + funcs[v.name] = v.fn + } } return funcs } diff --git a/bake/hclparser/stdlib_test.go b/bake/hclparser/stdlib_test.go index df2336cee9d..4c933f7488c 100644 --- a/bake/hclparser/stdlib_test.go +++ b/bake/hclparser/stdlib_test.go @@ -34,7 +34,7 @@ func TestIndexOf(t *testing.T) { for name, test := range tests { name, test := name, test t.Run(name, func(t *testing.T) { - got, err := indexOfFunc.Call([]cty.Value{test.input, test.key}) + got, err := indexOfFunc().Call([]cty.Value{test.input, test.key}) if err != nil { if test.wantErr { return From 52bb668085b2db89fda8cc211028324e0217edf7 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 15 Jul 2024 13:36:28 -0700 Subject: [PATCH 3/4] remoteutil: fix pkg remove unnecessary map initialization Signed-off-by: Tonis Tiigi --- driver/remote/util/dialer_unix.go | 2 +- driver/remote/util/dialer_windows.go | 2 +- driver/remote/util/endpoint.go | 19 ++++++++++--------- driver/remote/util/endpoint_test.go | 12 ++++++++++++ 4 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 driver/remote/util/endpoint_test.go diff --git a/driver/remote/util/dialer_unix.go b/driver/remote/util/dialer_unix.go index dd3c95dfe59..307663179f9 100644 --- a/driver/remote/util/dialer_unix.go +++ b/driver/remote/util/dialer_unix.go @@ -1,7 +1,7 @@ //go:build !windows // +build !windows -package remote +package remoteutil import ( "context" diff --git a/driver/remote/util/dialer_windows.go b/driver/remote/util/dialer_windows.go index c48c8f5501a..f5d4b9218b3 100644 --- a/driver/remote/util/dialer_windows.go +++ b/driver/remote/util/dialer_windows.go @@ -1,4 +1,4 @@ -package remote +package remoteutil import ( "context" diff --git a/driver/remote/util/endpoint.go b/driver/remote/util/endpoint.go index 53a6510d0bf..c8a72c56f6a 100644 --- a/driver/remote/util/endpoint.go +++ b/driver/remote/util/endpoint.go @@ -1,18 +1,19 @@ -package remote +package remoteutil import ( "net/url" + "slices" "github.com/pkg/errors" ) -var schemes = map[string]struct{}{ - "tcp": {}, - "unix": {}, - "ssh": {}, - "docker-container": {}, - "kube-pod": {}, - "npipe": {}, +var schemes = []string{ + "docker-container", + "kube-pod", + "npipe", + "ssh", + "tcp", + "unix", } func IsValidEndpoint(ep string) error { @@ -20,7 +21,7 @@ func IsValidEndpoint(ep string) error { if err != nil { return errors.Wrapf(err, "failed to parse endpoint %s", ep) } - if _, ok := schemes[endpoint.Scheme]; !ok { + if _, ok := slices.BinarySearch(schemes, endpoint.Scheme); !ok { return errors.Errorf("unrecognized url scheme %s", endpoint.Scheme) } return nil diff --git a/driver/remote/util/endpoint_test.go b/driver/remote/util/endpoint_test.go new file mode 100644 index 00000000000..0360e05011c --- /dev/null +++ b/driver/remote/util/endpoint_test.go @@ -0,0 +1,12 @@ +package remoteutil + +import ( + "slices" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSchemes(t *testing.T) { + require.True(t, slices.IsSorted(schemes)) +} From 96509847b9614dad6fdbc20fad1330c03bf8cade Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 15 Jul 2024 15:45:09 -0700 Subject: [PATCH 4/4] remote: avoid signal names map on init Signed-off-by: Tonis Tiigi --- controller/remote/io.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/controller/remote/io.go b/controller/remote/io.go index 6a8c59c31af..6b8f7646687 100644 --- a/controller/remote/io.go +++ b/controller/remote/io.go @@ -207,6 +207,7 @@ func attachIO(ctx context.Context, stream msgStream, initMessage *pb.InitMessage if cfg.signal != nil { eg.Go(func() error { + names := signalNames() for { var sig syscall.Signal select { @@ -216,7 +217,7 @@ func attachIO(ctx context.Context, stream msgStream, initMessage *pb.InitMessage case <-ctx.Done(): return nil } - name := sigToName[sig] + name := names[sig] if name == "" { continue } @@ -380,12 +381,12 @@ func copyToStream(fd uint32, snd msgStream, r io.Reader) error { }) } -var sigToName = map[syscall.Signal]string{} - -func init() { +func signalNames() map[syscall.Signal]string { + m := make(map[syscall.Signal]string, len(signal.SignalMap)) for name, value := range signal.SignalMap { - sigToName[value] = name + m[value] = name } + return m } type debugStream struct {