From 0554ddf3eefff09196141d79be1ecaeb9b93fcbf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 07:53:17 +0000 Subject: [PATCH] Bump sigs.k8s.io/node-feature-discovery from 0.16.6 to 0.17.2 in /tests Bumps [sigs.k8s.io/node-feature-discovery](https://github.com/kubernetes-sigs/node-feature-discovery) from 0.16.6 to 0.17.2. - [Release notes](https://github.com/kubernetes-sigs/node-feature-discovery/releases) - [Commits](https://github.com/kubernetes-sigs/node-feature-discovery/compare/v0.16.6...v0.17.2) --- updated-dependencies: - dependency-name: sigs.k8s.io/node-feature-discovery dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tests/go.mod | 43 +- tests/go.sum | 100 +- .../blang/semver/v4}/LICENSE | 5 +- .../vendor/github.com/blang/semver/v4/json.go | 23 + .../github.com/blang/semver/v4/range.go | 416 +++ .../github.com/blang/semver/v4/semver.go | 476 ++++ .../vendor/github.com/blang/semver/v4/sort.go | 28 + .../vendor/github.com/blang/semver/v4/sql.go | 30 + .../cyphar/filepath-securejoin/CHANGELOG.md | 186 ++ .../cyphar/filepath-securejoin/LICENSE | 2 +- .../cyphar/filepath-securejoin/README.md | 140 +- .../cyphar/filepath-securejoin/VERSION | 2 +- .../cyphar/filepath-securejoin/doc.go | 39 + .../cyphar/filepath-securejoin/join.go | 104 +- .../filepath-securejoin/lookup_linux.go | 389 +++ .../cyphar/filepath-securejoin/mkdir_linux.go | 212 ++ .../cyphar/filepath-securejoin/open_linux.go | 103 + .../filepath-securejoin/openat2_linux.go | 128 + .../filepath-securejoin/openat_linux.go | 59 + .../filepath-securejoin/procfs_linux.go | 440 +++ .../cyphar/filepath-securejoin/vfs.go | 26 +- .../distribution/reference/README.md | 2 +- .../distribution/reference/normalize.go | 59 +- .../distribution/reference/reference.go | 44 +- .../image-spec/specs-go/version.go | 2 +- .../go.opentelemetry.io/otel/.golangci.yml | 13 +- .../go.opentelemetry.io/otel/CHANGELOG.md | 121 +- .../go.opentelemetry.io/otel/CODEOWNERS | 6 +- .../go.opentelemetry.io/otel/CONTRIBUTING.md | 18 +- .../vendor/go.opentelemetry.io/otel/Makefile | 22 +- .../vendor/go.opentelemetry.io/otel/README.md | 34 +- .../go.opentelemetry.io/otel/RELEASING.md | 12 +- .../go.opentelemetry.io/otel/attribute/set.go | 40 +- .../otel/baggage/baggage.go | 150 +- .../go.opentelemetry.io/otel/codes/codes.go | 2 +- tests/vendor/go.opentelemetry.io/otel/doc.go | 2 + .../otel/internal/global/meter.go | 317 ++- .../otel/internal/rawhelpers.go | 12 +- .../otel/metric/asyncfloat64.go | 2 +- .../otel/metric/asyncint64.go | 2 +- .../otel/metric/instrument.go | 2 +- .../go.opentelemetry.io/otel/metric/meter.go | 13 + .../go.opentelemetry.io/otel/renovate.json | 8 + .../go.opentelemetry.io/otel/trace/context.go | 2 +- .../go.opentelemetry.io/otel/trace/doc.go | 2 +- .../otel/trace/provider.go | 59 + .../go.opentelemetry.io/otel/trace/span.go | 177 ++ .../go.opentelemetry.io/otel/trace/trace.go | 249 -- .../go.opentelemetry.io/otel/trace/tracer.go | 37 + .../otel/trace/tracestate.go | 10 + .../otel/verify_examples.sh | 74 - .../otel/verify_released_changelog.sh | 42 + .../go.opentelemetry.io/otel/version.go | 2 +- .../go.opentelemetry.io/otel/versions.yaml | 10 +- tests/vendor/go.starlark.net/LICENSE | 29 - .../internal/compile/compile.go | 1927 ------------- .../internal/compile/serial.go | 399 --- .../go.starlark.net/internal/spell/spell.go | 115 - .../vendor/go.starlark.net/resolve/binding.go | 74 - .../vendor/go.starlark.net/resolve/resolve.go | 981 ------- .../vendor/go.starlark.net/starlark/debug.go | 42 - tests/vendor/go.starlark.net/starlark/empty.s | 3 - tests/vendor/go.starlark.net/starlark/eval.go | 1672 ----------- .../go.starlark.net/starlark/hashtable.go | 442 --- tests/vendor/go.starlark.net/starlark/int.go | 459 --- .../go.starlark.net/starlark/int_generic.go | 33 - .../go.starlark.net/starlark/int_posix64.go | 89 - .../vendor/go.starlark.net/starlark/interp.go | 704 ----- .../go.starlark.net/starlark/library.go | 2455 ----------------- .../go.starlark.net/starlark/profile.go | 449 --- .../vendor/go.starlark.net/starlark/unpack.go | 355 --- .../vendor/go.starlark.net/starlark/value.go | 1613 ----------- .../go.starlark.net/starlarkstruct/module.go | 43 - .../go.starlark.net/starlarkstruct/struct.go | 282 -- .../vendor/go.starlark.net/syntax/grammar.txt | 129 - .../vendor/go.starlark.net/syntax/options.go | 63 - tests/vendor/go.starlark.net/syntax/parse.go | 1057 ------- tests/vendor/go.starlark.net/syntax/quote.go | 309 --- tests/vendor/go.starlark.net/syntax/scan.go | 1124 -------- tests/vendor/go.starlark.net/syntax/syntax.go | 529 ---- tests/vendor/go.starlark.net/syntax/walk.go | 161 -- .../grpc/grpclog/component.go | 10 +- .../google.golang.org/grpc/grpclog/grpclog.go | 104 +- .../grpc/grpclog/internal/grpclog.go | 26 + .../grpc/grpclog/internal/logger.go | 87 + .../grpc/grpclog/internal/loggerv2.go | 267 ++ .../google.golang.org/grpc/grpclog/logger.go | 59 +- .../grpc/grpclog/loggerv2.go | 181 +- .../grpc/internal/experimental.go | 8 +- .../grpc/internal/grpclog/grpclog.go | 126 - .../grpc/internal/grpclog/prefixLogger.go | 93 - .../grpc/internal/internal.go | 52 +- .../grpc/internal/status/status.go | 39 +- .../grpc/internal/tcp_keepalive_unix.go | 2 +- .../grpc/internal/tcp_keepalive_windows.go | 2 +- .../gopkg.in/evanphx/json-patch.v5/.gitignore | 6 - .../gopkg.in/evanphx/json-patch.v5/LICENSE | 25 - .../gopkg.in/evanphx/json-patch.v5/README.md | 317 --- .../gopkg.in/evanphx/json-patch.v5/errors.go | 38 - .../gopkg.in/evanphx/json-patch.v5/merge.go | 389 --- .../gopkg.in/evanphx/json-patch.v5/patch.go | 851 ------ .../genericclioptions/builder_flags_fake.go | 19 +- .../pkg/genericclioptions/record_flags.go | 2 +- .../k8s.io/cli-runtime/pkg/printers/json.go | 5 +- .../cli-runtime/pkg/printers/jsonpath.go | 3 +- .../k8s.io/cli-runtime/pkg/printers/name.go | 3 +- .../cli-runtime/pkg/printers/template.go | 3 +- .../k8s.io/cli-runtime/pkg/printers/yaml.go | 5 +- .../cli-runtime/pkg/resource/builder.go | 4 +- .../pkg/resource/query_param_verifier.go | 2 +- .../k8s.io/kubectl/pkg/cmd/util/helpers.go | 19 +- .../pkg/util/i18n/translations/README.md | 2 +- .../kubectl/ja_JP/LC_MESSAGES/k8s.po | 2 +- .../pkg/util/templates/help_flags_printer.go | 2 +- tests/vendor/modules.txt | 80 +- .../kustomize/api/filters/nameref/nameref.go | 9 +- .../filters/patchjson6902/patchjson6902.go | 2 +- .../accumulator/loadconfigfromcrds.go | 2 +- .../builtins/HelmChartInflationGenerator.go | 42 +- .../builtins/PatchJson6902Transformer.go | 2 +- .../api/internal/builtins/PatchTransformer.go | 2 +- .../internal/builtins/SortOrderTransformer.go | 56 +- .../builtinpluginconsts/namereference.go | 7 + .../builtinconfig/loaddefaultconfig.go | 2 +- .../builtinconfig/transformerconfig.go | 17 +- .../internal/plugins/execplugin/execplugin.go | 26 +- .../api/internal/plugins/fnplugin/fnplugin.go | 1 - .../internal/plugins/loader/load_go_plugin.go | 62 + .../plugins/loader/load_go_plugin_disabled.go | 25 + .../api/internal/plugins/loader/loader.go | 47 - .../api/internal/target/kusttarget.go | 14 +- .../target/kusttarget_configplugin.go | 29 +- .../api/internal/utils/errtimeout.go | 6 +- .../kustomize/api/provenance/provenance.go | 35 + .../kustomize/api/resource/factory.go | 21 +- .../kustomize/api/resource/resource.go | 25 +- .../kustomize/api/types/helmchartargs.go | 6 + .../kustomize/api/types/kustomization.go | 2 + .../sigs.k8s.io/kustomize/api/types/labels.go | 4 +- .../kustomize/api/types/pluginconfig.go | 2 +- .../kustomize/api/types/pluginrestrictions.go | 2 - .../kyaml/fn/runtime/container/container.go | 2 +- .../fn/runtime/runtimeutil/functiontypes.go | 14 - .../kyaml/fn/runtime/starlark/context.go | 79 - .../kyaml/fn/runtime/starlark/doc.go | 36 - .../kyaml/fn/runtime/starlark/starlark.go | 180 -- .../github.com/qri-io/starlib/util/doc.go | 25 - .../github.com/qri-io/starlib/util/util.go | 275 -- .../kustomize/kyaml/kio/filters/filters.go | 210 -- .../kustomize/kyaml/kio/filters/fmtr.go | 314 --- .../kustomize/kyaml/kio/filters/grep.go | 117 - .../kustomize/kyaml/kio/filters/local.go | 38 - .../kustomize/kyaml/kio/filters/merge.go | 86 - .../kustomize/kyaml/kio/filters/merge3.go | 317 --- .../kustomize/kyaml/kio/filters/modify.go | 4 - .../kyaml/kio/filters/stripcomments.go | 32 - .../kustomize/kyaml/kio/ignorefilesmatcher.go | 2 +- .../kyaml/openapi/kustomizationapi/swagger.go | 2 +- .../kustomize/kyaml/openapi/openapi.go | 2 +- .../kustomize/kyaml/runfn/runfn.go | 41 - .../sigs.k8s.io/kustomize/kyaml/yaml/alias.go | 2 +- .../sigs.k8s.io/kustomize/kyaml/yaml/fns.go | 10 +- .../kustomize/kyaml/yaml/merge2/merge2.go | 5 +- .../kustomize/kyaml/yaml/merge3/merge3.go | 45 - .../kustomize/kyaml/yaml/merge3/visitor.go | 172 -- .../sigs.k8s.io/kustomize/kyaml/yaml/rnode.go | 17 + .../clientset/versioned/clientset.go | 4 +- .../typed/nfd/v1alpha1/nfd_client.go | 10 +- .../typed/nfd/v1alpha1/nodefeature.go | 144 +- .../typed/nfd/v1alpha1/nodefeaturegroup.go | 163 +- .../typed/nfd/v1alpha1/nodefeaturerule.go | 134 +- 171 files changed, 4809 insertions(+), 20990 deletions(-) rename tests/vendor/{sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util => github.com/blang/semver/v4}/LICENSE (92%) create mode 100644 tests/vendor/github.com/blang/semver/v4/json.go create mode 100644 tests/vendor/github.com/blang/semver/v4/range.go create mode 100644 tests/vendor/github.com/blang/semver/v4/semver.go create mode 100644 tests/vendor/github.com/blang/semver/v4/sort.go create mode 100644 tests/vendor/github.com/blang/semver/v4/sql.go create mode 100644 tests/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md create mode 100644 tests/vendor/github.com/cyphar/filepath-securejoin/doc.go create mode 100644 tests/vendor/github.com/cyphar/filepath-securejoin/lookup_linux.go create mode 100644 tests/vendor/github.com/cyphar/filepath-securejoin/mkdir_linux.go create mode 100644 tests/vendor/github.com/cyphar/filepath-securejoin/open_linux.go create mode 100644 tests/vendor/github.com/cyphar/filepath-securejoin/openat2_linux.go create mode 100644 tests/vendor/github.com/cyphar/filepath-securejoin/openat_linux.go create mode 100644 tests/vendor/github.com/cyphar/filepath-securejoin/procfs_linux.go create mode 100644 tests/vendor/go.opentelemetry.io/otel/trace/provider.go create mode 100644 tests/vendor/go.opentelemetry.io/otel/trace/span.go create mode 100644 tests/vendor/go.opentelemetry.io/otel/trace/tracer.go delete mode 100644 tests/vendor/go.opentelemetry.io/otel/verify_examples.sh create mode 100644 tests/vendor/go.opentelemetry.io/otel/verify_released_changelog.sh delete mode 100644 tests/vendor/go.starlark.net/LICENSE delete mode 100644 tests/vendor/go.starlark.net/internal/compile/compile.go delete mode 100644 tests/vendor/go.starlark.net/internal/compile/serial.go delete mode 100644 tests/vendor/go.starlark.net/internal/spell/spell.go delete mode 100644 tests/vendor/go.starlark.net/resolve/binding.go delete mode 100644 tests/vendor/go.starlark.net/resolve/resolve.go delete mode 100644 tests/vendor/go.starlark.net/starlark/debug.go delete mode 100644 tests/vendor/go.starlark.net/starlark/empty.s delete mode 100644 tests/vendor/go.starlark.net/starlark/eval.go delete mode 100644 tests/vendor/go.starlark.net/starlark/hashtable.go delete mode 100644 tests/vendor/go.starlark.net/starlark/int.go delete mode 100644 tests/vendor/go.starlark.net/starlark/int_generic.go delete mode 100644 tests/vendor/go.starlark.net/starlark/int_posix64.go delete mode 100644 tests/vendor/go.starlark.net/starlark/interp.go delete mode 100644 tests/vendor/go.starlark.net/starlark/library.go delete mode 100644 tests/vendor/go.starlark.net/starlark/profile.go delete mode 100644 tests/vendor/go.starlark.net/starlark/unpack.go delete mode 100644 tests/vendor/go.starlark.net/starlark/value.go delete mode 100644 tests/vendor/go.starlark.net/starlarkstruct/module.go delete mode 100644 tests/vendor/go.starlark.net/starlarkstruct/struct.go delete mode 100644 tests/vendor/go.starlark.net/syntax/grammar.txt delete mode 100644 tests/vendor/go.starlark.net/syntax/options.go delete mode 100644 tests/vendor/go.starlark.net/syntax/parse.go delete mode 100644 tests/vendor/go.starlark.net/syntax/quote.go delete mode 100644 tests/vendor/go.starlark.net/syntax/scan.go delete mode 100644 tests/vendor/go.starlark.net/syntax/syntax.go delete mode 100644 tests/vendor/go.starlark.net/syntax/walk.go create mode 100644 tests/vendor/google.golang.org/grpc/grpclog/internal/grpclog.go create mode 100644 tests/vendor/google.golang.org/grpc/grpclog/internal/logger.go create mode 100644 tests/vendor/google.golang.org/grpc/grpclog/internal/loggerv2.go delete mode 100644 tests/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go delete mode 100644 tests/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go delete mode 100644 tests/vendor/gopkg.in/evanphx/json-patch.v5/.gitignore delete mode 100644 tests/vendor/gopkg.in/evanphx/json-patch.v5/LICENSE delete mode 100644 tests/vendor/gopkg.in/evanphx/json-patch.v5/README.md delete mode 100644 tests/vendor/gopkg.in/evanphx/json-patch.v5/errors.go delete mode 100644 tests/vendor/gopkg.in/evanphx/json-patch.v5/merge.go delete mode 100644 tests/vendor/gopkg.in/evanphx/json-patch.v5/patch.go create mode 100644 tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin.go create mode 100644 tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin_disabled.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/context.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/doc.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/starlark.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/doc.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/util.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/filters.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/fmtr.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/grep.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/local.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge3.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/modify.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/stripcomments.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge3/merge3.go delete mode 100644 tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge3/visitor.go diff --git a/tests/go.mod b/tests/go.mod index fd6d68657..0b9ed3d16 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -8,12 +8,12 @@ require ( github.com/onsi/ginkgo/v2 v2.22.1 github.com/onsi/gomega v1.36.2 github.com/stretchr/testify v1.10.0 - k8s.io/api v0.32.1 - k8s.io/apiextensions-apiserver v0.32.1 - k8s.io/apimachinery v0.32.1 - k8s.io/client-go v0.32.1 + k8s.io/api v0.32.2 + k8s.io/apiextensions-apiserver v0.32.2 + k8s.io/apimachinery v0.32.2 + k8s.io/client-go v0.32.2 k8s.io/klog/v2 v2.130.1 - sigs.k8s.io/node-feature-discovery v0.16.6 + sigs.k8s.io/node-feature-discovery v0.17.2 sigs.k8s.io/node-feature-discovery/api/nfd v0.17.1 sigs.k8s.io/yaml v1.4.0 ) @@ -31,15 +31,16 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.44.122 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect github.com/containerd/containerd v1.7.12 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/cyphar/filepath-securejoin v0.3.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/distribution/reference v0.5.0 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v25.0.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v25.0.6+incompatible // indirect @@ -120,7 +121,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc6 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -147,10 +148,9 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - go.starlark.net v0.0.0-20231121155337-90ade8b19d09 // indirect + go.opentelemetry.io/otel v1.31.0 // indirect + go.opentelemetry.io/otel/metric v1.31.0 // indirect + go.opentelemetry.io/otel/trace v1.31.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.33.0 // indirect @@ -159,26 +159,25 @@ require ( golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.7.0 // indirect + golang.org/x/time v0.8.0 // indirect golang.org/x/tools v0.28.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect - google.golang.org/grpc v1.65.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect + google.golang.org/grpc v1.69.0 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect - gopkg.in/evanphx/json-patch.v5 v5.7.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect helm.sh/helm/v3 v3.15.2 // indirect - k8s.io/apiserver v0.32.1 // indirect - k8s.io/cli-runtime v0.30.3 // indirect - k8s.io/component-base v0.32.1 // indirect + k8s.io/apiserver v0.32.2 // indirect + k8s.io/cli-runtime v0.32.2 // indirect + k8s.io/component-base v0.32.2 // indirect k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect - k8s.io/kubectl v0.30.3 // indirect + k8s.io/kubectl v0.32.2 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect oras.land/oras-go v1.2.5 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/kustomize/api v0.16.0 // indirect - sigs.k8s.io/kustomize/kyaml v0.16.0 // indirect + sigs.k8s.io/kustomize/api v0.18.0 // indirect + sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect ) diff --git a/tests/go.sum b/tests/go.sum index 848cd8d7a..2eb65b9b8 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -19,8 +19,8 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= @@ -38,6 +38,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= @@ -66,16 +68,16 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lV github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.3.5 h1:L81NHjquoQmcPgXcttUS9qTSR/+bXry6pbSINQGpjj4= +github.com/cyphar/filepath-securejoin v0.3.5/go.mod h1:edhVd3c6OXKjUmSrVa/tGJRS9joFTxlslFCAyaxigkE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbTO1lpcGSkU= github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= @@ -107,8 +109,8 @@ github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6 github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -292,8 +294,8 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= -github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= -github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= +github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -320,8 +322,8 @@ github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU= -github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= @@ -429,14 +431,12 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.starlark.net v0.0.0-20231121155337-90ade8b19d09 h1:hzy3LFnSN8kuQK8h9tHl4ndF6UruMj47OqwqsS+/Ai4= -go.starlark.net v0.0.0-20231121155337-90ade8b19d09/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -452,8 +452,6 @@ golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbR golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -508,8 +506,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -521,10 +519,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.69.0 h1:quSiOM1GJPmPH5XtU+BCoVXcDVJJAzNcoyfC2cCjGkI= +google.golang.org/grpc v1.69.0/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -534,8 +532,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= -gopkg.in/evanphx/json-patch.v5 v5.7.0 h1:dGKGylPlZ/jus2g1YqhhyzfH0gPy2R8/MYUpW/OslTY= -gopkg.in/evanphx/json-patch.v5 v5.7.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -553,38 +549,38 @@ gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= helm.sh/helm/v3 v3.15.2 h1:/3XINUFinJOBjQplGnjw92eLGpgXXp1L8chWPkCkDuw= helm.sh/helm/v3 v3.15.2/go.mod h1:FzSIP8jDQaa6WAVg9F+OkKz7J0ZmAga4MABtTbsb9WQ= -k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc= -k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= -k8s.io/apiextensions-apiserver v0.32.1 h1:hjkALhRUeCariC8DiVmb5jj0VjIc1N0DREP32+6UXZw= -k8s.io/apiextensions-apiserver v0.32.1/go.mod h1:sxWIGuGiYov7Io1fAS2X06NjMIk5CbRHc2StSmbaQto= -k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= -k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/apiserver v0.32.1 h1:oo0OozRos66WFq87Zc5tclUX2r0mymoVHRq8JmR7Aak= -k8s.io/apiserver v0.32.1/go.mod h1:UcB9tWjBY7aryeI5zAgzVJB/6k7E97bkr1RgqDz0jPw= -k8s.io/cli-runtime v0.30.3 h1:aG69oRzJuP2Q4o8dm+f5WJIX4ZBEwrvdID0+MXyUY6k= -k8s.io/cli-runtime v0.30.3/go.mod h1:hwrrRdd9P84CXSKzhHxrOivAR9BRnkMt0OeP5mj7X30= -k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU= -k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg= -k8s.io/component-base v0.32.1 h1:/5IfJ0dHIKBWysGV0yKTFfacZ5yNV1sulPh3ilJjRZk= -k8s.io/component-base v0.32.1/go.mod h1:j1iMMHi/sqAHeG5z+O9BFNCF698a1u0186zkjMZQ28w= +k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw= +k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y= +k8s.io/apiextensions-apiserver v0.32.2 h1:2YMk285jWMk2188V2AERy5yDwBYrjgWYggscghPCvV4= +k8s.io/apiextensions-apiserver v0.32.2/go.mod h1:GPwf8sph7YlJT3H6aKUWtd0E+oyShk/YHWQHf/OOgCA= +k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= +k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/apiserver v0.32.2 h1:WzyxAu4mvLkQxwD9hGa4ZfExo3yZZaYzoYvvVDlM6vw= +k8s.io/apiserver v0.32.2/go.mod h1:PEwREHiHNU2oFdte7BjzA1ZyjWjuckORLIK/wLV5goM= +k8s.io/cli-runtime v0.32.2 h1:aKQR4foh9qeyckKRkNXUccP9moxzffyndZAvr+IXMks= +k8s.io/cli-runtime v0.32.2/go.mod h1:a/JpeMztz3xDa7GCyyShcwe55p8pbcCVQxvqZnIwXN8= +k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA= +k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94= +k8s.io/component-base v0.32.2 h1:1aUL5Vdmu7qNo4ZsE+569PV5zFatM9hl+lb3dEea2zU= +k8s.io/component-base v0.32.2/go.mod h1:PXJ61Vx9Lg+P5mS8TLd7bCIr+eMJRQTyXe8KvkrvJq0= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= -k8s.io/kubectl v0.30.3 h1:YIBBvMdTW0xcDpmrOBzcpUVsn+zOgjMYIu7kAq+yqiI= -k8s.io/kubectl v0.30.3/go.mod h1:IcR0I9RN2+zzTRUa1BzZCm4oM0NLOawE6RzlDvd1Fpo= +k8s.io/kubectl v0.32.2 h1:TAkag6+XfSBgkqK9I7ZvwtF0WVtUAvK8ZqTt+5zi1Us= +k8s.io/kubectl v0.32.2/go.mod h1:+h/NQFSPxiDZYX/WZaWw9fwYezGLISP0ud8nQKg+3g8= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo= oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/kustomize/api v0.16.0 h1:/zAR4FOQDCkgSDmVzV2uiFbuy9bhu3jEzthrHCuvm1g= -sigs.k8s.io/kustomize/api v0.16.0/go.mod h1:MnFZ7IP2YqVyVwMWoRxPtgl/5hpA+eCCrQR/866cm5c= -sigs.k8s.io/kustomize/kyaml v0.16.0 h1:6J33uKSoATlKZH16unr2XOhDI+otoe2sR3M8PDzW3K0= -sigs.k8s.io/kustomize/kyaml v0.16.0/go.mod h1:xOK/7i+vmE14N2FdFyugIshB8eF6ALpy7jI87Q2nRh4= -sigs.k8s.io/node-feature-discovery v0.16.6 h1:G+n0gStHnLojsLVLgP/ArsC2gwP1fkw7TrHr0MJ4x8k= -sigs.k8s.io/node-feature-discovery v0.16.6/go.mod h1:7qS1l8P6UdfLa/ec8VneMvINbdWbuhTuuQr1wZ7/Jbg= +sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo= +sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U= +sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E= +sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo= +sigs.k8s.io/node-feature-discovery v0.17.2 h1:0/uM3riZft2FKLybrYRuuqQVwPe14az/zaylo9Xl70Q= +sigs.k8s.io/node-feature-discovery v0.17.2/go.mod h1:Vw8K+THXTrSO38xnAja3JSQH8u6EE1AUS4iFWmoFTqA= sigs.k8s.io/node-feature-discovery/api/nfd v0.17.1 h1:Ugn+nnCp08bOc0cA3QyonGZpkOy9j0y0O5gRXdtc720= sigs.k8s.io/node-feature-discovery/api/nfd v0.17.1/go.mod h1:LxvqM3WtCMHxCFvJ6faI16O1BbW0eekHGg/jwxecF3M= sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/LICENSE b/tests/vendor/github.com/blang/semver/v4/LICENSE similarity index 92% rename from tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/LICENSE rename to tests/vendor/github.com/blang/semver/v4/LICENSE index 31f292dce..5ba5c86fc 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/LICENSE +++ b/tests/vendor/github.com/blang/semver/v4/LICENSE @@ -1,6 +1,6 @@ -The MIT License (MIT) +The MIT License -Copyright (c) 2018 QRI, Inc. +Copyright (c) 2014 Benedikt Lang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -19,3 +19,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/tests/vendor/github.com/blang/semver/v4/json.go b/tests/vendor/github.com/blang/semver/v4/json.go new file mode 100644 index 000000000..a74bf7c44 --- /dev/null +++ b/tests/vendor/github.com/blang/semver/v4/json.go @@ -0,0 +1,23 @@ +package semver + +import ( + "encoding/json" +) + +// MarshalJSON implements the encoding/json.Marshaler interface. +func (v Version) MarshalJSON() ([]byte, error) { + return json.Marshal(v.String()) +} + +// UnmarshalJSON implements the encoding/json.Unmarshaler interface. +func (v *Version) UnmarshalJSON(data []byte) (err error) { + var versionString string + + if err = json.Unmarshal(data, &versionString); err != nil { + return + } + + *v, err = Parse(versionString) + + return +} diff --git a/tests/vendor/github.com/blang/semver/v4/range.go b/tests/vendor/github.com/blang/semver/v4/range.go new file mode 100644 index 000000000..95f7139b9 --- /dev/null +++ b/tests/vendor/github.com/blang/semver/v4/range.go @@ -0,0 +1,416 @@ +package semver + +import ( + "fmt" + "strconv" + "strings" + "unicode" +) + +type wildcardType int + +const ( + noneWildcard wildcardType = iota + majorWildcard wildcardType = 1 + minorWildcard wildcardType = 2 + patchWildcard wildcardType = 3 +) + +func wildcardTypefromInt(i int) wildcardType { + switch i { + case 1: + return majorWildcard + case 2: + return minorWildcard + case 3: + return patchWildcard + default: + return noneWildcard + } +} + +type comparator func(Version, Version) bool + +var ( + compEQ comparator = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) == 0 + } + compNE = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) != 0 + } + compGT = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) == 1 + } + compGE = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) >= 0 + } + compLT = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) == -1 + } + compLE = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) <= 0 + } +) + +type versionRange struct { + v Version + c comparator +} + +// rangeFunc creates a Range from the given versionRange. +func (vr *versionRange) rangeFunc() Range { + return Range(func(v Version) bool { + return vr.c(v, vr.v) + }) +} + +// Range represents a range of versions. +// A Range can be used to check if a Version satisfies it: +// +// range, err := semver.ParseRange(">1.0.0 <2.0.0") +// range(semver.MustParse("1.1.1") // returns true +type Range func(Version) bool + +// OR combines the existing Range with another Range using logical OR. +func (rf Range) OR(f Range) Range { + return Range(func(v Version) bool { + return rf(v) || f(v) + }) +} + +// AND combines the existing Range with another Range using logical AND. +func (rf Range) AND(f Range) Range { + return Range(func(v Version) bool { + return rf(v) && f(v) + }) +} + +// ParseRange parses a range and returns a Range. +// If the range could not be parsed an error is returned. +// +// Valid ranges are: +// - "<1.0.0" +// - "<=1.0.0" +// - ">1.0.0" +// - ">=1.0.0" +// - "1.0.0", "=1.0.0", "==1.0.0" +// - "!1.0.0", "!=1.0.0" +// +// A Range can consist of multiple ranges separated by space: +// Ranges can be linked by logical AND: +// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0" +// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2 +// +// Ranges can also be linked by logical OR: +// - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x" +// +// AND has a higher precedence than OR. It's not possible to use brackets. +// +// Ranges can be combined by both AND and OR +// +// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` +func ParseRange(s string) (Range, error) { + parts := splitAndTrim(s) + orParts, err := splitORParts(parts) + if err != nil { + return nil, err + } + expandedParts, err := expandWildcardVersion(orParts) + if err != nil { + return nil, err + } + var orFn Range + for _, p := range expandedParts { + var andFn Range + for _, ap := range p { + opStr, vStr, err := splitComparatorVersion(ap) + if err != nil { + return nil, err + } + vr, err := buildVersionRange(opStr, vStr) + if err != nil { + return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err) + } + rf := vr.rangeFunc() + + // Set function + if andFn == nil { + andFn = rf + } else { // Combine with existing function + andFn = andFn.AND(rf) + } + } + if orFn == nil { + orFn = andFn + } else { + orFn = orFn.OR(andFn) + } + + } + return orFn, nil +} + +// splitORParts splits the already cleaned parts by '||'. +// Checks for invalid positions of the operator and returns an +// error if found. +func splitORParts(parts []string) ([][]string, error) { + var ORparts [][]string + last := 0 + for i, p := range parts { + if p == "||" { + if i == 0 { + return nil, fmt.Errorf("First element in range is '||'") + } + ORparts = append(ORparts, parts[last:i]) + last = i + 1 + } + } + if last == len(parts) { + return nil, fmt.Errorf("Last element in range is '||'") + } + ORparts = append(ORparts, parts[last:]) + return ORparts, nil +} + +// buildVersionRange takes a slice of 2: operator and version +// and builds a versionRange, otherwise an error. +func buildVersionRange(opStr, vStr string) (*versionRange, error) { + c := parseComparator(opStr) + if c == nil { + return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, "")) + } + v, err := Parse(vStr) + if err != nil { + return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err) + } + + return &versionRange{ + v: v, + c: c, + }, nil + +} + +// inArray checks if a byte is contained in an array of bytes +func inArray(s byte, list []byte) bool { + for _, el := range list { + if el == s { + return true + } + } + return false +} + +// splitAndTrim splits a range string by spaces and cleans whitespaces +func splitAndTrim(s string) (result []string) { + last := 0 + var lastChar byte + excludeFromSplit := []byte{'>', '<', '='} + for i := 0; i < len(s); i++ { + if s[i] == ' ' && !inArray(lastChar, excludeFromSplit) { + if last < i-1 { + result = append(result, s[last:i]) + } + last = i + 1 + } else if s[i] != ' ' { + lastChar = s[i] + } + } + if last < len(s)-1 { + result = append(result, s[last:]) + } + + for i, v := range result { + result[i] = strings.Replace(v, " ", "", -1) + } + + // parts := strings.Split(s, " ") + // for _, x := range parts { + // if s := strings.TrimSpace(x); len(s) != 0 { + // result = append(result, s) + // } + // } + return +} + +// splitComparatorVersion splits the comparator from the version. +// Input must be free of leading or trailing spaces. +func splitComparatorVersion(s string) (string, string, error) { + i := strings.IndexFunc(s, unicode.IsDigit) + if i == -1 { + return "", "", fmt.Errorf("Could not get version from string: %q", s) + } + return strings.TrimSpace(s[0:i]), s[i:], nil +} + +// getWildcardType will return the type of wildcard that the +// passed version contains +func getWildcardType(vStr string) wildcardType { + parts := strings.Split(vStr, ".") + nparts := len(parts) + wildcard := parts[nparts-1] + + possibleWildcardType := wildcardTypefromInt(nparts) + if wildcard == "x" { + return possibleWildcardType + } + + return noneWildcard +} + +// createVersionFromWildcard will convert a wildcard version +// into a regular version, replacing 'x's with '0's, handling +// special cases like '1.x.x' and '1.x' +func createVersionFromWildcard(vStr string) string { + // handle 1.x.x + vStr2 := strings.Replace(vStr, ".x.x", ".x", 1) + vStr2 = strings.Replace(vStr2, ".x", ".0", 1) + parts := strings.Split(vStr2, ".") + + // handle 1.x + if len(parts) == 2 { + return vStr2 + ".0" + } + + return vStr2 +} + +// incrementMajorVersion will increment the major version +// of the passed version +func incrementMajorVersion(vStr string) (string, error) { + parts := strings.Split(vStr, ".") + i, err := strconv.Atoi(parts[0]) + if err != nil { + return "", err + } + parts[0] = strconv.Itoa(i + 1) + + return strings.Join(parts, "."), nil +} + +// incrementMajorVersion will increment the minor version +// of the passed version +func incrementMinorVersion(vStr string) (string, error) { + parts := strings.Split(vStr, ".") + i, err := strconv.Atoi(parts[1]) + if err != nil { + return "", err + } + parts[1] = strconv.Itoa(i + 1) + + return strings.Join(parts, "."), nil +} + +// expandWildcardVersion will expand wildcards inside versions +// following these rules: +// +// * when dealing with patch wildcards: +// >= 1.2.x will become >= 1.2.0 +// <= 1.2.x will become < 1.3.0 +// > 1.2.x will become >= 1.3.0 +// < 1.2.x will become < 1.2.0 +// != 1.2.x will become < 1.2.0 >= 1.3.0 +// +// * when dealing with minor wildcards: +// >= 1.x will become >= 1.0.0 +// <= 1.x will become < 2.0.0 +// > 1.x will become >= 2.0.0 +// < 1.0 will become < 1.0.0 +// != 1.x will become < 1.0.0 >= 2.0.0 +// +// * when dealing with wildcards without +// version operator: +// 1.2.x will become >= 1.2.0 < 1.3.0 +// 1.x will become >= 1.0.0 < 2.0.0 +func expandWildcardVersion(parts [][]string) ([][]string, error) { + var expandedParts [][]string + for _, p := range parts { + var newParts []string + for _, ap := range p { + if strings.Contains(ap, "x") { + opStr, vStr, err := splitComparatorVersion(ap) + if err != nil { + return nil, err + } + + versionWildcardType := getWildcardType(vStr) + flatVersion := createVersionFromWildcard(vStr) + + var resultOperator string + var shouldIncrementVersion bool + switch opStr { + case ">": + resultOperator = ">=" + shouldIncrementVersion = true + case ">=": + resultOperator = ">=" + case "<": + resultOperator = "<" + case "<=": + resultOperator = "<" + shouldIncrementVersion = true + case "", "=", "==": + newParts = append(newParts, ">="+flatVersion) + resultOperator = "<" + shouldIncrementVersion = true + case "!=", "!": + newParts = append(newParts, "<"+flatVersion) + resultOperator = ">=" + shouldIncrementVersion = true + } + + var resultVersion string + if shouldIncrementVersion { + switch versionWildcardType { + case patchWildcard: + resultVersion, _ = incrementMinorVersion(flatVersion) + case minorWildcard: + resultVersion, _ = incrementMajorVersion(flatVersion) + } + } else { + resultVersion = flatVersion + } + + ap = resultOperator + resultVersion + } + newParts = append(newParts, ap) + } + expandedParts = append(expandedParts, newParts) + } + + return expandedParts, nil +} + +func parseComparator(s string) comparator { + switch s { + case "==": + fallthrough + case "": + fallthrough + case "=": + return compEQ + case ">": + return compGT + case ">=": + return compGE + case "<": + return compLT + case "<=": + return compLE + case "!": + fallthrough + case "!=": + return compNE + } + + return nil +} + +// MustParseRange is like ParseRange but panics if the range cannot be parsed. +func MustParseRange(s string) Range { + r, err := ParseRange(s) + if err != nil { + panic(`semver: ParseRange(` + s + `): ` + err.Error()) + } + return r +} diff --git a/tests/vendor/github.com/blang/semver/v4/semver.go b/tests/vendor/github.com/blang/semver/v4/semver.go new file mode 100644 index 000000000..307de610f --- /dev/null +++ b/tests/vendor/github.com/blang/semver/v4/semver.go @@ -0,0 +1,476 @@ +package semver + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +const ( + numbers string = "0123456789" + alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" + alphanum = alphas + numbers +) + +// SpecVersion is the latest fully supported spec version of semver +var SpecVersion = Version{ + Major: 2, + Minor: 0, + Patch: 0, +} + +// Version represents a semver compatible version +type Version struct { + Major uint64 + Minor uint64 + Patch uint64 + Pre []PRVersion + Build []string //No Precedence +} + +// Version to string +func (v Version) String() string { + b := make([]byte, 0, 5) + b = strconv.AppendUint(b, v.Major, 10) + b = append(b, '.') + b = strconv.AppendUint(b, v.Minor, 10) + b = append(b, '.') + b = strconv.AppendUint(b, v.Patch, 10) + + if len(v.Pre) > 0 { + b = append(b, '-') + b = append(b, v.Pre[0].String()...) + + for _, pre := range v.Pre[1:] { + b = append(b, '.') + b = append(b, pre.String()...) + } + } + + if len(v.Build) > 0 { + b = append(b, '+') + b = append(b, v.Build[0]...) + + for _, build := range v.Build[1:] { + b = append(b, '.') + b = append(b, build...) + } + } + + return string(b) +} + +// FinalizeVersion discards prerelease and build number and only returns +// major, minor and patch number. +func (v Version) FinalizeVersion() string { + b := make([]byte, 0, 5) + b = strconv.AppendUint(b, v.Major, 10) + b = append(b, '.') + b = strconv.AppendUint(b, v.Minor, 10) + b = append(b, '.') + b = strconv.AppendUint(b, v.Patch, 10) + return string(b) +} + +// Equals checks if v is equal to o. +func (v Version) Equals(o Version) bool { + return (v.Compare(o) == 0) +} + +// EQ checks if v is equal to o. +func (v Version) EQ(o Version) bool { + return (v.Compare(o) == 0) +} + +// NE checks if v is not equal to o. +func (v Version) NE(o Version) bool { + return (v.Compare(o) != 0) +} + +// GT checks if v is greater than o. +func (v Version) GT(o Version) bool { + return (v.Compare(o) == 1) +} + +// GTE checks if v is greater than or equal to o. +func (v Version) GTE(o Version) bool { + return (v.Compare(o) >= 0) +} + +// GE checks if v is greater than or equal to o. +func (v Version) GE(o Version) bool { + return (v.Compare(o) >= 0) +} + +// LT checks if v is less than o. +func (v Version) LT(o Version) bool { + return (v.Compare(o) == -1) +} + +// LTE checks if v is less than or equal to o. +func (v Version) LTE(o Version) bool { + return (v.Compare(o) <= 0) +} + +// LE checks if v is less than or equal to o. +func (v Version) LE(o Version) bool { + return (v.Compare(o) <= 0) +} + +// Compare compares Versions v to o: +// -1 == v is less than o +// 0 == v is equal to o +// 1 == v is greater than o +func (v Version) Compare(o Version) int { + if v.Major != o.Major { + if v.Major > o.Major { + return 1 + } + return -1 + } + if v.Minor != o.Minor { + if v.Minor > o.Minor { + return 1 + } + return -1 + } + if v.Patch != o.Patch { + if v.Patch > o.Patch { + return 1 + } + return -1 + } + + // Quick comparison if a version has no prerelease versions + if len(v.Pre) == 0 && len(o.Pre) == 0 { + return 0 + } else if len(v.Pre) == 0 && len(o.Pre) > 0 { + return 1 + } else if len(v.Pre) > 0 && len(o.Pre) == 0 { + return -1 + } + + i := 0 + for ; i < len(v.Pre) && i < len(o.Pre); i++ { + if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 { + continue + } else if comp == 1 { + return 1 + } else { + return -1 + } + } + + // If all pr versions are the equal but one has further prversion, this one greater + if i == len(v.Pre) && i == len(o.Pre) { + return 0 + } else if i == len(v.Pre) && i < len(o.Pre) { + return -1 + } else { + return 1 + } + +} + +// IncrementPatch increments the patch version +func (v *Version) IncrementPatch() error { + v.Patch++ + return nil +} + +// IncrementMinor increments the minor version +func (v *Version) IncrementMinor() error { + v.Minor++ + v.Patch = 0 + return nil +} + +// IncrementMajor increments the major version +func (v *Version) IncrementMajor() error { + v.Major++ + v.Minor = 0 + v.Patch = 0 + return nil +} + +// Validate validates v and returns error in case +func (v Version) Validate() error { + // Major, Minor, Patch already validated using uint64 + + for _, pre := range v.Pre { + if !pre.IsNum { //Numeric prerelease versions already uint64 + if len(pre.VersionStr) == 0 { + return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr) + } + if !containsOnly(pre.VersionStr, alphanum) { + return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr) + } + } + } + + for _, build := range v.Build { + if len(build) == 0 { + return fmt.Errorf("Build meta data can not be empty %q", build) + } + if !containsOnly(build, alphanum) { + return fmt.Errorf("Invalid character(s) found in build meta data %q", build) + } + } + + return nil +} + +// New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error +func New(s string) (*Version, error) { + v, err := Parse(s) + vp := &v + return vp, err +} + +// Make is an alias for Parse, parses version string and returns a validated Version or error +func Make(s string) (Version, error) { + return Parse(s) +} + +// ParseTolerant allows for certain version specifications that do not strictly adhere to semver +// specs to be parsed by this library. It does so by normalizing versions before passing them to +// Parse(). It currently trims spaces, removes a "v" prefix, adds a 0 patch number to versions +// with only major and minor components specified, and removes leading 0s. +func ParseTolerant(s string) (Version, error) { + s = strings.TrimSpace(s) + s = strings.TrimPrefix(s, "v") + + // Split into major.minor.(patch+pr+meta) + parts := strings.SplitN(s, ".", 3) + // Remove leading zeros. + for i, p := range parts { + if len(p) > 1 { + p = strings.TrimLeft(p, "0") + if len(p) == 0 || !strings.ContainsAny(p[0:1], "0123456789") { + p = "0" + p + } + parts[i] = p + } + } + // Fill up shortened versions. + if len(parts) < 3 { + if strings.ContainsAny(parts[len(parts)-1], "+-") { + return Version{}, errors.New("Short version cannot contain PreRelease/Build meta data") + } + for len(parts) < 3 { + parts = append(parts, "0") + } + } + s = strings.Join(parts, ".") + + return Parse(s) +} + +// Parse parses version string and returns a validated Version or error +func Parse(s string) (Version, error) { + if len(s) == 0 { + return Version{}, errors.New("Version string empty") + } + + // Split into major.minor.(patch+pr+meta) + parts := strings.SplitN(s, ".", 3) + if len(parts) != 3 { + return Version{}, errors.New("No Major.Minor.Patch elements found") + } + + // Major + if !containsOnly(parts[0], numbers) { + return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0]) + } + if hasLeadingZeroes(parts[0]) { + return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0]) + } + major, err := strconv.ParseUint(parts[0], 10, 64) + if err != nil { + return Version{}, err + } + + // Minor + if !containsOnly(parts[1], numbers) { + return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1]) + } + if hasLeadingZeroes(parts[1]) { + return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1]) + } + minor, err := strconv.ParseUint(parts[1], 10, 64) + if err != nil { + return Version{}, err + } + + v := Version{} + v.Major = major + v.Minor = minor + + var build, prerelease []string + patchStr := parts[2] + + if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 { + build = strings.Split(patchStr[buildIndex+1:], ".") + patchStr = patchStr[:buildIndex] + } + + if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 { + prerelease = strings.Split(patchStr[preIndex+1:], ".") + patchStr = patchStr[:preIndex] + } + + if !containsOnly(patchStr, numbers) { + return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr) + } + if hasLeadingZeroes(patchStr) { + return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr) + } + patch, err := strconv.ParseUint(patchStr, 10, 64) + if err != nil { + return Version{}, err + } + + v.Patch = patch + + // Prerelease + for _, prstr := range prerelease { + parsedPR, err := NewPRVersion(prstr) + if err != nil { + return Version{}, err + } + v.Pre = append(v.Pre, parsedPR) + } + + // Build meta data + for _, str := range build { + if len(str) == 0 { + return Version{}, errors.New("Build meta data is empty") + } + if !containsOnly(str, alphanum) { + return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str) + } + v.Build = append(v.Build, str) + } + + return v, nil +} + +// MustParse is like Parse but panics if the version cannot be parsed. +func MustParse(s string) Version { + v, err := Parse(s) + if err != nil { + panic(`semver: Parse(` + s + `): ` + err.Error()) + } + return v +} + +// PRVersion represents a PreRelease Version +type PRVersion struct { + VersionStr string + VersionNum uint64 + IsNum bool +} + +// NewPRVersion creates a new valid prerelease version +func NewPRVersion(s string) (PRVersion, error) { + if len(s) == 0 { + return PRVersion{}, errors.New("Prerelease is empty") + } + v := PRVersion{} + if containsOnly(s, numbers) { + if hasLeadingZeroes(s) { + return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s) + } + num, err := strconv.ParseUint(s, 10, 64) + + // Might never be hit, but just in case + if err != nil { + return PRVersion{}, err + } + v.VersionNum = num + v.IsNum = true + } else if containsOnly(s, alphanum) { + v.VersionStr = s + v.IsNum = false + } else { + return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s) + } + return v, nil +} + +// IsNumeric checks if prerelease-version is numeric +func (v PRVersion) IsNumeric() bool { + return v.IsNum +} + +// Compare compares two PreRelease Versions v and o: +// -1 == v is less than o +// 0 == v is equal to o +// 1 == v is greater than o +func (v PRVersion) Compare(o PRVersion) int { + if v.IsNum && !o.IsNum { + return -1 + } else if !v.IsNum && o.IsNum { + return 1 + } else if v.IsNum && o.IsNum { + if v.VersionNum == o.VersionNum { + return 0 + } else if v.VersionNum > o.VersionNum { + return 1 + } else { + return -1 + } + } else { // both are Alphas + if v.VersionStr == o.VersionStr { + return 0 + } else if v.VersionStr > o.VersionStr { + return 1 + } else { + return -1 + } + } +} + +// PreRelease version to string +func (v PRVersion) String() string { + if v.IsNum { + return strconv.FormatUint(v.VersionNum, 10) + } + return v.VersionStr +} + +func containsOnly(s string, set string) bool { + return strings.IndexFunc(s, func(r rune) bool { + return !strings.ContainsRune(set, r) + }) == -1 +} + +func hasLeadingZeroes(s string) bool { + return len(s) > 1 && s[0] == '0' +} + +// NewBuildVersion creates a new valid build version +func NewBuildVersion(s string) (string, error) { + if len(s) == 0 { + return "", errors.New("Buildversion is empty") + } + if !containsOnly(s, alphanum) { + return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s) + } + return s, nil +} + +// FinalizeVersion returns the major, minor and patch number only and discards +// prerelease and build number. +func FinalizeVersion(s string) (string, error) { + v, err := Parse(s) + if err != nil { + return "", err + } + v.Pre = nil + v.Build = nil + + finalVer := v.String() + return finalVer, nil +} diff --git a/tests/vendor/github.com/blang/semver/v4/sort.go b/tests/vendor/github.com/blang/semver/v4/sort.go new file mode 100644 index 000000000..e18f88082 --- /dev/null +++ b/tests/vendor/github.com/blang/semver/v4/sort.go @@ -0,0 +1,28 @@ +package semver + +import ( + "sort" +) + +// Versions represents multiple versions. +type Versions []Version + +// Len returns length of version collection +func (s Versions) Len() int { + return len(s) +} + +// Swap swaps two versions inside the collection by its indices +func (s Versions) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +// Less checks if version at index i is less than version at index j +func (s Versions) Less(i, j int) bool { + return s[i].LT(s[j]) +} + +// Sort sorts a slice of versions +func Sort(versions []Version) { + sort.Sort(Versions(versions)) +} diff --git a/tests/vendor/github.com/blang/semver/v4/sql.go b/tests/vendor/github.com/blang/semver/v4/sql.go new file mode 100644 index 000000000..db958134f --- /dev/null +++ b/tests/vendor/github.com/blang/semver/v4/sql.go @@ -0,0 +1,30 @@ +package semver + +import ( + "database/sql/driver" + "fmt" +) + +// Scan implements the database/sql.Scanner interface. +func (v *Version) Scan(src interface{}) (err error) { + var str string + switch src := src.(type) { + case string: + str = src + case []byte: + str = string(src) + default: + return fmt.Errorf("version.Scan: cannot convert %T to string", src) + } + + if t, err := Parse(str); err == nil { + *v = t + } + + return +} + +// Value implements the database/sql/driver.Valuer interface. +func (v Version) Value() (driver.Value, error) { + return v.String(), nil +} diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md b/tests/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md new file mode 100644 index 000000000..05657248f --- /dev/null +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md @@ -0,0 +1,186 @@ +# Changelog # +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] ## + +## [0.3.5] - 2024-12-06 ## +### Fixed ### +- `MkdirAll` will now no longer return an `EEXIST` error if two racing + processes are creating the same directory. We will still verify that the path + is a directory, but this will avoid spurious errors when multiple threads or + programs are trying to `MkdirAll` the same path. opencontainers/runc#4543 + +## [0.3.4] - 2024-10-09 ## + +### Fixed ### +- Previously, some testing mocks we had resulted in us doing `import "testing"` + in non-`_test.go` code, which made some downstreams like Kubernetes unhappy. + This has been fixed. (#32) + +## [0.3.3] - 2024-09-30 ## + +### Fixed ### +- The mode and owner verification logic in `MkdirAll` has been removed. This + was originally intended to protect against some theoretical attacks but upon + further consideration these protections don't actually buy us anything and + they were causing spurious errors with more complicated filesystem setups. +- The "is the created directory empty" logic in `MkdirAll` has also been + removed. This was not causing us issues yet, but some pseudofilesystems (such + as `cgroup`) create non-empty directories and so this logic would've been + wrong for such cases. + +## [0.3.2] - 2024-09-13 ## + +### Changed ### +- Passing the `S_ISUID` or `S_ISGID` modes to `MkdirAllInRoot` will now return + an explicit error saying that those bits are ignored by `mkdirat(2)`. In the + past a different error was returned, but since the silent ignoring behaviour + is codified in the man pages a more explicit error seems apt. While silently + ignoring these bits would be the most compatible option, it could lead to + users thinking their code sets these bits when it doesn't. Programs that need + to deal with compatibility can mask the bits themselves. (#23, #25) + +### Fixed ### +- If a directory has `S_ISGID` set, then all child directories will have + `S_ISGID` set when created and a different gid will be used for any inode + created under the directory. Previously, the "expected owner and mode" + validation in `securejoin.MkdirAll` did not correctly handle this. We now + correctly handle this case. (#24, #25) + +## [0.3.1] - 2024-07-23 ## + +### Changed ### +- By allowing `Open(at)InRoot` to opt-out of the extra work done by `MkdirAll` + to do the necessary "partial lookups", `Open(at)InRoot` now does less work + for both implementations (resulting in a many-fold decrease in the number of + operations for `openat2`, and a modest improvement for non-`openat2`) and is + far more guaranteed to match the correct `openat2(RESOLVE_IN_ROOT)` + behaviour. +- We now use `readlinkat(fd, "")` where possible. For `Open(at)InRoot` this + effectively just means that we no longer risk getting spurious errors during + rename races. However, for our hardened procfs handler, this in theory should + prevent mount attacks from tricking us when doing magic-link readlinks (even + when using the unsafe host `/proc` handle). Unfortunately `Reopen` is still + potentially vulnerable to those kinds of somewhat-esoteric attacks. + + Technically this [will only work on post-2.6.39 kernels][linux-readlinkat-emptypath] + but it seems incredibly unlikely anyone is using `filepath-securejoin` on a + pre-2011 kernel. + +### Fixed ### +- Several improvements were made to the errors returned by `Open(at)InRoot` and + `MkdirAll` when dealing with invalid paths under the emulated (ie. + non-`openat2`) implementation. Previously, some paths would return the wrong + error (`ENOENT` when the last component was a non-directory), and other paths + would be returned as though they were acceptable (trailing-slash components + after a non-directory would be ignored by `Open(at)InRoot`). + + These changes were done to match `openat2`'s behaviour and purely is a + consistency fix (most users are going to be using `openat2` anyway). + +[linux-readlinkat-emptypath]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=65cfc6722361570bfe255698d9cd4dccaf47570d + +## [0.3.0] - 2024-07-11 ## + +### Added ### +- A new set of `*os.File`-based APIs have been added. These are adapted from + [libpathrs][] and we strongly suggest using them if possible (as they provide + far more protection against attacks than `SecureJoin`): + + - `Open(at)InRoot` resolves a path inside a rootfs and returns an `*os.File` + handle to the path. Note that the handle returned is an `O_PATH` handle, + which cannot be used for reading or writing (as well as some other + operations -- [see open(2) for more details][open.2]) + + - `Reopen` takes an `O_PATH` file handle and safely re-opens it to upgrade + it to a regular handle. This can also be used with non-`O_PATH` handles, + but `O_PATH` is the most obvious application. + + - `MkdirAll` is an implementation of `os.MkdirAll` that is safe to use to + create a directory tree within a rootfs. + + As these are new APIs, they may change in the future. However, they should be + safe to start migrating to as we have extensive tests ensuring they behave + correctly and are safe against various races and other attacks. + +[libpathrs]: https://github.com/openSUSE/libpathrs +[open.2]: https://www.man7.org/linux/man-pages/man2/open.2.html + +## [0.2.5] - 2024-05-03 ## + +### Changed ### +- Some minor changes were made to how lexical components (like `..` and `.`) + are handled during path generation in `SecureJoin`. There is no behaviour + change as a result of this fix (the resulting paths are the same). + +### Fixed ### +- The error returned when we hit a symlink loop now references the correct + path. (#10) + +## [0.2.4] - 2023-09-06 ## + +### Security ### +- This release fixes a potential security issue in filepath-securejoin when + used on Windows ([GHSA-6xv5-86q9-7xr8][], which could be used to generate + paths outside of the provided rootfs in certain cases), as well as improving + the overall behaviour of filepath-securejoin when dealing with Windows paths + that contain volume names. Thanks to Paulo Gomes for discovering and fixing + these issues. + +### Fixed ### +- Switch to GitHub Actions for CI so we can test on Windows as well as Linux + and MacOS. + +[GHSA-6xv5-86q9-7xr8]: https://github.com/advisories/GHSA-6xv5-86q9-7xr8 + +## [0.2.3] - 2021-06-04 ## + +### Changed ### +- Switch to Go 1.13-style `%w` error wrapping, letting us drop the dependency + on `github.com/pkg/errors`. + +## [0.2.2] - 2018-09-05 ## + +### Changed ### +- Use `syscall.ELOOP` as the base error for symlink loops, rather than our own + (internal) error. This allows callers to more easily use `errors.Is` to check + for this case. + +## [0.2.1] - 2018-09-05 ## + +### Fixed ### +- Use our own `IsNotExist` implementation, which lets us handle `ENOTDIR` + properly within `SecureJoin`. + +## [0.2.0] - 2017-07-19 ## + +We now have 100% test coverage! + +### Added ### +- Add a `SecureJoinVFS` API that can be used for mocking (as we do in our new + tests) or for implementing custom handling of lookup operations (such as for + rootless containers, where work is necessary to access directories with weird + modes because we don't have `CAP_DAC_READ_SEARCH` or `CAP_DAC_OVERRIDE`). + +## 0.1.0 - 2017-07-19 + +This is our first release of `github.com/cyphar/filepath-securejoin`, +containing a full implementation with a coverage of 93.5% (the only missing +cases are the error cases, which are hard to mocktest at the moment). + +[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.5...HEAD +[0.3.5]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.4...v0.3.5 +[0.3.4]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.3...v0.3.4 +[0.3.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.2...v0.3.3 +[0.3.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.1...v0.3.2 +[0.3.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.0...v0.3.1 +[0.3.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.5...v0.3.0 +[0.2.5]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.4...v0.2.5 +[0.2.4]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.3...v0.2.4 +[0.2.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.2...v0.2.3 +[0.2.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.1...v0.2.2 +[0.2.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.0...v0.2.1 +[0.2.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.1.0...v0.2.0 diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/LICENSE b/tests/vendor/github.com/cyphar/filepath-securejoin/LICENSE index bec842f29..cb1ab88da 100644 --- a/tests/vendor/github.com/cyphar/filepath-securejoin/LICENSE +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/LICENSE @@ -1,5 +1,5 @@ Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved. -Copyright (C) 2017 SUSE LLC. All rights reserved. +Copyright (C) 2017-2024 SUSE LLC. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/README.md b/tests/vendor/github.com/cyphar/filepath-securejoin/README.md index 4eca0f235..eaeb53fcd 100644 --- a/tests/vendor/github.com/cyphar/filepath-securejoin/README.md +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/README.md @@ -1,32 +1,26 @@ ## `filepath-securejoin` ## +[![Go Documentation](https://pkg.go.dev/badge/github.com/cyphar/filepath-securejoin.svg)](https://pkg.go.dev/github.com/cyphar/filepath-securejoin) [![Build Status](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml/badge.svg)](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml) -An implementation of `SecureJoin`, a [candidate for inclusion in the Go -standard library][go#20126]. The purpose of this function is to be a "secure" -alternative to `filepath.Join`, and in particular it provides certain -guarantees that are not provided by `filepath.Join`. - -> **NOTE**: This code is *only* safe if you are not at risk of other processes -> modifying path components after you've used `SecureJoin`. If it is possible -> for a malicious process to modify path components of the resolved path, then -> you will be vulnerable to some fairly trivial TOCTOU race conditions. [There -> are some Linux kernel patches I'm working on which might allow for a better -> solution.][lwn-obeneath] -> -> In addition, with a slightly modified API it might be possible to use -> `O_PATH` and verify that the opened path is actually the resolved one -- but -> I have not done that yet. I might add it in the future as a helper function -> to help users verify the path (we can't just return `/proc/self/fd/` -> because that doesn't always work transparently for all users). - -This is the function prototype: +### Old API ### -```go -func SecureJoin(root, unsafePath string) (string, error) -``` +This library was originally just an implementation of `SecureJoin` which was +[intended to be included in the Go standard library][go#20126] as a safer +`filepath.Join` that would restrict the path lookup to be inside a root +directory. + +The implementation was based on code that existed in several container +runtimes. Unfortunately, this API is **fundamentally unsafe** against attackers +that can modify path components after `SecureJoin` returns and before the +caller uses the path, allowing for some fairly trivial TOCTOU attacks. + +`SecureJoin` (and `SecureJoinVFS`) are still provided by this library to +support legacy users, but new users are strongly suggested to avoid using +`SecureJoin` and instead use the [new api](#new-api) or switch to +[libpathrs][libpathrs]. -This library **guarantees** the following: +With the above limitations in mind, this library guarantees the following: * If no error is set, the resulting string **must** be a child path of `root` and will not contain any symlink path components (they will all be @@ -47,7 +41,7 @@ This library **guarantees** the following: A (trivial) implementation of this function on GNU/Linux systems could be done with the following (note that this requires root privileges and is far more opaque than the implementation in this library, and also requires that -`readlink` is inside the `root` path): +`readlink` is inside the `root` path and is trustworthy): ```go package securejoin @@ -70,9 +64,105 @@ func SecureJoin(root, unsafePath string) (string, error) { } ``` -[lwn-obeneath]: https://lwn.net/Articles/767547/ +[libpathrs]: https://github.com/openSUSE/libpathrs [go#20126]: https://github.com/golang/go/issues/20126 +### New API ### + +While we recommend users switch to [libpathrs][libpathrs] as soon as it has a +stable release, some methods implemented by libpathrs have been ported to this +library to ease the transition. These APIs are only supported on Linux. + +These APIs are implemented such that `filepath-securejoin` will +opportunistically use certain newer kernel APIs that make these operations far +more secure. In particular: + +* All of the lookup operations will use [`openat2`][openat2.2] on new enough + kernels (Linux 5.6 or later) to restrict lookups through magic-links and + bind-mounts (for certain operations) and to make use of `RESOLVE_IN_ROOT` to + efficiently resolve symlinks within a rootfs. + +* The APIs provide hardening against a malicious `/proc` mount to either detect + or avoid being tricked by a `/proc` that is not legitimate. This is done + using [`openat2`][openat2.2] for all users, and privileged users will also be + further protected by using [`fsopen`][fsopen.2] and [`open_tree`][open_tree.2] + (Linux 5.2 or later). + +[openat2.2]: https://www.man7.org/linux/man-pages/man2/openat2.2.html +[fsopen.2]: https://github.com/brauner/man-pages-md/blob/main/fsopen.md +[open_tree.2]: https://github.com/brauner/man-pages-md/blob/main/open_tree.md + +#### `OpenInRoot` #### + +```go +func OpenInRoot(root, unsafePath string) (*os.File, error) +func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) +func Reopen(handle *os.File, flags int) (*os.File, error) +``` + +`OpenInRoot` is a much safer version of + +```go +path, err := securejoin.SecureJoin(root, unsafePath) +file, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC) +``` + +that protects against various race attacks that could lead to serious security +issues, depending on the application. Note that the returned `*os.File` is an +`O_PATH` file descriptor, which is quite restricted. Callers will probably need +to use `Reopen` to get a more usable handle (this split is done to provide +useful features like PTY spawning and to avoid users accidentally opening bad +inodes that could cause a DoS). + +Callers need to be careful in how they use the returned `*os.File`. Usually it +is only safe to operate on the handle directly, and it is very easy to create a +security issue. [libpathrs][libpathrs] provides far more helpers to make using +these handles safer -- there is currently no plan to port them to +`filepath-securejoin`. + +`OpenatInRoot` is like `OpenInRoot` except that the root is provided using an +`*os.File`. This allows you to ensure that multiple `OpenatInRoot` (or +`MkdirAllHandle`) calls are operating on the same rootfs. + +> **NOTE**: Unlike `SecureJoin`, `OpenInRoot` will error out as soon as it hits +> a dangling symlink or non-existent path. This is in contrast to `SecureJoin` +> which treated non-existent components as though they were real directories, +> and would allow for partial resolution of dangling symlinks. These behaviours +> are at odds with how Linux treats non-existent paths and dangling symlinks, +> and so these are no longer allowed. + +#### `MkdirAll` #### + +```go +func MkdirAll(root, unsafePath string, mode int) error +func MkdirAllHandle(root *os.File, unsafePath string, mode int) (*os.File, error) +``` + +`MkdirAll` is a much safer version of + +```go +path, err := securejoin.SecureJoin(root, unsafePath) +err = os.MkdirAll(path, mode) +``` + +that protects against the same kinds of races that `OpenInRoot` protects +against. + +`MkdirAllHandle` is like `MkdirAll` except that the root is provided using an +`*os.File` (the reason for this is the same as with `OpenatInRoot`) and an +`*os.File` of the final created directory is returned (this directory is +guaranteed to be effectively identical to the directory created by +`MkdirAllHandle`, which is not possible to ensure by just using `OpenatInRoot` +after `MkdirAll`). + +> **NOTE**: Unlike `SecureJoin`, `MkdirAll` will error out as soon as it hits +> a dangling symlink or non-existent path. This is in contrast to `SecureJoin` +> which treated non-existent components as though they were real directories, +> and would allow for partial resolution of dangling symlinks. These behaviours +> are at odds with how Linux treats non-existent paths and dangling symlinks, +> and so these are no longer allowed. This means that `MkdirAll` will not +> create non-existent directories referenced by a dangling symlink. + ### License ### The license of this project is the same as Go, which is a BSD 3-clause license diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/VERSION b/tests/vendor/github.com/cyphar/filepath-securejoin/VERSION index abd410582..c2c0004f0 100644 --- a/tests/vendor/github.com/cyphar/filepath-securejoin/VERSION +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/VERSION @@ -1 +1 @@ -0.2.4 +0.3.5 diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/doc.go b/tests/vendor/github.com/cyphar/filepath-securejoin/doc.go new file mode 100644 index 000000000..1ec7d065e --- /dev/null +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/doc.go @@ -0,0 +1,39 @@ +// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved. +// Copyright (C) 2017-2024 SUSE LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package securejoin implements a set of helpers to make it easier to write Go +// code that is safe against symlink-related escape attacks. The primary idea +// is to let you resolve a path within a rootfs directory as if the rootfs was +// a chroot. +// +// securejoin has two APIs, a "legacy" API and a "modern" API. +// +// The legacy API is [SecureJoin] and [SecureJoinVFS]. These methods are +// **not** safe against race conditions where an attacker changes the +// filesystem after (or during) the [SecureJoin] operation. +// +// The new API is made up of [OpenInRoot] and [MkdirAll] (and derived +// functions). These are safe against racing attackers and have several other +// protections that are not provided by the legacy API. There are many more +// operations that most programs expect to be able to do safely, but we do not +// provide explicit support for them because we want to encourage users to +// switch to [libpathrs](https://github.com/openSUSE/libpathrs) which is a +// cross-language next-generation library that is entirely designed around +// operating on paths safely. +// +// securejoin has been used by several container runtimes (Docker, runc, +// Kubernetes, etc) for quite a few years as a de-facto standard for operating +// on container filesystem paths "safely". However, most users still use the +// legacy API which is unsafe against various attacks (there is a fairly long +// history of CVEs in dependent as a result). Users should switch to the modern +// API as soon as possible (or even better, switch to libpathrs). +// +// This project was initially intended to be included in the Go standard +// library, but [it was rejected](https://go.dev/issue/20126). There is now a +// [new Go proposal](https://go.dev/issue/67002) for a safe path resolution API +// that shares some of the goals of filepath-securejoin. However, that design +// is intended to work like `openat2(RESOLVE_BENEATH)` which does not fit the +// usecase of container runtimes and most system tools. +package securejoin diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/join.go b/tests/vendor/github.com/cyphar/filepath-securejoin/join.go index aa32b85fb..e0ee3f2b5 100644 --- a/tests/vendor/github.com/cyphar/filepath-securejoin/join.go +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/join.go @@ -1,17 +1,11 @@ // Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved. -// Copyright (C) 2017 SUSE LLC. All rights reserved. +// Copyright (C) 2017-2024 SUSE LLC. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package securejoin is an implementation of the hopefully-soon-to-be-included -// SecureJoin helper that is meant to be part of the "path/filepath" package. -// The purpose of this project is to provide a PoC implementation to make the -// SecureJoin proposal (https://github.com/golang/go/issues/20126) more -// tangible. package securejoin import ( - "bytes" "errors" "os" "path/filepath" @@ -19,26 +13,34 @@ import ( "syscall" ) +const maxSymlinkLimit = 255 + // IsNotExist tells you if err is an error that implies that either the path // accessed does not exist (or path components don't exist). This is -// effectively a more broad version of os.IsNotExist. +// effectively a more broad version of [os.IsNotExist]. func IsNotExist(err error) bool { // Check that it's not actually an ENOTDIR, which in some cases is a more // convoluted case of ENOENT (usually involving weird paths). return errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) || errors.Is(err, syscall.ENOENT) } -// SecureJoinVFS joins the two given path components (similar to Join) except +// SecureJoinVFS joins the two given path components (similar to [filepath.Join]) except // that the returned path is guaranteed to be scoped inside the provided root // path (when evaluated). Any symbolic links in the path are evaluated with the // given root treated as the root of the filesystem, similar to a chroot. The -// filesystem state is evaluated through the given VFS interface (if nil, the -// standard os.* family of functions are used). +// filesystem state is evaluated through the given [VFS] interface (if nil, the +// standard [os].* family of functions are used). // // Note that the guarantees provided by this function only apply if the path // components in the returned string are not modified (in other words are not // replaced with symlinks on the filesystem) after this function has returned. -// Such a symlink race is necessarily out-of-scope of SecureJoin. +// Such a symlink race is necessarily out-of-scope of SecureJoinVFS. +// +// NOTE: Due to the above limitation, Linux users are strongly encouraged to +// use [OpenInRoot] instead, which does safely protect against these kinds of +// attacks. There is no way to solve this problem with SecureJoinVFS because +// the API is fundamentally wrong (you cannot return a "safe" path string and +// guarantee it won't be modified afterwards). // // Volume names in unsafePath are always discarded, regardless if they are // provided via direct input or when evaluating symlinks. Therefore: @@ -51,75 +53,73 @@ func SecureJoinVFS(root, unsafePath string, vfs VFS) (string, error) { } unsafePath = filepath.FromSlash(unsafePath) - var path bytes.Buffer - n := 0 - for unsafePath != "" { - if n > 255 { - return "", &os.PathError{Op: "SecureJoin", Path: root + string(filepath.Separator) + unsafePath, Err: syscall.ELOOP} + var ( + currentPath string + remainingPath = unsafePath + linksWalked int + ) + for remainingPath != "" { + if v := filepath.VolumeName(remainingPath); v != "" { + remainingPath = remainingPath[len(v):] } - if v := filepath.VolumeName(unsafePath); v != "" { - unsafePath = unsafePath[len(v):] - } - - // Next path component, p. - i := strings.IndexRune(unsafePath, filepath.Separator) - var p string - if i == -1 { - p, unsafePath = unsafePath, "" + // Get the next path component. + var part string + if i := strings.IndexRune(remainingPath, filepath.Separator); i == -1 { + part, remainingPath = remainingPath, "" } else { - p, unsafePath = unsafePath[:i], unsafePath[i+1:] + part, remainingPath = remainingPath[:i], remainingPath[i+1:] } - // Create a cleaned path, using the lexical semantics of /../a, to - // create a "scoped" path component which can safely be joined to fullP - // for evaluation. At this point, path.String() doesn't contain any - // symlink components. - cleanP := filepath.Clean(string(filepath.Separator) + path.String() + p) - if cleanP == string(filepath.Separator) { - path.Reset() + // Apply the component lexically to the path we are building. + // currentPath does not contain any symlinks, and we are lexically + // dealing with a single component, so it's okay to do a filepath.Clean + // here. + nextPath := filepath.Join(string(filepath.Separator), currentPath, part) + if nextPath == string(filepath.Separator) { + currentPath = "" continue } - fullP := filepath.Clean(root + cleanP) + fullPath := root + string(filepath.Separator) + nextPath // Figure out whether the path is a symlink. - fi, err := vfs.Lstat(fullP) + fi, err := vfs.Lstat(fullPath) if err != nil && !IsNotExist(err) { return "", err } // Treat non-existent path components the same as non-symlinks (we // can't do any better here). if IsNotExist(err) || fi.Mode()&os.ModeSymlink == 0 { - path.WriteString(p) - path.WriteRune(filepath.Separator) + currentPath = nextPath continue } - // Only increment when we actually dereference a link. - n++ + // It's a symlink, so get its contents and expand it by prepending it + // to the yet-unparsed path. + linksWalked++ + if linksWalked > maxSymlinkLimit { + return "", &os.PathError{Op: "SecureJoin", Path: root + string(filepath.Separator) + unsafePath, Err: syscall.ELOOP} + } - // It's a symlink, expand it by prepending it to the yet-unparsed path. - dest, err := vfs.Readlink(fullP) + dest, err := vfs.Readlink(fullPath) if err != nil { return "", err } + remainingPath = dest + string(filepath.Separator) + remainingPath // Absolute symlinks reset any work we've already done. if filepath.IsAbs(dest) { - path.Reset() + currentPath = "" } - unsafePath = dest + string(filepath.Separator) + unsafePath } - // We have to clean path.String() here because it may contain '..' - // components that are entirely lexical, but would be misleading otherwise. - // And finally do a final clean to ensure that root is also lexically - // clean. - fullP := filepath.Clean(string(filepath.Separator) + path.String()) - return filepath.Clean(root + fullP), nil + // There should be no lexical components like ".." left in the path here, + // but for safety clean up the path before joining it to the root. + finalPath := filepath.Join(string(filepath.Separator), currentPath) + return filepath.Join(root, finalPath), nil } -// SecureJoin is a wrapper around SecureJoinVFS that just uses the os.* library -// of functions as the VFS. If in doubt, use this function over SecureJoinVFS. +// SecureJoin is a wrapper around [SecureJoinVFS] that just uses the [os].* library +// of functions as the [VFS]. If in doubt, use this function over [SecureJoinVFS]. func SecureJoin(root, unsafePath string) (string, error) { return SecureJoinVFS(root, unsafePath, nil) } diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/lookup_linux.go b/tests/vendor/github.com/cyphar/filepath-securejoin/lookup_linux.go new file mode 100644 index 000000000..290befa15 --- /dev/null +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/lookup_linux.go @@ -0,0 +1,389 @@ +//go:build linux + +// Copyright (C) 2024 SUSE LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package securejoin + +import ( + "errors" + "fmt" + "os" + "path" + "path/filepath" + "slices" + "strings" + + "golang.org/x/sys/unix" +) + +type symlinkStackEntry struct { + // (dir, remainingPath) is what we would've returned if the link didn't + // exist. This matches what openat2(RESOLVE_IN_ROOT) would return in + // this case. + dir *os.File + remainingPath string + // linkUnwalked is the remaining path components from the original + // Readlink which we have yet to walk. When this slice is empty, we + // drop the link from the stack. + linkUnwalked []string +} + +func (se symlinkStackEntry) String() string { + return fmt.Sprintf("<%s>/%s [->%s]", se.dir.Name(), se.remainingPath, strings.Join(se.linkUnwalked, "/")) +} + +func (se symlinkStackEntry) Close() { + _ = se.dir.Close() +} + +type symlinkStack []*symlinkStackEntry + +func (s *symlinkStack) IsEmpty() bool { + return s == nil || len(*s) == 0 +} + +func (s *symlinkStack) Close() { + if s != nil { + for _, link := range *s { + link.Close() + } + // TODO: Switch to clear once we switch to Go 1.21. + *s = nil + } +} + +var ( + errEmptyStack = errors.New("[internal] stack is empty") + errBrokenSymlinkStack = errors.New("[internal error] broken symlink stack") +) + +func (s *symlinkStack) popPart(part string) error { + if s == nil || s.IsEmpty() { + // If there is nothing in the symlink stack, then the part was from the + // real path provided by the user, and this is a no-op. + return errEmptyStack + } + if part == "." { + // "." components are no-ops -- we drop them when doing SwapLink. + return nil + } + + tailEntry := (*s)[len(*s)-1] + + // Double-check that we are popping the component we expect. + if len(tailEntry.linkUnwalked) == 0 { + return fmt.Errorf("%w: trying to pop component %q of empty stack entry %s", errBrokenSymlinkStack, part, tailEntry) + } + headPart := tailEntry.linkUnwalked[0] + if headPart != part { + return fmt.Errorf("%w: trying to pop component %q but the last stack entry is %s (%q)", errBrokenSymlinkStack, part, tailEntry, headPart) + } + + // Drop the component, but keep the entry around in case we are dealing + // with a "tail-chained" symlink. + tailEntry.linkUnwalked = tailEntry.linkUnwalked[1:] + return nil +} + +func (s *symlinkStack) PopPart(part string) error { + if err := s.popPart(part); err != nil { + if errors.Is(err, errEmptyStack) { + // Skip empty stacks. + err = nil + } + return err + } + + // Clean up any of the trailing stack entries that are empty. + for lastGood := len(*s) - 1; lastGood >= 0; lastGood-- { + entry := (*s)[lastGood] + if len(entry.linkUnwalked) > 0 { + break + } + entry.Close() + (*s) = (*s)[:lastGood] + } + return nil +} + +func (s *symlinkStack) push(dir *os.File, remainingPath, linkTarget string) error { + if s == nil { + return nil + } + // Split the link target and clean up any "" parts. + linkTargetParts := slices.DeleteFunc( + strings.Split(linkTarget, "/"), + func(part string) bool { return part == "" || part == "." }) + + // Copy the directory so the caller doesn't close our copy. + dirCopy, err := dupFile(dir) + if err != nil { + return err + } + + // Add to the stack. + *s = append(*s, &symlinkStackEntry{ + dir: dirCopy, + remainingPath: remainingPath, + linkUnwalked: linkTargetParts, + }) + return nil +} + +func (s *symlinkStack) SwapLink(linkPart string, dir *os.File, remainingPath, linkTarget string) error { + // If we are currently inside a symlink resolution, remove the symlink + // component from the last symlink entry, but don't remove the entry even + // if it's empty. If we are a "tail-chained" symlink (a trailing symlink we + // hit during a symlink resolution) we need to keep the old symlink until + // we finish the resolution. + if err := s.popPart(linkPart); err != nil { + if !errors.Is(err, errEmptyStack) { + return err + } + // Push the component regardless of whether the stack was empty. + } + return s.push(dir, remainingPath, linkTarget) +} + +func (s *symlinkStack) PopTopSymlink() (*os.File, string, bool) { + if s == nil || s.IsEmpty() { + return nil, "", false + } + tailEntry := (*s)[0] + *s = (*s)[1:] + return tailEntry.dir, tailEntry.remainingPath, true +} + +// partialLookupInRoot tries to lookup as much of the request path as possible +// within the provided root (a-la RESOLVE_IN_ROOT) and opens the final existing +// component of the requested path, returning a file handle to the final +// existing component and a string containing the remaining path components. +func partialLookupInRoot(root *os.File, unsafePath string) (*os.File, string, error) { + return lookupInRoot(root, unsafePath, true) +} + +func completeLookupInRoot(root *os.File, unsafePath string) (*os.File, error) { + handle, remainingPath, err := lookupInRoot(root, unsafePath, false) + if remainingPath != "" && err == nil { + // should never happen + err = fmt.Errorf("[bug] non-empty remaining path when doing a non-partial lookup: %q", remainingPath) + } + // lookupInRoot(partial=false) will always close the handle if an error is + // returned, so no need to double-check here. + return handle, err +} + +func lookupInRoot(root *os.File, unsafePath string, partial bool) (Handle *os.File, _ string, _ error) { + unsafePath = filepath.ToSlash(unsafePath) // noop + + // This is very similar to SecureJoin, except that we operate on the + // components using file descriptors. We then return the last component we + // managed open, along with the remaining path components not opened. + + // Try to use openat2 if possible. + if hasOpenat2() { + return lookupOpenat2(root, unsafePath, partial) + } + + // Get the "actual" root path from /proc/self/fd. This is necessary if the + // root is some magic-link like /proc/$pid/root, in which case we want to + // make sure when we do checkProcSelfFdPath that we are using the correct + // root path. + logicalRootPath, err := procSelfFdReadlink(root) + if err != nil { + return nil, "", fmt.Errorf("get real root path: %w", err) + } + + currentDir, err := dupFile(root) + if err != nil { + return nil, "", fmt.Errorf("clone root fd: %w", err) + } + defer func() { + // If a handle is not returned, close the internal handle. + if Handle == nil { + _ = currentDir.Close() + } + }() + + // symlinkStack is used to emulate how openat2(RESOLVE_IN_ROOT) treats + // dangling symlinks. If we hit a non-existent path while resolving a + // symlink, we need to return the (dir, remainingPath) that we had when we + // hit the symlink (treating the symlink as though it were a regular file). + // The set of (dir, remainingPath) sets is stored within the symlinkStack + // and we add and remove parts when we hit symlink and non-symlink + // components respectively. We need a stack because of recursive symlinks + // (symlinks that contain symlink components in their target). + // + // Note that the stack is ONLY used for book-keeping. All of the actual + // path walking logic is still based on currentPath/remainingPath and + // currentDir (as in SecureJoin). + var symStack *symlinkStack + if partial { + symStack = new(symlinkStack) + defer symStack.Close() + } + + var ( + linksWalked int + currentPath string + remainingPath = unsafePath + ) + for remainingPath != "" { + // Save the current remaining path so if the part is not real we can + // return the path including the component. + oldRemainingPath := remainingPath + + // Get the next path component. + var part string + if i := strings.IndexByte(remainingPath, '/'); i == -1 { + part, remainingPath = remainingPath, "" + } else { + part, remainingPath = remainingPath[:i], remainingPath[i+1:] + } + // If we hit an empty component, we need to treat it as though it is + // "." so that trailing "/" and "//" components on a non-directory + // correctly return the right error code. + if part == "" { + part = "." + } + + // Apply the component lexically to the path we are building. + // currentPath does not contain any symlinks, and we are lexically + // dealing with a single component, so it's okay to do a filepath.Clean + // here. + nextPath := path.Join("/", currentPath, part) + // If we logically hit the root, just clone the root rather than + // opening the part and doing all of the other checks. + if nextPath == "/" { + if err := symStack.PopPart(part); err != nil { + return nil, "", fmt.Errorf("walking into root with part %q failed: %w", part, err) + } + // Jump to root. + rootClone, err := dupFile(root) + if err != nil { + return nil, "", fmt.Errorf("clone root fd: %w", err) + } + _ = currentDir.Close() + currentDir = rootClone + currentPath = nextPath + continue + } + + // Try to open the next component. + nextDir, err := openatFile(currentDir, part, unix.O_PATH|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0) + switch { + case err == nil: + st, err := nextDir.Stat() + if err != nil { + _ = nextDir.Close() + return nil, "", fmt.Errorf("stat component %q: %w", part, err) + } + + switch st.Mode() & os.ModeType { + case os.ModeSymlink: + // readlinkat implies AT_EMPTY_PATH since Linux 2.6.39. See + // Linux commit 65cfc6722361 ("readlinkat(), fchownat() and + // fstatat() with empty relative pathnames"). + linkDest, err := readlinkatFile(nextDir, "") + // We don't need the handle anymore. + _ = nextDir.Close() + if err != nil { + return nil, "", err + } + + linksWalked++ + if linksWalked > maxSymlinkLimit { + return nil, "", &os.PathError{Op: "securejoin.lookupInRoot", Path: logicalRootPath + "/" + unsafePath, Err: unix.ELOOP} + } + + // Swap out the symlink's component for the link entry itself. + if err := symStack.SwapLink(part, currentDir, oldRemainingPath, linkDest); err != nil { + return nil, "", fmt.Errorf("walking into symlink %q failed: push symlink: %w", part, err) + } + + // Update our logical remaining path. + remainingPath = linkDest + "/" + remainingPath + // Absolute symlinks reset any work we've already done. + if path.IsAbs(linkDest) { + // Jump to root. + rootClone, err := dupFile(root) + if err != nil { + return nil, "", fmt.Errorf("clone root fd: %w", err) + } + _ = currentDir.Close() + currentDir = rootClone + currentPath = "/" + } + + default: + // If we are dealing with a directory, simply walk into it. + _ = currentDir.Close() + currentDir = nextDir + currentPath = nextPath + + // The part was real, so drop it from the symlink stack. + if err := symStack.PopPart(part); err != nil { + return nil, "", fmt.Errorf("walking into directory %q failed: %w", part, err) + } + + // If we are operating on a .., make sure we haven't escaped. + // We only have to check for ".." here because walking down + // into a regular component component cannot cause you to + // escape. This mirrors the logic in RESOLVE_IN_ROOT, except we + // have to check every ".." rather than only checking after a + // rename or mount on the system. + if part == ".." { + // Make sure the root hasn't moved. + if err := checkProcSelfFdPath(logicalRootPath, root); err != nil { + return nil, "", fmt.Errorf("root path moved during lookup: %w", err) + } + // Make sure the path is what we expect. + fullPath := logicalRootPath + nextPath + if err := checkProcSelfFdPath(fullPath, currentDir); err != nil { + return nil, "", fmt.Errorf("walking into %q had unexpected result: %w", part, err) + } + } + } + + default: + if !partial { + return nil, "", err + } + // If there are any remaining components in the symlink stack, we + // are still within a symlink resolution and thus we hit a dangling + // symlink. So pretend that the first symlink in the stack we hit + // was an ENOENT (to match openat2). + if oldDir, remainingPath, ok := symStack.PopTopSymlink(); ok { + _ = currentDir.Close() + return oldDir, remainingPath, err + } + // We have hit a final component that doesn't exist, so we have our + // partial open result. Note that we have to use the OLD remaining + // path, since the lookup failed. + return currentDir, oldRemainingPath, err + } + } + + // If the unsafePath had a trailing slash, we need to make sure we try to + // do a relative "." open so that we will correctly return an error when + // the final component is a non-directory (to match openat2). In the + // context of openat2, a trailing slash and a trailing "/." are completely + // equivalent. + if strings.HasSuffix(unsafePath, "/") { + nextDir, err := openatFile(currentDir, ".", unix.O_PATH|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0) + if err != nil { + if !partial { + _ = currentDir.Close() + currentDir = nil + } + return currentDir, "", err + } + _ = currentDir.Close() + currentDir = nextDir + } + + // All of the components existed! + return currentDir, "", nil +} diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/mkdir_linux.go b/tests/vendor/github.com/cyphar/filepath-securejoin/mkdir_linux.go new file mode 100644 index 000000000..6dfe8c42b --- /dev/null +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/mkdir_linux.go @@ -0,0 +1,212 @@ +//go:build linux + +// Copyright (C) 2024 SUSE LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package securejoin + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "slices" + "strings" + + "golang.org/x/sys/unix" +) + +var ( + errInvalidMode = errors.New("invalid permission mode") + errPossibleAttack = errors.New("possible attack detected") +) + +// MkdirAllHandle is equivalent to [MkdirAll], except that it is safer to use +// in two respects: +// +// - The caller provides the root directory as an *[os.File] (preferably O_PATH) +// handle. This means that the caller can be sure which root directory is +// being used. Note that this can be emulated by using /proc/self/fd/... as +// the root path with [os.MkdirAll]. +// +// - Once all of the directories have been created, an *[os.File] O_PATH handle +// to the directory at unsafePath is returned to the caller. This is done in +// an effectively-race-free way (an attacker would only be able to swap the +// final directory component), which is not possible to emulate with +// [MkdirAll]. +// +// In addition, the returned handle is obtained far more efficiently than doing +// a brand new lookup of unsafePath (such as with [SecureJoin] or openat2) after +// doing [MkdirAll]. If you intend to open the directory after creating it, you +// should use MkdirAllHandle. +func MkdirAllHandle(root *os.File, unsafePath string, mode int) (_ *os.File, Err error) { + // Make sure there are no os.FileMode bits set. + if mode&^0o7777 != 0 { + return nil, fmt.Errorf("%w for mkdir 0o%.3o", errInvalidMode, mode) + } + // On Linux, mkdirat(2) (and os.Mkdir) silently ignore the suid and sgid + // bits. We could also silently ignore them but since we have very few + // users it seems more prudent to return an error so users notice that + // these bits will not be set. + if mode&^0o1777 != 0 { + return nil, fmt.Errorf("%w for mkdir 0o%.3o: suid and sgid are ignored by mkdir", errInvalidMode, mode) + } + + // Try to open as much of the path as possible. + currentDir, remainingPath, err := partialLookupInRoot(root, unsafePath) + defer func() { + if Err != nil { + _ = currentDir.Close() + } + }() + if err != nil && !errors.Is(err, unix.ENOENT) { + return nil, fmt.Errorf("find existing subpath of %q: %w", unsafePath, err) + } + + // If there is an attacker deleting directories as we walk into them, + // detect this proactively. Note this is guaranteed to detect if the + // attacker deleted any part of the tree up to currentDir. + // + // Once we walk into a dead directory, partialLookupInRoot would not be + // able to walk further down the tree (directories must be empty before + // they are deleted), and if the attacker has removed the entire tree we + // can be sure that anything that was originally inside a dead directory + // must also be deleted and thus is a dead directory in its own right. + // + // This is mostly a quality-of-life check, because mkdir will simply fail + // later if the attacker deletes the tree after this check. + if err := isDeadInode(currentDir); err != nil { + return nil, fmt.Errorf("finding existing subpath of %q: %w", unsafePath, err) + } + + // Re-open the path to match the O_DIRECTORY reopen loop later (so that we + // always return a non-O_PATH handle). We also check that we actually got a + // directory. + if reopenDir, err := Reopen(currentDir, unix.O_DIRECTORY|unix.O_CLOEXEC); errors.Is(err, unix.ENOTDIR) { + return nil, fmt.Errorf("cannot create subdirectories in %q: %w", currentDir.Name(), unix.ENOTDIR) + } else if err != nil { + return nil, fmt.Errorf("re-opening handle to %q: %w", currentDir.Name(), err) + } else { + _ = currentDir.Close() + currentDir = reopenDir + } + + remainingParts := strings.Split(remainingPath, string(filepath.Separator)) + if slices.Contains(remainingParts, "..") { + // The path contained ".." components after the end of the "real" + // components. We could try to safely resolve ".." here but that would + // add a bunch of extra logic for something that it's not clear even + // needs to be supported. So just return an error. + // + // If we do filepath.Clean(remainingPath) then we end up with the + // problem that ".." can erase a trailing dangling symlink and produce + // a path that doesn't quite match what the user asked for. + return nil, fmt.Errorf("%w: yet-to-be-created path %q contains '..' components", unix.ENOENT, remainingPath) + } + + // Make sure the mode doesn't have any type bits. + mode &^= unix.S_IFMT + + // Create the remaining components. + for _, part := range remainingParts { + switch part { + case "", ".": + // Skip over no-op paths. + continue + } + + // NOTE: mkdir(2) will not follow trailing symlinks, so we can safely + // create the final component without worrying about symlink-exchange + // attacks. + // + // If we get -EEXIST, it's possible that another program created the + // directory at the same time as us. In that case, just continue on as + // if we created it (if the created inode is not a directory, the + // following open call will fail). + if err := unix.Mkdirat(int(currentDir.Fd()), part, uint32(mode)); err != nil && !errors.Is(err, unix.EEXIST) { + err = &os.PathError{Op: "mkdirat", Path: currentDir.Name() + "/" + part, Err: err} + // Make the error a bit nicer if the directory is dead. + if err2 := isDeadInode(currentDir); err2 != nil { + err = fmt.Errorf("%w (%w)", err, err2) + } + return nil, err + } + + // Get a handle to the next component. O_DIRECTORY means we don't need + // to use O_PATH. + var nextDir *os.File + if hasOpenat2() { + nextDir, err = openat2File(currentDir, part, &unix.OpenHow{ + Flags: unix.O_NOFOLLOW | unix.O_DIRECTORY | unix.O_CLOEXEC, + Resolve: unix.RESOLVE_BENEATH | unix.RESOLVE_NO_SYMLINKS | unix.RESOLVE_NO_XDEV, + }) + } else { + nextDir, err = openatFile(currentDir, part, unix.O_NOFOLLOW|unix.O_DIRECTORY|unix.O_CLOEXEC, 0) + } + if err != nil { + return nil, err + } + _ = currentDir.Close() + currentDir = nextDir + + // It's possible that the directory we just opened was swapped by an + // attacker. Unfortunately there isn't much we can do to protect + // against this, and MkdirAll's behaviour is that we will reuse + // existing directories anyway so the need to protect against this is + // incredibly limited (and arguably doesn't even deserve mention here). + // + // Ideally we might want to check that the owner and mode match what we + // would've created -- unfortunately, it is non-trivial to verify that + // the owner and mode of the created directory match. While plain Unix + // DAC rules seem simple enough to emulate, there are a bunch of other + // factors that can change the mode or owner of created directories + // (default POSIX ACLs, mount options like uid=1,gid=2,umask=0 on + // filesystems like vfat, etc etc). We used to try to verify this but + // it just lead to a series of spurious errors. + // + // We could also check that the directory is non-empty, but + // unfortunately some pseduofilesystems (like cgroupfs) create + // non-empty directories, which would result in different spurious + // errors. + } + return currentDir, nil +} + +// MkdirAll is a race-safe alternative to the [os.MkdirAll] function, +// where the new directory is guaranteed to be within the root directory (if an +// attacker can move directories from inside the root to outside the root, the +// created directory tree might be outside of the root but the key constraint +// is that at no point will we walk outside of the directory tree we are +// creating). +// +// Effectively, MkdirAll(root, unsafePath, mode) is equivalent to +// +// path, _ := securejoin.SecureJoin(root, unsafePath) +// err := os.MkdirAll(path, mode) +// +// But is much safer. The above implementation is unsafe because if an attacker +// can modify the filesystem tree between [SecureJoin] and [os.MkdirAll], it is +// possible for MkdirAll to resolve unsafe symlink components and create +// directories outside of the root. +// +// If you plan to open the directory after you have created it or want to use +// an open directory handle as the root, you should use [MkdirAllHandle] instead. +// This function is a wrapper around [MkdirAllHandle]. +// +// NOTE: The mode argument must be set the unix mode bits (unix.S_I...), not +// the Go generic mode bits ([os.FileMode]...). +func MkdirAll(root, unsafePath string, mode int) error { + rootDir, err := os.OpenFile(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0) + if err != nil { + return err + } + defer rootDir.Close() + + f, err := MkdirAllHandle(rootDir, unsafePath, mode) + if err != nil { + return err + } + _ = f.Close() + return nil +} diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/open_linux.go b/tests/vendor/github.com/cyphar/filepath-securejoin/open_linux.go new file mode 100644 index 000000000..230be73f0 --- /dev/null +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/open_linux.go @@ -0,0 +1,103 @@ +//go:build linux + +// Copyright (C) 2024 SUSE LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package securejoin + +import ( + "fmt" + "os" + "strconv" + + "golang.org/x/sys/unix" +) + +// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided +// using an *[os.File] handle, to ensure that the correct root directory is used. +func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) { + handle, err := completeLookupInRoot(root, unsafePath) + if err != nil { + return nil, &os.PathError{Op: "securejoin.OpenInRoot", Path: unsafePath, Err: err} + } + return handle, nil +} + +// OpenInRoot safely opens the provided unsafePath within the root. +// Effectively, OpenInRoot(root, unsafePath) is equivalent to +// +// path, _ := securejoin.SecureJoin(root, unsafePath) +// handle, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC) +// +// But is much safer. The above implementation is unsafe because if an attacker +// can modify the filesystem tree between [SecureJoin] and [os.OpenFile], it is +// possible for the returned file to be outside of the root. +// +// Note that the returned handle is an O_PATH handle, meaning that only a very +// limited set of operations will work on the handle. This is done to avoid +// accidentally opening an untrusted file that could cause issues (such as a +// disconnected TTY that could cause a DoS, or some other issue). In order to +// use the returned handle, you can "upgrade" it to a proper handle using +// [Reopen]. +func OpenInRoot(root, unsafePath string) (*os.File, error) { + rootDir, err := os.OpenFile(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0) + if err != nil { + return nil, err + } + defer rootDir.Close() + return OpenatInRoot(rootDir, unsafePath) +} + +// Reopen takes an *[os.File] handle and re-opens it through /proc/self/fd. +// Reopen(file, flags) is effectively equivalent to +// +// fdPath := fmt.Sprintf("/proc/self/fd/%d", file.Fd()) +// os.OpenFile(fdPath, flags|unix.O_CLOEXEC) +// +// But with some extra hardenings to ensure that we are not tricked by a +// maliciously-configured /proc mount. While this attack scenario is not +// common, in container runtimes it is possible for higher-level runtimes to be +// tricked into configuring an unsafe /proc that can be used to attack file +// operations. See [CVE-2019-19921] for more details. +// +// [CVE-2019-19921]: https://github.com/advisories/GHSA-fh74-hm69-rqjw +func Reopen(handle *os.File, flags int) (*os.File, error) { + procRoot, err := getProcRoot() + if err != nil { + return nil, err + } + + // We can't operate on /proc/thread-self/fd/$n directly when doing a + // re-open, so we need to open /proc/thread-self/fd and then open a single + // final component. + procFdDir, closer, err := procThreadSelf(procRoot, "fd/") + if err != nil { + return nil, fmt.Errorf("get safe /proc/thread-self/fd handle: %w", err) + } + defer procFdDir.Close() + defer closer() + + // Try to detect if there is a mount on top of the magic-link we are about + // to open. If we are using unsafeHostProcRoot(), this could change after + // we check it (and there's nothing we can do about that) but for + // privateProcRoot() this should be guaranteed to be safe (at least since + // Linux 5.12[1], when anonymous mount namespaces were completely isolated + // from external mounts including mount propagation events). + // + // [1]: Linux commit ee2e3f50629f ("mount: fix mounting of detached mounts + // onto targets that reside on shared mounts"). + fdStr := strconv.Itoa(int(handle.Fd())) + if err := checkSymlinkOvermount(procRoot, procFdDir, fdStr); err != nil { + return nil, fmt.Errorf("check safety of /proc/thread-self/fd/%s magiclink: %w", fdStr, err) + } + + flags |= unix.O_CLOEXEC + // Rather than just wrapping openatFile, open-code it so we can copy + // handle.Name(). + reopenFd, err := unix.Openat(int(procFdDir.Fd()), fdStr, flags, 0) + if err != nil { + return nil, fmt.Errorf("reopen fd %d: %w", handle.Fd(), err) + } + return os.NewFile(uintptr(reopenFd), handle.Name()), nil +} diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/openat2_linux.go b/tests/vendor/github.com/cyphar/filepath-securejoin/openat2_linux.go new file mode 100644 index 000000000..ae3b381ef --- /dev/null +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/openat2_linux.go @@ -0,0 +1,128 @@ +//go:build linux + +// Copyright (C) 2024 SUSE LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package securejoin + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + "sync" + + "golang.org/x/sys/unix" +) + +var hasOpenat2 = sync.OnceValue(func() bool { + fd, err := unix.Openat2(unix.AT_FDCWD, ".", &unix.OpenHow{ + Flags: unix.O_PATH | unix.O_CLOEXEC, + Resolve: unix.RESOLVE_NO_SYMLINKS | unix.RESOLVE_IN_ROOT, + }) + if err != nil { + return false + } + _ = unix.Close(fd) + return true +}) + +func scopedLookupShouldRetry(how *unix.OpenHow, err error) bool { + // RESOLVE_IN_ROOT (and RESOLVE_BENEATH) can return -EAGAIN if we resolve + // ".." while a mount or rename occurs anywhere on the system. This could + // happen spuriously, or as the result of an attacker trying to mess with + // us during lookup. + // + // In addition, scoped lookups have a "safety check" at the end of + // complete_walk which will return -EXDEV if the final path is not in the + // root. + return how.Resolve&(unix.RESOLVE_IN_ROOT|unix.RESOLVE_BENEATH) != 0 && + (errors.Is(err, unix.EAGAIN) || errors.Is(err, unix.EXDEV)) +} + +const scopedLookupMaxRetries = 10 + +func openat2File(dir *os.File, path string, how *unix.OpenHow) (*os.File, error) { + fullPath := dir.Name() + "/" + path + // Make sure we always set O_CLOEXEC. + how.Flags |= unix.O_CLOEXEC + var tries int + for tries < scopedLookupMaxRetries { + fd, err := unix.Openat2(int(dir.Fd()), path, how) + if err != nil { + if scopedLookupShouldRetry(how, err) { + // We retry a couple of times to avoid the spurious errors, and + // if we are being attacked then returning -EAGAIN is the best + // we can do. + tries++ + continue + } + return nil, &os.PathError{Op: "openat2", Path: fullPath, Err: err} + } + // If we are using RESOLVE_IN_ROOT, the name we generated may be wrong. + // NOTE: The procRoot code MUST NOT use RESOLVE_IN_ROOT, otherwise + // you'll get infinite recursion here. + if how.Resolve&unix.RESOLVE_IN_ROOT == unix.RESOLVE_IN_ROOT { + if actualPath, err := rawProcSelfFdReadlink(fd); err == nil { + fullPath = actualPath + } + } + return os.NewFile(uintptr(fd), fullPath), nil + } + return nil, &os.PathError{Op: "openat2", Path: fullPath, Err: errPossibleAttack} +} + +func lookupOpenat2(root *os.File, unsafePath string, partial bool) (*os.File, string, error) { + if !partial { + file, err := openat2File(root, unsafePath, &unix.OpenHow{ + Flags: unix.O_PATH | unix.O_CLOEXEC, + Resolve: unix.RESOLVE_IN_ROOT | unix.RESOLVE_NO_MAGICLINKS, + }) + return file, "", err + } + return partialLookupOpenat2(root, unsafePath) +} + +// partialLookupOpenat2 is an alternative implementation of +// partialLookupInRoot, using openat2(RESOLVE_IN_ROOT) to more safely get a +// handle to the deepest existing child of the requested path within the root. +func partialLookupOpenat2(root *os.File, unsafePath string) (*os.File, string, error) { + // TODO: Implement this as a git-bisect-like binary search. + + unsafePath = filepath.ToSlash(unsafePath) // noop + endIdx := len(unsafePath) + var lastError error + for endIdx > 0 { + subpath := unsafePath[:endIdx] + + handle, err := openat2File(root, subpath, &unix.OpenHow{ + Flags: unix.O_PATH | unix.O_CLOEXEC, + Resolve: unix.RESOLVE_IN_ROOT | unix.RESOLVE_NO_MAGICLINKS, + }) + if err == nil { + // Jump over the slash if we have a non-"" remainingPath. + if endIdx < len(unsafePath) { + endIdx += 1 + } + // We found a subpath! + return handle, unsafePath[endIdx:], lastError + } + if errors.Is(err, unix.ENOENT) || errors.Is(err, unix.ENOTDIR) { + // That path doesn't exist, let's try the next directory up. + endIdx = strings.LastIndexByte(subpath, '/') + lastError = err + continue + } + return nil, "", fmt.Errorf("open subpath: %w", err) + } + // If we couldn't open anything, the whole subpath is missing. Return a + // copy of the root fd so that the caller doesn't close this one by + // accident. + rootClone, err := dupFile(root) + if err != nil { + return nil, "", err + } + return rootClone, unsafePath, lastError +} diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/openat_linux.go b/tests/vendor/github.com/cyphar/filepath-securejoin/openat_linux.go new file mode 100644 index 000000000..949fb5f2d --- /dev/null +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/openat_linux.go @@ -0,0 +1,59 @@ +//go:build linux + +// Copyright (C) 2024 SUSE LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package securejoin + +import ( + "os" + "path/filepath" + + "golang.org/x/sys/unix" +) + +func dupFile(f *os.File) (*os.File, error) { + fd, err := unix.FcntlInt(f.Fd(), unix.F_DUPFD_CLOEXEC, 0) + if err != nil { + return nil, os.NewSyscallError("fcntl(F_DUPFD_CLOEXEC)", err) + } + return os.NewFile(uintptr(fd), f.Name()), nil +} + +func openatFile(dir *os.File, path string, flags int, mode int) (*os.File, error) { + // Make sure we always set O_CLOEXEC. + flags |= unix.O_CLOEXEC + fd, err := unix.Openat(int(dir.Fd()), path, flags, uint32(mode)) + if err != nil { + return nil, &os.PathError{Op: "openat", Path: dir.Name() + "/" + path, Err: err} + } + // All of the paths we use with openatFile(2) are guaranteed to be + // lexically safe, so we can use path.Join here. + fullPath := filepath.Join(dir.Name(), path) + return os.NewFile(uintptr(fd), fullPath), nil +} + +func fstatatFile(dir *os.File, path string, flags int) (unix.Stat_t, error) { + var stat unix.Stat_t + if err := unix.Fstatat(int(dir.Fd()), path, &stat, flags); err != nil { + return stat, &os.PathError{Op: "fstatat", Path: dir.Name() + "/" + path, Err: err} + } + return stat, nil +} + +func readlinkatFile(dir *os.File, path string) (string, error) { + size := 4096 + for { + linkBuf := make([]byte, size) + n, err := unix.Readlinkat(int(dir.Fd()), path, linkBuf) + if err != nil { + return "", &os.PathError{Op: "readlinkat", Path: dir.Name() + "/" + path, Err: err} + } + if n != size { + return string(linkBuf[:n]), nil + } + // Possible truncation, resize the buffer. + size *= 2 + } +} diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/procfs_linux.go b/tests/vendor/github.com/cyphar/filepath-securejoin/procfs_linux.go new file mode 100644 index 000000000..8cc827d70 --- /dev/null +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/procfs_linux.go @@ -0,0 +1,440 @@ +//go:build linux + +// Copyright (C) 2024 SUSE LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package securejoin + +import ( + "errors" + "fmt" + "os" + "runtime" + "strconv" + "sync" + + "golang.org/x/sys/unix" +) + +func fstat(f *os.File) (unix.Stat_t, error) { + var stat unix.Stat_t + if err := unix.Fstat(int(f.Fd()), &stat); err != nil { + return stat, &os.PathError{Op: "fstat", Path: f.Name(), Err: err} + } + return stat, nil +} + +func fstatfs(f *os.File) (unix.Statfs_t, error) { + var statfs unix.Statfs_t + if err := unix.Fstatfs(int(f.Fd()), &statfs); err != nil { + return statfs, &os.PathError{Op: "fstatfs", Path: f.Name(), Err: err} + } + return statfs, nil +} + +// The kernel guarantees that the root inode of a procfs mount has an +// f_type of PROC_SUPER_MAGIC and st_ino of PROC_ROOT_INO. +const ( + procSuperMagic = 0x9fa0 // PROC_SUPER_MAGIC + procRootIno = 1 // PROC_ROOT_INO +) + +func verifyProcRoot(procRoot *os.File) error { + if statfs, err := fstatfs(procRoot); err != nil { + return err + } else if statfs.Type != procSuperMagic { + return fmt.Errorf("%w: incorrect procfs root filesystem type 0x%x", errUnsafeProcfs, statfs.Type) + } + if stat, err := fstat(procRoot); err != nil { + return err + } else if stat.Ino != procRootIno { + return fmt.Errorf("%w: incorrect procfs root inode number %d", errUnsafeProcfs, stat.Ino) + } + return nil +} + +var hasNewMountApi = sync.OnceValue(func() bool { + // All of the pieces of the new mount API we use (fsopen, fsconfig, + // fsmount, open_tree) were added together in Linux 5.1[1,2], so we can + // just check for one of the syscalls and the others should also be + // available. + // + // Just try to use open_tree(2) to open a file without OPEN_TREE_CLONE. + // This is equivalent to openat(2), but tells us if open_tree is + // available (and thus all of the other basic new mount API syscalls). + // open_tree(2) is most light-weight syscall to test here. + // + // [1]: merge commit 400913252d09 + // [2]: + fd, err := unix.OpenTree(-int(unix.EBADF), "/", unix.OPEN_TREE_CLOEXEC) + if err != nil { + return false + } + _ = unix.Close(fd) + return true +}) + +func fsopen(fsName string, flags int) (*os.File, error) { + // Make sure we always set O_CLOEXEC. + flags |= unix.FSOPEN_CLOEXEC + fd, err := unix.Fsopen(fsName, flags) + if err != nil { + return nil, os.NewSyscallError("fsopen "+fsName, err) + } + return os.NewFile(uintptr(fd), "fscontext:"+fsName), nil +} + +func fsmount(ctx *os.File, flags, mountAttrs int) (*os.File, error) { + // Make sure we always set O_CLOEXEC. + flags |= unix.FSMOUNT_CLOEXEC + fd, err := unix.Fsmount(int(ctx.Fd()), flags, mountAttrs) + if err != nil { + return nil, os.NewSyscallError("fsmount "+ctx.Name(), err) + } + return os.NewFile(uintptr(fd), "fsmount:"+ctx.Name()), nil +} + +func newPrivateProcMount() (*os.File, error) { + procfsCtx, err := fsopen("proc", unix.FSOPEN_CLOEXEC) + if err != nil { + return nil, err + } + defer procfsCtx.Close() + + // Try to configure hidepid=ptraceable,subset=pid if possible, but ignore errors. + _ = unix.FsconfigSetString(int(procfsCtx.Fd()), "hidepid", "ptraceable") + _ = unix.FsconfigSetString(int(procfsCtx.Fd()), "subset", "pid") + + // Get an actual handle. + if err := unix.FsconfigCreate(int(procfsCtx.Fd())); err != nil { + return nil, os.NewSyscallError("fsconfig create procfs", err) + } + return fsmount(procfsCtx, unix.FSMOUNT_CLOEXEC, unix.MS_RDONLY|unix.MS_NODEV|unix.MS_NOEXEC|unix.MS_NOSUID) +} + +func openTree(dir *os.File, path string, flags uint) (*os.File, error) { + dirFd := -int(unix.EBADF) + dirName := "." + if dir != nil { + dirFd = int(dir.Fd()) + dirName = dir.Name() + } + // Make sure we always set O_CLOEXEC. + flags |= unix.OPEN_TREE_CLOEXEC + fd, err := unix.OpenTree(dirFd, path, flags) + if err != nil { + return nil, &os.PathError{Op: "open_tree", Path: path, Err: err} + } + return os.NewFile(uintptr(fd), dirName+"/"+path), nil +} + +func clonePrivateProcMount() (_ *os.File, Err error) { + // Try to make a clone without using AT_RECURSIVE if we can. If this works, + // we can be sure there are no over-mounts and so if the root is valid then + // we're golden. Otherwise, we have to deal with over-mounts. + procfsHandle, err := openTree(nil, "/proc", unix.OPEN_TREE_CLONE) + if err != nil || hookForcePrivateProcRootOpenTreeAtRecursive(procfsHandle) { + procfsHandle, err = openTree(nil, "/proc", unix.OPEN_TREE_CLONE|unix.AT_RECURSIVE) + } + if err != nil { + return nil, fmt.Errorf("creating a detached procfs clone: %w", err) + } + defer func() { + if Err != nil { + _ = procfsHandle.Close() + } + }() + if err := verifyProcRoot(procfsHandle); err != nil { + return nil, err + } + return procfsHandle, nil +} + +func privateProcRoot() (*os.File, error) { + if !hasNewMountApi() || hookForceGetProcRootUnsafe() { + return nil, fmt.Errorf("new mount api: %w", unix.ENOTSUP) + } + // Try to create a new procfs mount from scratch if we can. This ensures we + // can get a procfs mount even if /proc is fake (for whatever reason). + procRoot, err := newPrivateProcMount() + if err != nil || hookForcePrivateProcRootOpenTree(procRoot) { + // Try to clone /proc then... + procRoot, err = clonePrivateProcMount() + } + return procRoot, err +} + +func unsafeHostProcRoot() (_ *os.File, Err error) { + procRoot, err := os.OpenFile("/proc", unix.O_PATH|unix.O_NOFOLLOW|unix.O_DIRECTORY|unix.O_CLOEXEC, 0) + if err != nil { + return nil, err + } + defer func() { + if Err != nil { + _ = procRoot.Close() + } + }() + if err := verifyProcRoot(procRoot); err != nil { + return nil, err + } + return procRoot, nil +} + +func doGetProcRoot() (*os.File, error) { + procRoot, err := privateProcRoot() + if err != nil { + // Fall back to using a /proc handle if making a private mount failed. + // If we have openat2, at least we can avoid some kinds of over-mount + // attacks, but without openat2 there's not much we can do. + procRoot, err = unsafeHostProcRoot() + } + return procRoot, err +} + +var getProcRoot = sync.OnceValues(func() (*os.File, error) { + return doGetProcRoot() +}) + +var hasProcThreadSelf = sync.OnceValue(func() bool { + return unix.Access("/proc/thread-self/", unix.F_OK) == nil +}) + +var errUnsafeProcfs = errors.New("unsafe procfs detected") + +type procThreadSelfCloser func() + +// procThreadSelf returns a handle to /proc/thread-self/ (or an +// equivalent handle on older kernels where /proc/thread-self doesn't exist). +// Once finished with the handle, you must call the returned closer function +// (runtime.UnlockOSThread). You must not pass the returned *os.File to other +// Go threads or use the handle after calling the closer. +// +// This is similar to ProcThreadSelf from runc, but with extra hardening +// applied and using *os.File. +func procThreadSelf(procRoot *os.File, subpath string) (_ *os.File, _ procThreadSelfCloser, Err error) { + // We need to lock our thread until the caller is done with the handle + // because between getting the handle and using it we could get interrupted + // by the Go runtime and hit the case where the underlying thread is + // swapped out and the original thread is killed, resulting in + // pull-your-hair-out-hard-to-debug issues in the caller. + runtime.LockOSThread() + defer func() { + if Err != nil { + runtime.UnlockOSThread() + } + }() + + // Figure out what prefix we want to use. + threadSelf := "thread-self/" + if !hasProcThreadSelf() || hookForceProcSelfTask() { + /// Pre-3.17 kernels don't have /proc/thread-self, so do it manually. + threadSelf = "self/task/" + strconv.Itoa(unix.Gettid()) + "/" + if _, err := fstatatFile(procRoot, threadSelf, unix.AT_SYMLINK_NOFOLLOW); err != nil || hookForceProcSelf() { + // In this case, we running in a pid namespace that doesn't match + // the /proc mount we have. This can happen inside runc. + // + // Unfortunately, there is no nice way to get the correct TID to + // use here because of the age of the kernel, so we have to just + // use /proc/self and hope that it works. + threadSelf = "self/" + } + } + + // Grab the handle. + var ( + handle *os.File + err error + ) + if hasOpenat2() { + // We prefer being able to use RESOLVE_NO_XDEV if we can, to be + // absolutely sure we are operating on a clean /proc handle that + // doesn't have any cheeky overmounts that could trick us (including + // symlink mounts on top of /proc/thread-self). RESOLVE_BENEATH isn't + // strictly needed, but just use it since we have it. + // + // NOTE: /proc/self is technically a magic-link (the contents of the + // symlink are generated dynamically), but it doesn't use + // nd_jump_link() so RESOLVE_NO_MAGICLINKS allows it. + // + // NOTE: We MUST NOT use RESOLVE_IN_ROOT here, as openat2File uses + // procSelfFdReadlink to clean up the returned f.Name() if we use + // RESOLVE_IN_ROOT (which would lead to an infinite recursion). + handle, err = openat2File(procRoot, threadSelf+subpath, &unix.OpenHow{ + Flags: unix.O_PATH | unix.O_NOFOLLOW | unix.O_CLOEXEC, + Resolve: unix.RESOLVE_BENEATH | unix.RESOLVE_NO_XDEV | unix.RESOLVE_NO_MAGICLINKS, + }) + if err != nil { + return nil, nil, fmt.Errorf("%w: %w", errUnsafeProcfs, err) + } + } else { + handle, err = openatFile(procRoot, threadSelf+subpath, unix.O_PATH|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0) + if err != nil { + return nil, nil, fmt.Errorf("%w: %w", errUnsafeProcfs, err) + } + defer func() { + if Err != nil { + _ = handle.Close() + } + }() + // We can't detect bind-mounts of different parts of procfs on top of + // /proc (a-la RESOLVE_NO_XDEV), but we can at least be sure that we + // aren't on the wrong filesystem here. + if statfs, err := fstatfs(handle); err != nil { + return nil, nil, err + } else if statfs.Type != procSuperMagic { + return nil, nil, fmt.Errorf("%w: incorrect /proc/self/fd filesystem type 0x%x", errUnsafeProcfs, statfs.Type) + } + } + return handle, runtime.UnlockOSThread, nil +} + +var hasStatxMountId = sync.OnceValue(func() bool { + var ( + stx unix.Statx_t + // We don't care which mount ID we get. The kernel will give us the + // unique one if it is supported. + wantStxMask uint32 = unix.STATX_MNT_ID_UNIQUE | unix.STATX_MNT_ID + ) + err := unix.Statx(-int(unix.EBADF), "/", 0, int(wantStxMask), &stx) + return err == nil && stx.Mask&wantStxMask != 0 +}) + +func getMountId(dir *os.File, path string) (uint64, error) { + // If we don't have statx(STATX_MNT_ID*) support, we can't do anything. + if !hasStatxMountId() { + return 0, nil + } + + var ( + stx unix.Statx_t + // We don't care which mount ID we get. The kernel will give us the + // unique one if it is supported. + wantStxMask uint32 = unix.STATX_MNT_ID_UNIQUE | unix.STATX_MNT_ID + ) + + err := unix.Statx(int(dir.Fd()), path, unix.AT_EMPTY_PATH|unix.AT_SYMLINK_NOFOLLOW, int(wantStxMask), &stx) + if stx.Mask&wantStxMask == 0 { + // It's not a kernel limitation, for some reason we couldn't get a + // mount ID. Assume it's some kind of attack. + err = fmt.Errorf("%w: could not get mount id", errUnsafeProcfs) + } + if err != nil { + return 0, &os.PathError{Op: "statx(STATX_MNT_ID_...)", Path: dir.Name() + "/" + path, Err: err} + } + return stx.Mnt_id, nil +} + +func checkSymlinkOvermount(procRoot *os.File, dir *os.File, path string) error { + // Get the mntId of our procfs handle. + expectedMountId, err := getMountId(procRoot, "") + if err != nil { + return err + } + // Get the mntId of the target magic-link. + gotMountId, err := getMountId(dir, path) + if err != nil { + return err + } + // As long as the directory mount is alive, even with wrapping mount IDs, + // we would expect to see a different mount ID here. (Of course, if we're + // using unsafeHostProcRoot() then an attaker could change this after we + // did this check.) + if expectedMountId != gotMountId { + return fmt.Errorf("%w: symlink %s/%s has an overmount obscuring the real link (mount ids do not match %d != %d)", errUnsafeProcfs, dir.Name(), path, expectedMountId, gotMountId) + } + return nil +} + +func doRawProcSelfFdReadlink(procRoot *os.File, fd int) (string, error) { + fdPath := fmt.Sprintf("fd/%d", fd) + procFdLink, closer, err := procThreadSelf(procRoot, fdPath) + if err != nil { + return "", fmt.Errorf("get safe /proc/thread-self/%s handle: %w", fdPath, err) + } + defer procFdLink.Close() + defer closer() + + // Try to detect if there is a mount on top of the magic-link. Since we use the handle directly + // provide to the closure. If the closure uses the handle directly, this + // should be safe in general (a mount on top of the path afterwards would + // not affect the handle itself) and will definitely be safe if we are + // using privateProcRoot() (at least since Linux 5.12[1], when anonymous + // mount namespaces were completely isolated from external mounts including + // mount propagation events). + // + // [1]: Linux commit ee2e3f50629f ("mount: fix mounting of detached mounts + // onto targets that reside on shared mounts"). + if err := checkSymlinkOvermount(procRoot, procFdLink, ""); err != nil { + return "", fmt.Errorf("check safety of /proc/thread-self/fd/%d magiclink: %w", fd, err) + } + + // readlinkat implies AT_EMPTY_PATH since Linux 2.6.39. See Linux commit + // 65cfc6722361 ("readlinkat(), fchownat() and fstatat() with empty + // relative pathnames"). + return readlinkatFile(procFdLink, "") +} + +func rawProcSelfFdReadlink(fd int) (string, error) { + procRoot, err := getProcRoot() + if err != nil { + return "", err + } + return doRawProcSelfFdReadlink(procRoot, fd) +} + +func procSelfFdReadlink(f *os.File) (string, error) { + return rawProcSelfFdReadlink(int(f.Fd())) +} + +var ( + errPossibleBreakout = errors.New("possible breakout detected") + errInvalidDirectory = errors.New("wandered into deleted directory") + errDeletedInode = errors.New("cannot verify path of deleted inode") +) + +func isDeadInode(file *os.File) error { + // If the nlink of a file drops to 0, there is an attacker deleting + // directories during our walk, which could result in weird /proc values. + // It's better to error out in this case. + stat, err := fstat(file) + if err != nil { + return fmt.Errorf("check for dead inode: %w", err) + } + if stat.Nlink == 0 { + err := errDeletedInode + if stat.Mode&unix.S_IFMT == unix.S_IFDIR { + err = errInvalidDirectory + } + return fmt.Errorf("%w %q", err, file.Name()) + } + return nil +} + +func checkProcSelfFdPath(path string, file *os.File) error { + if err := isDeadInode(file); err != nil { + return err + } + actualPath, err := procSelfFdReadlink(file) + if err != nil { + return fmt.Errorf("get path of handle: %w", err) + } + if actualPath != path { + return fmt.Errorf("%w: handle path %q doesn't match expected path %q", errPossibleBreakout, actualPath, path) + } + return nil +} + +// Test hooks used in the procfs tests to verify that the fallback logic works. +// See testing_mocks_linux_test.go and procfs_linux_test.go for more details. +var ( + hookForcePrivateProcRootOpenTree = hookDummyFile + hookForcePrivateProcRootOpenTreeAtRecursive = hookDummyFile + hookForceGetProcRootUnsafe = hookDummy + + hookForceProcSelfTask = hookDummy + hookForceProcSelf = hookDummy +) + +func hookDummy() bool { return false } +func hookDummyFile(_ *os.File) bool { return false } diff --git a/tests/vendor/github.com/cyphar/filepath-securejoin/vfs.go b/tests/vendor/github.com/cyphar/filepath-securejoin/vfs.go index a82a5eae1..36373f8c5 100644 --- a/tests/vendor/github.com/cyphar/filepath-securejoin/vfs.go +++ b/tests/vendor/github.com/cyphar/filepath-securejoin/vfs.go @@ -1,4 +1,4 @@ -// Copyright (C) 2017 SUSE LLC. All rights reserved. +// Copyright (C) 2017-2024 SUSE LLC. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -10,19 +10,19 @@ import "os" // are several projects (umoci and go-mtree) that are using this sort of // interface. -// VFS is the minimal interface necessary to use SecureJoinVFS. A nil VFS is -// equivalent to using the standard os.* family of functions. This is mainly +// VFS is the minimal interface necessary to use [SecureJoinVFS]. A nil VFS is +// equivalent to using the standard [os].* family of functions. This is mainly // used for the purposes of mock testing, but also can be used to otherwise use -// SecureJoin with VFS-like system. +// [SecureJoinVFS] with VFS-like system. type VFS interface { - // Lstat returns a FileInfo describing the named file. If the file is a - // symbolic link, the returned FileInfo describes the symbolic link. Lstat - // makes no attempt to follow the link. These semantics are identical to - // os.Lstat. + // Lstat returns an [os.FileInfo] describing the named file. If the + // file is a symbolic link, the returned [os.FileInfo] describes the + // symbolic link. Lstat makes no attempt to follow the link. + // The semantics are identical to [os.Lstat]. Lstat(name string) (os.FileInfo, error) - // Readlink returns the destination of the named symbolic link. These - // semantics are identical to os.Readlink. + // Readlink returns the destination of the named symbolic link. + // The semantics are identical to [os.Readlink]. Readlink(name string) (string, error) } @@ -30,12 +30,6 @@ type VFS interface { // module. type osVFS struct{} -// Lstat returns a FileInfo describing the named file. If the file is a -// symbolic link, the returned FileInfo describes the symbolic link. Lstat -// makes no attempt to follow the link. These semantics are identical to -// os.Lstat. func (o osVFS) Lstat(name string) (os.FileInfo, error) { return os.Lstat(name) } -// Readlink returns the destination of the named symbolic link. These -// semantics are identical to os.Readlink. func (o osVFS) Readlink(name string) (string, error) { return os.Readlink(name) } diff --git a/tests/vendor/github.com/distribution/reference/README.md b/tests/vendor/github.com/distribution/reference/README.md index e2531e49c..172a02e0b 100644 --- a/tests/vendor/github.com/distribution/reference/README.md +++ b/tests/vendor/github.com/distribution/reference/README.md @@ -10,7 +10,7 @@ Go library to handle references to container images. [![codecov](https://codecov.io/gh/distribution/reference/branch/main/graph/badge.svg)](https://codecov.io/gh/distribution/reference) [![FOSSA Status](https://app.fossa.com/api/projects/custom%2B162%2Fgithub.com%2Fdistribution%2Freference.svg?type=shield)](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fdistribution%2Freference?ref=badge_shield) -This repository contains a library for handling refrences to container images held in container registries. Please see [godoc](https://pkg.go.dev/github.com/distribution/reference) for details. +This repository contains a library for handling references to container images held in container registries. Please see [godoc](https://pkg.go.dev/github.com/distribution/reference) for details. ## Contribution diff --git a/tests/vendor/github.com/distribution/reference/normalize.go b/tests/vendor/github.com/distribution/reference/normalize.go index a30229d01..f4128314c 100644 --- a/tests/vendor/github.com/distribution/reference/normalize.go +++ b/tests/vendor/github.com/distribution/reference/normalize.go @@ -123,20 +123,51 @@ func ParseDockerRef(ref string) (Named, error) { // splitDockerDomain splits a repository name to domain and remote-name. // If no valid domain is found, the default domain is used. Repository name // needs to be already validated before. -func splitDockerDomain(name string) (domain, remainder string) { - i := strings.IndexRune(name, '/') - if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != localhost && strings.ToLower(name[:i]) == name[:i]) { - domain, remainder = defaultDomain, name - } else { - domain, remainder = name[:i], name[i+1:] - } - if domain == legacyDefaultDomain { - domain = defaultDomain - } - if domain == defaultDomain && !strings.ContainsRune(remainder, '/') { - remainder = officialRepoPrefix + remainder - } - return +func splitDockerDomain(name string) (domain, remoteName string) { + maybeDomain, maybeRemoteName, ok := strings.Cut(name, "/") + if !ok { + // Fast-path for single element ("familiar" names), such as "ubuntu" + // or "ubuntu:latest". Familiar names must be handled separately, to + // prevent them from being handled as "hostname:port". + // + // Canonicalize them as "docker.io/library/name[:tag]" + + // FIXME(thaJeztah): account for bare "localhost" or "example.com" names, which SHOULD be considered a domain. + return defaultDomain, officialRepoPrefix + name + } + + switch { + case maybeDomain == localhost: + // localhost is a reserved namespace and always considered a domain. + domain, remoteName = maybeDomain, maybeRemoteName + case maybeDomain == legacyDefaultDomain: + // canonicalize the Docker Hub and legacy "Docker Index" domains. + domain, remoteName = defaultDomain, maybeRemoteName + case strings.ContainsAny(maybeDomain, ".:"): + // Likely a domain or IP-address: + // + // - contains a "." (e.g., "example.com" or "127.0.0.1") + // - contains a ":" (e.g., "example:5000", "::1", or "[::1]:5000") + domain, remoteName = maybeDomain, maybeRemoteName + case strings.ToLower(maybeDomain) != maybeDomain: + // Uppercase namespaces are not allowed, so if the first element + // is not lowercase, we assume it to be a domain-name. + domain, remoteName = maybeDomain, maybeRemoteName + default: + // None of the above: it's not a domain, so use the default, and + // use the name input the remote-name. + domain, remoteName = defaultDomain, name + } + + if domain == defaultDomain && !strings.ContainsRune(remoteName, '/') { + // Canonicalize "familiar" names, but only on Docker Hub, not + // on other domains: + // + // "docker.io/ubuntu[:tag]" => "docker.io/library/ubuntu[:tag]" + remoteName = officialRepoPrefix + remoteName + } + + return domain, remoteName } // familiarizeName returns a shortened version of the name familiar diff --git a/tests/vendor/github.com/distribution/reference/reference.go b/tests/vendor/github.com/distribution/reference/reference.go index e98c44daa..900398bde 100644 --- a/tests/vendor/github.com/distribution/reference/reference.go +++ b/tests/vendor/github.com/distribution/reference/reference.go @@ -35,8 +35,13 @@ import ( ) const ( + // RepositoryNameTotalLengthMax is the maximum total number of characters in a repository name. + RepositoryNameTotalLengthMax = 255 + // NameTotalLengthMax is the maximum total number of characters in a repository name. - NameTotalLengthMax = 255 + // + // Deprecated: use [RepositoryNameTotalLengthMax] instead. + NameTotalLengthMax = RepositoryNameTotalLengthMax ) var ( @@ -55,8 +60,8 @@ var ( // ErrNameEmpty is returned for empty, invalid repository names. ErrNameEmpty = errors.New("repository name must have at least one component") - // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. - ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) + // ErrNameTooLong is returned when a repository name is longer than RepositoryNameTotalLengthMax. + ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", RepositoryNameTotalLengthMax) // ErrNameNotCanonical is returned when a name is not canonical. ErrNameNotCanonical = errors.New("repository name must be canonical") @@ -165,6 +170,9 @@ func Path(named Named) (name string) { return path } +// splitDomain splits a named reference into a hostname and path string. +// If no valid hostname is found, the hostname is empty and the full value +// is returned as name func splitDomain(name string) (string, string) { match := anchoredNameRegexp.FindStringSubmatch(name) if len(match) != 3 { @@ -173,19 +181,6 @@ func splitDomain(name string) (string, string) { return match[1], match[2] } -// SplitHostname splits a named reference into a -// hostname and name string. If no valid hostname is -// found, the hostname is empty and the full value -// is returned as name -// -// Deprecated: Use [Domain] or [Path]. -func SplitHostname(named Named) (string, string) { - if r, ok := named.(namedRepository); ok { - return r.Domain(), r.Path() - } - return splitDomain(named.Name()) -} - // Parse parses s and returns a syntactically valid Reference. // If an error was encountered it is returned, along with a nil Reference. func Parse(s string) (Reference, error) { @@ -200,10 +195,6 @@ func Parse(s string) (Reference, error) { return nil, ErrReferenceInvalidFormat } - if len(matches[1]) > NameTotalLengthMax { - return nil, ErrNameTooLong - } - var repo repository nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) @@ -215,6 +206,10 @@ func Parse(s string) (Reference, error) { repo.path = matches[1] } + if len(repo.path) > RepositoryNameTotalLengthMax { + return nil, ErrNameTooLong + } + ref := reference{ namedRepository: repo, tag: matches[2], @@ -253,14 +248,15 @@ func ParseNamed(s string) (Named, error) { // WithName returns a named object representing the given string. If the input // is invalid ErrReferenceInvalidFormat will be returned. func WithName(name string) (Named, error) { - if len(name) > NameTotalLengthMax { - return nil, ErrNameTooLong - } - match := anchoredNameRegexp.FindStringSubmatch(name) if match == nil || len(match) != 3 { return nil, ErrReferenceInvalidFormat } + + if len(match[2]) > RepositoryNameTotalLengthMax { + return nil, ErrNameTooLong + } + return repository{ domain: match[1], path: match[2], diff --git a/tests/vendor/github.com/opencontainers/image-spec/specs-go/version.go b/tests/vendor/github.com/opencontainers/image-spec/specs-go/version.go index 6d01f6e71..7069ae44d 100644 --- a/tests/vendor/github.com/opencontainers/image-spec/specs-go/version.go +++ b/tests/vendor/github.com/opencontainers/image-spec/specs-go/version.go @@ -25,7 +25,7 @@ const ( VersionPatch = 0 // VersionDev indicates development branch. Releases will be empty string. - VersionDev = "-rc.6" + VersionDev = "" ) // Version is the specification version that the package types support. diff --git a/tests/vendor/go.opentelemetry.io/otel/.golangci.yml b/tests/vendor/go.opentelemetry.io/otel/.golangci.yml index 6d9c8b649..d09555506 100644 --- a/tests/vendor/go.opentelemetry.io/otel/.golangci.yml +++ b/tests/vendor/go.opentelemetry.io/otel/.golangci.yml @@ -9,6 +9,8 @@ linters: disable-all: true # Specifically enable linters we want to use. enable: + - asasalint + - bodyclose - depguard - errcheck - errorlint @@ -23,6 +25,7 @@ linters: - revive - staticcheck - tenv + - testifylint - typecheck - unconvert - unused @@ -62,12 +65,12 @@ issues: - path: _test\.go linters: - gosec - # Igonoring gosec G404: Use of weak random number generator (math/rand instead of crypto/rand) + # Ignoring gosec G404: Use of weak random number generator (math/rand instead of crypto/rand) # as we commonly use it in tests and examples. - text: "G404:" linters: - gosec - # Igonoring gosec G402: TLS MinVersion too low + # Ignoring gosec G402: TLS MinVersion too low # as the https://pkg.go.dev/crypto/tls#Config handles MinVersion default well. - text: "G402: TLS MinVersion too low." linters: @@ -300,3 +303,9 @@ linters-settings: # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#waitgroup-by-value - name: waitgroup-by-value disabled: false + testifylint: + enable-all: true + disable: + - float-compare + - go-require + - require-error diff --git a/tests/vendor/go.opentelemetry.io/otel/CHANGELOG.md b/tests/vendor/go.opentelemetry.io/otel/CHANGELOG.md index c01e6998e..4b361d026 100644 --- a/tests/vendor/go.opentelemetry.io/otel/CHANGELOG.md +++ b/tests/vendor/go.opentelemetry.io/otel/CHANGELOG.md @@ -8,6 +8,112 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] + + + +## [1.31.0/0.53.0/0.7.0/0.0.10] 2024-10-11 + +### Added + +- Add `go.opentelemetry.io/otel/sdk/metric/exemplar` package which includes `Exemplar`, `Filter`, `TraceBasedFilter`, `AlwaysOnFilter`, `HistogramReservoir`, `FixedSizeReservoir`, `Reservoir`, `Value` and `ValueType` types. These will be used for configuring the exemplar reservoir for the metrics sdk. (#5747, #5862) +- Add `WithExportBufferSize` option to log batch processor.(#5877) + +### Changed + +- Enable exemplars by default in `go.opentelemetry.io/otel/sdk/metric`. Exemplars can be disabled by setting `OTEL_METRICS_EXEMPLAR_FILTER=always_off` (#5778) +- `Logger.Enabled` in `go.opentelemetry.io/otel/log` now accepts a newly introduced `EnabledParameters` type instead of `Record`. (#5791) +- `FilterProcessor.Enabled` in `go.opentelemetry.io/otel/sdk/log/internal/x` now accepts `EnabledParameters` instead of `Record`. (#5791) +- The `Record` type in `go.opentelemetry.io/otel/log` is no longer comparable. (#5847) +- Performance improvements for the trace SDK `SetAttributes` method in `Span`. (#5864) +- Reduce memory allocations for the `Event` and `Link` lists in `Span`. (#5858) +- Performance improvements for the trace SDK `AddEvent`, `AddLink`, `RecordError` and `End` methods in `Span`. (#5874) + +### Deprecated + +- Deprecate all examples under `go.opentelemetry.io/otel/example` as they are moved to [Contrib repository](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/examples). (#5854) + +### Fixed + +- The race condition for multiple `FixedSize` exemplar reservoirs identified in #5814 is resolved. (#5819) +- Fix log records duplication in case of heterogeneous resource attributes by correctly mapping each log record to it's resource and scope. (#5803) +- Fix timer channel drain to avoid hanging on Go 1.23. (#5868) +- Fix delegation for global meter providers, and panic when calling otel.SetMeterProvider. (#5827) +- Change the `reflect.TypeOf` to use a nil pointer to not allocate on the heap unless necessary. (#5827) + +## [1.30.0/0.52.0/0.6.0/0.0.9] 2024-09-09 + +### Added + +- Support `OTEL_EXPORTER_OTLP_LOGS_INSECURE` and `OTEL_EXPORTER_OTLP_INSECURE` environments in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`. (#5739) +- The `WithResource` option for `NewMeterProvider` now merges the provided resources with the ones from environment variables. (#5773) +- The `WithResource` option for `NewLoggerProvider` now merges the provided resources with the ones from environment variables. (#5773) +- Add UTF-8 support to `go.opentelemetry.io/otel/exporters/prometheus`. (#5755) + +### Fixed + +- Fix memory leak in the global `MeterProvider` when identical instruments are repeatedly created. (#5754) +- Fix panic on instruments creation when setting meter provider. (#5758) +- Fix an issue where `SetMeterProvider` in `go.opentelemetry.io/otel` might miss the delegation for instruments and registries. (#5780) + +### Removed + +- Drop support for [Go 1.21]. (#5736, #5740, #5800) + +## [1.29.0/0.51.0/0.5.0] 2024-08-23 + +This release is the last to support [Go 1.21]. +The next release will require at least [Go 1.22]. + +### Added + +- Add MacOS ARM64 platform to the compatibility testing suite. (#5577) +- Add `InstrumentationScope` field to `SpanStub` in `go.opentelemetry.io/otel/sdk/trace/tracetest`, as a replacement for the deprecated `InstrumentationLibrary`. (#5627) +- Make the initial release of `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc`. + This new module contains an OTLP exporter that transmits log telemetry using gRPC. + This module is unstable and breaking changes may be introduced. + See our [versioning policy](VERSIONING.md) for more information about these stability guarantees. (#5629) +- Add `Walk` function to `TraceState` in `go.opentelemetry.io/otel/trace` to iterate all the key-value pairs. (#5651) +- Bridge the trace state in `go.opentelemetry.io/otel/bridge/opencensus`. (#5651) +- Zero value of `SimpleProcessor` in `go.opentelemetry.io/otel/sdk/log` no longer panics. (#5665) +- The `FilterProcessor` interface type is added in `go.opentelemetry.io/otel/sdk/log/internal/x`. + This is an optional and experimental interface that log `Processor`s can implement to instruct the `Logger` if a `Record` will be processed or not. + It replaces the existing `Enabled` method that is removed from the `Processor` interface itself. + It does not fall within the scope of the OpenTelemetry Go versioning and stability [policy](./VERSIONING.md) and it may be changed in backwards incompatible ways or removed in feature releases. (#5692) +- Support [Go 1.23]. (#5720) + +### Changed + +- `NewMemberRaw`, `NewKeyProperty` and `NewKeyValuePropertyRaw` in `go.opentelemetry.io/otel/baggage` allow UTF-8 string in key. (#5132) +- `Processor.OnEmit` in `go.opentelemetry.io/otel/sdk/log` now accepts a pointer to `Record` instead of a value so that the record modifications done in a processor are propagated to subsequent registered processors. (#5636) +- `SimpleProcessor.Enabled` in `go.opentelemetry.io/otel/sdk/log` now returns `false` if the exporter is `nil`. (#5665) +- Update the concurrency requirements of `Exporter` in `go.opentelemetry.io/otel/sdk/log`. (#5666) +- `SimpleProcessor` in `go.opentelemetry.io/otel/sdk/log` synchronizes `OnEmit` calls. (#5666) +- The `Processor` interface in `go.opentelemetry.io/otel/sdk/log` no longer includes the `Enabled` method. + See the `FilterProcessor` interface type added in `go.opentelemetry.io/otel/sdk/log/internal/x` to continue providing this functionality. (#5692) +- The `SimpleProcessor` type in `go.opentelemetry.io/otel/sdk/log` is no longer comparable. (#5693) +- The `BatchProcessor` type in `go.opentelemetry.io/otel/sdk/log` is no longer comparable. (#5693) + +### Fixed + +- Correct comments for the priority of the `WithEndpoint` and `WithEndpointURL` options and their corresponding environment variables in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#5584) +- Pass the underlying error rather than a generic retry-able failure in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`, `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` and `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`. (#5541) +- Correct the `Tracer`, `Meter`, and `Logger` names used in `go.opentelemetry.io/otel/example/dice`. (#5612) +- Correct the `Tracer` names used in `go.opentelemetry.io/otel/example/namedtracer`. (#5612) +- Correct the `Tracer` name used in `go.opentelemetry.io/otel/example/opencensus`. (#5612) +- Correct the `Tracer` and `Meter` names used in `go.opentelemetry.io/otel/example/otel-collector`. (#5612) +- Correct the `Tracer` names used in `go.opentelemetry.io/otel/example/passthrough`. (#5612) +- Correct the `Meter` name used in `go.opentelemetry.io/otel/example/prometheus`. (#5612) +- Correct the `Tracer` names used in `go.opentelemetry.io/otel/example/zipkin`. (#5612) +- Correct comments for the priority of the `WithEndpoint` and `WithEndpointURL` options and their corresponding environment variables in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#5641) +- Correct comments for the priority of the `WithEndpoint` and `WithEndpointURL` options and their corresponding environment variables in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#5650) +- Stop percent encoding header environment variables in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`, `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`, `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` (#5705) +- Remove invalid environment variable header keys in `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc`, `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp`, `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` (#5705) + +### Removed + +- The `Enabled` method of the `SimpleProcessor` in `go.opentelemetry.io/otel/sdk/log` is removed. (#5692) +- The `Enabled` method of the `BatchProcessor` in `go.opentelemetry.io/otel/sdk/log` is removed. (#5692) + ## [1.28.0/0.50.0/0.4.0] 2024-07-02 ### Added @@ -49,6 +155,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Fix stale timestamps reported by the last-value aggregation. (#5517) - Indicate the `Exporter` in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp` must be created by the `New` method. (#5521) - Improved performance in all `{Bool,Int64,Float64,String}SliceValue` functions of `go.opentelemetry.io/attributes` by reducing the number of allocations. (#5549) +- Replace invalid percent-encoded octet sequences with replacement char in `go.opentelemetry.io/otel/baggage`. (#5528) ## [1.27.0/0.49.0/0.3.0] 2024-05-21 @@ -175,7 +282,7 @@ The next release will require at least [Go 1.21]. This module includes OpenTelemetry Go's implementation of the Logs Bridge API. This module is in an alpha state, it is subject to breaking changes. See our [versioning policy](./VERSIONING.md) for more info. (#4961) -- ARM64 platform to the compatibility testing suite. (#4994) +- Add ARM64 platform to the compatibility testing suite. (#4994) ### Fixed @@ -1836,7 +1943,7 @@ with major version 0. - Setting error status while recording error with Span from oteltest package. (#1729) - The concept of a remote and local Span stored in a context is unified to just the current Span. Because of this `"go.opentelemetry.io/otel/trace".RemoteSpanContextFromContext` is removed as it is no longer needed. - Instead, `"go.opentelemetry.io/otel/trace".SpanContextFromContex` can be used to return the current Span. + Instead, `"go.opentelemetry.io/otel/trace".SpanContextFromContext` can be used to return the current Span. If needed, that Span's `SpanContext.IsRemote()` can then be used to determine if it is remote or not. (#1731) - The `HasRemoteParent` field of the `"go.opentelemetry.io/otel/sdk/trace".SamplingParameters` is removed. This field is redundant to the information returned from the `Remote` method of the `SpanContext` held in the `ParentContext` field. (#1749) @@ -2410,7 +2517,7 @@ This release migrates the default OpenTelemetry SDK into its own Go module, deco - Prometheus exporter will not apply stale updates or forget inactive metrics. (#903) - Add test for api.standard `HTTPClientAttributesFromHTTPRequest`. (#905) - Bump github.com/golangci/golangci-lint from 1.27.0 to 1.28.1 in /tools. (#901, #913) -- Update otel-colector example to use the v0.5.0 collector. (#915) +- Update otel-collector example to use the v0.5.0 collector. (#915) - The `grpctrace` instrumentation uses a span name conforming to the OpenTelemetry semantic conventions (does not contain a leading slash (`/`)). (#922) - The `grpctrace` instrumentation includes an `rpc.method` attribute now set to the gRPC method name. (#900, #922) - The `grpctrace` instrumentation `rpc.service` attribute now contains the package name if one exists. @@ -3003,7 +3110,10 @@ It contains api and sdk for trace and meter. - CircleCI build CI manifest files. - CODEOWNERS file to track owners of this project. -[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.28.0...HEAD +[Unreleased]: https://github.com/open-telemetry/opentelemetry-go/compare/v1.31.0...HEAD +[1.31.0/0.53.0/0.7.0/0.0.10]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.31.0 +[1.30.0/0.52.0/0.6.0/0.0.9]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.30.0 +[1.29.0/0.51.0/0.5.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.29.0 [1.28.0/0.50.0/0.4.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.28.0 [1.27.0/0.49.0/0.3.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.27.0 [1.26.0/0.48.0/0.2.0-alpha]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.26.0 @@ -3086,6 +3196,9 @@ It contains api and sdk for trace and meter. [0.1.1]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.1.1 [0.1.0]: https://github.com/open-telemetry/opentelemetry-go/releases/tag/v0.1.0 + + +[Go 1.23]: https://go.dev/doc/go1.23 [Go 1.22]: https://go.dev/doc/go1.22 [Go 1.21]: https://go.dev/doc/go1.21 [Go 1.20]: https://go.dev/doc/go1.20 diff --git a/tests/vendor/go.opentelemetry.io/otel/CODEOWNERS b/tests/vendor/go.opentelemetry.io/otel/CODEOWNERS index 202554933..945a07d2b 100644 --- a/tests/vendor/go.opentelemetry.io/otel/CODEOWNERS +++ b/tests/vendor/go.opentelemetry.io/otel/CODEOWNERS @@ -5,13 +5,13 @@ ##################################################### # # Learn about membership in OpenTelemetry community: -# https://github.com/open-telemetry/community/blob/main/community-membership.md +# https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md # # # Learn about CODEOWNERS file format: # https://help.github.com/en/articles/about-code-owners # -* @MrAlias @XSAM @dashpole @MadVikingGod @pellared @hanyuancheung @dmathieu +* @MrAlias @XSAM @dashpole @pellared @dmathieu -CODEOWNERS @MrAlias @MadVikingGod @pellared @dashpole @XSAM @dmathieu +CODEOWNERS @MrAlias @pellared @dashpole @XSAM @dmathieu diff --git a/tests/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md b/tests/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md index b86572f58..bb3396557 100644 --- a/tests/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md +++ b/tests/vendor/go.opentelemetry.io/otel/CONTRIBUTING.md @@ -578,7 +578,10 @@ See also: The tests should never leak goroutines. Use the term `ConcurrentSafe` in the test name when it aims to verify the -absence of race conditions. +absence of race conditions. The top-level tests with this term will be run +many times in the `test-concurrent-safe` CI job to increase the chance of +catching concurrency issues. This does not apply to subtests when this term +is not in their root name. ### Internal packages @@ -628,11 +631,8 @@ should be canceled. ### Approvers -- [Chester Cheung](https://github.com/hanyuancheung), Tencent - ### Maintainers -- [Aaron Clawson](https://github.com/MadVikingGod), LightStep - [Damien Mathieu](https://github.com/dmathieu), Elastic - [David Ashpole](https://github.com/dashpole), Google - [Robert Pająk](https://github.com/pellared), Splunk @@ -641,16 +641,18 @@ should be canceled. ### Emeritus -- [Liz Fong-Jones](https://github.com/lizthegrey), Honeycomb -- [Gustavo Silva Paiva](https://github.com/paivagustavo), LightStep -- [Josh MacDonald](https://github.com/jmacd), LightStep +- [Aaron Clawson](https://github.com/MadVikingGod), LightStep - [Anthony Mirabella](https://github.com/Aneurysm9), AWS +- [Chester Cheung](https://github.com/hanyuancheung), Tencent - [Evan Torrie](https://github.com/evantorrie), Yahoo +- [Gustavo Silva Paiva](https://github.com/paivagustavo), LightStep +- [Josh MacDonald](https://github.com/jmacd), LightStep +- [Liz Fong-Jones](https://github.com/lizthegrey), Honeycomb ### Become an Approver or a Maintainer See the [community membership document in OpenTelemetry community -repo](https://github.com/open-telemetry/community/blob/main/community-membership.md). +repo](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md). [Approver]: #approvers [Maintainer]: #maintainers diff --git a/tests/vendor/go.opentelemetry.io/otel/Makefile b/tests/vendor/go.opentelemetry.io/otel/Makefile index f33619f76..a1228a212 100644 --- a/tests/vendor/go.opentelemetry.io/otel/Makefile +++ b/tests/vendor/go.opentelemetry.io/otel/Makefile @@ -54,9 +54,6 @@ $(TOOLS)/stringer: PACKAGE=golang.org/x/tools/cmd/stringer PORTO = $(TOOLS)/porto $(TOOLS)/porto: PACKAGE=github.com/jcchavezs/porto/cmd/porto -GOJQ = $(TOOLS)/gojq -$(TOOLS)/gojq: PACKAGE=github.com/itchyny/gojq/cmd/gojq - GOTMPL = $(TOOLS)/gotmpl $(GOTMPL): PACKAGE=go.opentelemetry.io/build-tools/gotmpl @@ -67,7 +64,7 @@ GOVULNCHECK = $(TOOLS)/govulncheck $(TOOLS)/govulncheck: PACKAGE=golang.org/x/vuln/cmd/govulncheck .PHONY: tools -tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(GOJQ) $(SEMCONVGEN) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE) +tools: $(CROSSLINK) $(GOLANGCI_LINT) $(MISSPELL) $(GOCOVMERGE) $(STRINGER) $(PORTO) $(SEMCONVGEN) $(MULTIMOD) $(SEMCONVKIT) $(GOTMPL) $(GORELEASE) # Virtualized python tools via docker @@ -145,12 +142,14 @@ build-tests/%: # Tests -TEST_TARGETS := test-default test-bench test-short test-verbose test-race +TEST_TARGETS := test-default test-bench test-short test-verbose test-race test-concurrent-safe .PHONY: $(TEST_TARGETS) test test-default test-race: ARGS=-race test-bench: ARGS=-run=xxxxxMatchNothingxxxxx -test.benchtime=1ms -bench=. test-short: ARGS=-short test-verbose: ARGS=-v -race +test-concurrent-safe: ARGS=-run=ConcurrentSafe -count=100 -race +test-concurrent-safe: TIMEOUT=120 $(TEST_TARGETS): test test: $(OTEL_GO_MOD_DIRS:%=test/%) test/%: DIR=$* @@ -178,17 +177,14 @@ test-coverage: $(GOCOVMERGE) done; \ $(GOCOVMERGE) $$(find . -name coverage.out) > coverage.txt -# Adding a directory will include all benchmarks in that directory if a filter is not specified. -BENCHMARK_TARGETS := sdk/trace .PHONY: benchmark -benchmark: $(BENCHMARK_TARGETS:%=benchmark/%) -BENCHMARK_FILTER = . -# You can override the filter for a particular directory by adding a rule here. -benchmark/sdk/trace: BENCHMARK_FILTER = SpanWithAttributes_8/AlwaysSample +benchmark: $(OTEL_GO_MOD_DIRS:%=benchmark/%) benchmark/%: - @echo "$(GO) test -timeout $(TIMEOUT)s -run=xxxxxMatchNothingxxxxx -bench=$(BENCHMARK_FILTER) $*..." \ + @echo "$(GO) test -run=xxxxxMatchNothingxxxxx -bench=. $*..." \ && cd $* \ - $(foreach filter, $(BENCHMARK_FILTER), && $(GO) test -timeout $(TIMEOUT)s -run=xxxxxMatchNothingxxxxx -bench=$(filter)) + && $(GO) list ./... \ + | grep -v third_party \ + | xargs $(GO) test -run=xxxxxMatchNothingxxxxx -bench=. .PHONY: golangci-lint golangci-lint-fix golangci-lint-fix: ARGS=--fix diff --git a/tests/vendor/go.opentelemetry.io/otel/README.md b/tests/vendor/go.opentelemetry.io/otel/README.md index 5a8909317..efec27890 100644 --- a/tests/vendor/go.opentelemetry.io/otel/README.md +++ b/tests/vendor/go.opentelemetry.io/otel/README.md @@ -47,20 +47,22 @@ stop ensuring compatibility with these versions in the following manner: Currently, this project supports the following environments. -| OS | Go Version | Architecture | -|---------|------------|--------------| -| Ubuntu | 1.22 | amd64 | -| Ubuntu | 1.21 | amd64 | -| Ubuntu | 1.22 | 386 | -| Ubuntu | 1.21 | 386 | -| Linux | 1.22 | arm64 | -| Linux | 1.21 | arm64 | -| MacOS | 1.22 | amd64 | -| MacOS | 1.21 | amd64 | -| Windows | 1.22 | amd64 | -| Windows | 1.21 | amd64 | -| Windows | 1.22 | 386 | -| Windows | 1.21 | 386 | +| OS | Go Version | Architecture | +|----------|------------|--------------| +| Ubuntu | 1.23 | amd64 | +| Ubuntu | 1.22 | amd64 | +| Ubuntu | 1.23 | 386 | +| Ubuntu | 1.22 | 386 | +| Linux | 1.23 | arm64 | +| Linux | 1.22 | arm64 | +| macOS 13 | 1.23 | amd64 | +| macOS 13 | 1.22 | amd64 | +| macOS | 1.23 | arm64 | +| macOS | 1.22 | arm64 | +| Windows | 1.23 | amd64 | +| Windows | 1.22 | amd64 | +| Windows | 1.23 | 386 | +| Windows | 1.22 | 386 | While this project should work for other systems, no compatibility guarantees are made for those systems currently. @@ -87,8 +89,8 @@ If you need to extend the telemetry an instrumentation library provides or want to build your own instrumentation for your application directly you will need to use the [Go otel](https://pkg.go.dev/go.opentelemetry.io/otel) -package. The included [examples](./example/) are a good way to see some -practical uses of this process. +package. The [examples](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/examples) +are a good way to see some practical uses of this process. ### Export diff --git a/tests/vendor/go.opentelemetry.io/otel/RELEASING.md b/tests/vendor/go.opentelemetry.io/otel/RELEASING.md index 940f57f3d..ffa9b6125 100644 --- a/tests/vendor/go.opentelemetry.io/otel/RELEASING.md +++ b/tests/vendor/go.opentelemetry.io/otel/RELEASING.md @@ -69,6 +69,7 @@ Update go.mod for submodules to depend on the new release which will happen in t ``` - Move all the `Unreleased` changes into a new section following the title scheme (`[] - `). + - Make sure the new section is under the comment for released section, like ``, so it is protected from being overwritten in the future. - Update all the appropriate links at the bottom. 4. Push the changes to upstream and create a Pull Request on GitHub. @@ -110,17 +111,6 @@ It is critical you make sure the version you push upstream is correct. Finally create a Release for the new `` on GitHub. The release body should include all the release notes from the Changelog for this release. -## Verify Examples - -After releasing verify that examples build outside of the repository. - -``` -./verify_examples.sh -``` - -The script copies examples into a different directory removes any `replace` declarations in `go.mod` and builds them. -This ensures they build with the published release, not the local copy. - ## Post-Release ### Contrib Repository diff --git a/tests/vendor/go.opentelemetry.io/otel/attribute/set.go b/tests/vendor/go.opentelemetry.io/otel/attribute/set.go index bff9c7fdb..6cbefcead 100644 --- a/tests/vendor/go.opentelemetry.io/otel/attribute/set.go +++ b/tests/vendor/go.opentelemetry.io/otel/attribute/set.go @@ -347,45 +347,25 @@ func computeDistinct(kvs []KeyValue) Distinct { func computeDistinctFixed(kvs []KeyValue) interface{} { switch len(kvs) { case 1: - ptr := new([1]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [1]KeyValue(kvs) case 2: - ptr := new([2]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [2]KeyValue(kvs) case 3: - ptr := new([3]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [3]KeyValue(kvs) case 4: - ptr := new([4]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [4]KeyValue(kvs) case 5: - ptr := new([5]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [5]KeyValue(kvs) case 6: - ptr := new([6]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [6]KeyValue(kvs) case 7: - ptr := new([7]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [7]KeyValue(kvs) case 8: - ptr := new([8]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [8]KeyValue(kvs) case 9: - ptr := new([9]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [9]KeyValue(kvs) case 10: - ptr := new([10]KeyValue) - copy((*ptr)[:], kvs) - return *ptr + return [10]KeyValue(kvs) default: return nil } diff --git a/tests/vendor/go.opentelemetry.io/otel/baggage/baggage.go b/tests/vendor/go.opentelemetry.io/otel/baggage/baggage.go index c40c896cc..36f536703 100644 --- a/tests/vendor/go.opentelemetry.io/otel/baggage/baggage.go +++ b/tests/vendor/go.opentelemetry.io/otel/baggage/baggage.go @@ -44,9 +44,15 @@ type Property struct { // NewKeyProperty returns a new Property for key. // +// The passed key must be valid, non-empty UTF-8 string. // If key is invalid, an error will be returned. +// However, the specific Propagators that are used to transmit baggage entries across +// component boundaries may impose their own restrictions on Property key. +// For example, the W3C Baggage specification restricts the Property keys to strings that +// satisfy the token definition from RFC7230, Section 3.2.6. +// For maximum compatibility, alphanumeric value are strongly recommended to be used as Property key. func NewKeyProperty(key string) (Property, error) { - if !validateKey(key) { + if !validateBaggageName(key) { return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key) } @@ -62,6 +68,10 @@ func NewKeyProperty(key string) (Property, error) { // Notice: Consider using [NewKeyValuePropertyRaw] instead // that does not require percent-encoding of the value. func NewKeyValueProperty(key, value string) (Property, error) { + if !validateKey(key) { + return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key) + } + if !validateValue(value) { return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, value) } @@ -74,11 +84,20 @@ func NewKeyValueProperty(key, value string) (Property, error) { // NewKeyValuePropertyRaw returns a new Property for key with value. // -// The passed key must be compliant with W3C Baggage specification. +// The passed key must be valid, non-empty UTF-8 string. +// The passed value must be valid UTF-8 string. +// However, the specific Propagators that are used to transmit baggage entries across +// component boundaries may impose their own restrictions on Property key. +// For example, the W3C Baggage specification restricts the Property keys to strings that +// satisfy the token definition from RFC7230, Section 3.2.6. +// For maximum compatibility, alphanumeric value are strongly recommended to be used as Property key. func NewKeyValuePropertyRaw(key, value string) (Property, error) { - if !validateKey(key) { + if !validateBaggageName(key) { return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, key) } + if !validateBaggageValue(value) { + return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, value) + } p := Property{ key: key, @@ -115,12 +134,15 @@ func (p Property) validate() error { return fmt.Errorf("invalid property: %w", err) } - if !validateKey(p.key) { + if !validateBaggageName(p.key) { return errFunc(fmt.Errorf("%w: %q", errInvalidKey, p.key)) } if !p.hasValue && p.value != "" { return errFunc(errors.New("inconsistent value")) } + if p.hasValue && !validateBaggageValue(p.value) { + return errFunc(fmt.Errorf("%w: %q", errInvalidValue, p.value)) + } return nil } @@ -138,7 +160,15 @@ func (p Property) Value() (string, bool) { // String encodes Property into a header string compliant with the W3C Baggage // specification. +// It would return empty string if the key is invalid with the W3C Baggage +// specification. This could happen for a UTF-8 key, as it may contain +// invalid characters. func (p Property) String() string { + // W3C Baggage specification does not allow percent-encoded keys. + if !validateKey(p.key) { + return "" + } + if p.hasValue { return fmt.Sprintf("%s%s%v", p.key, keyValueDelimiter, valueEscape(p.value)) } @@ -203,9 +233,14 @@ func (p properties) validate() error { // String encodes properties into a header string compliant with the W3C Baggage // specification. func (p properties) String() string { - props := make([]string, len(p)) - for i, prop := range p { - props[i] = prop.String() + props := make([]string, 0, len(p)) + for _, prop := range p { + s := prop.String() + + // Ignored empty properties. + if s != "" { + props = append(props, s) + } } return strings.Join(props, propertyDelimiter) } @@ -230,6 +265,10 @@ type Member struct { // Notice: Consider using [NewMemberRaw] instead // that does not require percent-encoding of the value. func NewMember(key, value string, props ...Property) (Member, error) { + if !validateKey(key) { + return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidKey, key) + } + if !validateValue(value) { return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value) } @@ -242,7 +281,13 @@ func NewMember(key, value string, props ...Property) (Member, error) { // NewMemberRaw returns a new Member from the passed arguments. // -// The passed key must be compliant with W3C Baggage specification. +// The passed key must be valid, non-empty UTF-8 string. +// The passed value must be valid UTF-8 string. +// However, the specific Propagators that are used to transmit baggage entries across +// component boundaries may impose their own restrictions on baggage key. +// For example, the W3C Baggage specification restricts the baggage keys to strings that +// satisfy the token definition from RFC7230, Section 3.2.6. +// For maximum compatibility, alphanumeric value are strongly recommended to be used as baggage key. func NewMemberRaw(key, value string, props ...Property) (Member, error) { m := Member{ key: key, @@ -294,19 +339,45 @@ func parseMember(member string) (Member, error) { return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidKey, key) } - val := strings.TrimSpace(v) - if !validateValue(val) { + rawVal := strings.TrimSpace(v) + if !validateValue(rawVal) { return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, v) } // Decode a percent-encoded value. - value, err := url.PathUnescape(val) + unescapeVal, err := url.PathUnescape(rawVal) if err != nil { return newInvalidMember(), fmt.Errorf("%w: %w", errInvalidValue, err) } + + value := replaceInvalidUTF8Sequences(len(rawVal), unescapeVal) return Member{key: key, value: value, properties: props, hasData: true}, nil } +// replaceInvalidUTF8Sequences replaces invalid UTF-8 sequences with '�'. +func replaceInvalidUTF8Sequences(cap int, unescapeVal string) string { + if utf8.ValidString(unescapeVal) { + return unescapeVal + } + // W3C baggage spec: + // https://github.com/w3c/baggage/blob/8c215efbeebd3fa4b1aceb937a747e56444f22f3/baggage/HTTP_HEADER_FORMAT.md?plain=1#L69 + + var b strings.Builder + b.Grow(cap) + for i := 0; i < len(unescapeVal); { + r, size := utf8.DecodeRuneInString(unescapeVal[i:]) + if r == utf8.RuneError && size == 1 { + // Invalid UTF-8 sequence found, replace it with '�' + _, _ = b.WriteString("�") + } else { + _, _ = b.WriteRune(r) + } + i += size + } + + return b.String() +} + // validate ensures m conforms to the W3C Baggage specification. // A key must be an ASCII string, returning an error otherwise. func (m Member) validate() error { @@ -314,9 +385,12 @@ func (m Member) validate() error { return fmt.Errorf("%w: %q", errInvalidMember, m) } - if !validateKey(m.key) { + if !validateBaggageName(m.key) { return fmt.Errorf("%w: %q", errInvalidKey, m.key) } + if !validateBaggageValue(m.value) { + return fmt.Errorf("%w: %q", errInvalidValue, m.value) + } return m.properties.validate() } @@ -331,10 +405,15 @@ func (m Member) Properties() []Property { return m.properties.Copy() } // String encodes Member into a header string compliant with the W3C Baggage // specification. +// It would return empty string if the key is invalid with the W3C Baggage +// specification. This could happen for a UTF-8 key, as it may contain +// invalid characters. func (m Member) String() string { - // A key is just an ASCII string. A value is restricted to be - // US-ASCII characters excluding CTLs, whitespace, - // DQUOTE, comma, semicolon, and backslash. + // W3C Baggage specification does not allow percent-encoded keys. + if !validateKey(m.key) { + return "" + } + s := m.key + keyValueDelimiter + valueEscape(m.value) if len(m.properties) > 0 { s += propertyDelimiter + m.properties.String() @@ -448,7 +527,7 @@ func (b Baggage) Member(key string) Member { } // Members returns all the baggage list-members. -// The order of the returned list-members does not have significance. +// The order of the returned list-members is not significant. // // The returned members are not validated, as we assume the validation happened // when they were added to the Baggage. @@ -469,8 +548,8 @@ func (b Baggage) Members() []Member { return members } -// SetMember returns a copy the Baggage with the member included. If the -// baggage contains a Member with the same key the existing Member is +// SetMember returns a copy of the Baggage with the member included. If the +// baggage contains a Member with the same key, the existing Member is // replaced. // // If member is invalid according to the W3C Baggage specification, an error @@ -528,14 +607,22 @@ func (b Baggage) Len() int { // String encodes Baggage into a header string compliant with the W3C Baggage // specification. +// It would ignore members where the member key is invalid with the W3C Baggage +// specification. This could happen for a UTF-8 key, as it may contain +// invalid characters. func (b Baggage) String() string { members := make([]string, 0, len(b.list)) for k, v := range b.list { - members = append(members, Member{ + s := Member{ key: k, value: v.Value, properties: fromInternalProperties(v.Properties), - }.String()) + }.String() + + // Ignored empty members. + if s != "" { + members = append(members, s) + } } return strings.Join(members, listDelimiter) } @@ -607,10 +694,12 @@ func parsePropertyInternal(s string) (p Property, ok bool) { } // Decode a percent-encoded value. - value, err := url.PathUnescape(s[valueStart:valueEnd]) + rawVal := s[valueStart:valueEnd] + unescapeVal, err := url.PathUnescape(rawVal) if err != nil { return } + value := replaceInvalidUTF8Sequences(len(rawVal), unescapeVal) ok = true p.key = s[keyStart:keyEnd] @@ -720,6 +809,24 @@ var safeKeyCharset = [utf8.RuneSelf]bool{ '~': true, } +// validateBaggageName checks if the string is a valid OpenTelemetry Baggage name. +// Baggage name is a valid, non-empty UTF-8 string. +func validateBaggageName(s string) bool { + if len(s) == 0 { + return false + } + + return utf8.ValidString(s) +} + +// validateBaggageValue checks if the string is a valid OpenTelemetry Baggage value. +// Baggage value is a valid UTF-8 strings. +// Empty string is also a valid UTF-8 string. +func validateBaggageValue(s string) bool { + return utf8.ValidString(s) +} + +// validateKey checks if the string is a valid W3C Baggage key. func validateKey(s string) bool { if len(s) == 0 { return false @@ -738,6 +845,7 @@ func validateKeyChar(c int32) bool { return c >= 0 && c < int32(utf8.RuneSelf) && safeKeyCharset[c] } +// validateValue checks if the string is a valid W3C Baggage value. func validateValue(s string) bool { for _, c := range s { if !validateValueChar(c) { diff --git a/tests/vendor/go.opentelemetry.io/otel/codes/codes.go b/tests/vendor/go.opentelemetry.io/otel/codes/codes.go index df29d96a6..2acbac354 100644 --- a/tests/vendor/go.opentelemetry.io/otel/codes/codes.go +++ b/tests/vendor/go.opentelemetry.io/otel/codes/codes.go @@ -83,7 +83,7 @@ func (c *Code) UnmarshalJSON(b []byte) error { return fmt.Errorf("invalid code: %q", ci) } - *c = Code(ci) + *c = Code(ci) // nolint: gosec // Bit size of 32 check above. return nil } return fmt.Errorf("invalid code: %q", string(b)) diff --git a/tests/vendor/go.opentelemetry.io/otel/doc.go b/tests/vendor/go.opentelemetry.io/otel/doc.go index 441c59501..921f85961 100644 --- a/tests/vendor/go.opentelemetry.io/otel/doc.go +++ b/tests/vendor/go.opentelemetry.io/otel/doc.go @@ -17,6 +17,8 @@ To read more about tracing, see go.opentelemetry.io/otel/trace. To read more about metrics, see go.opentelemetry.io/otel/metric. +To read more about logs, see go.opentelemetry.io/otel/log. + To read more about propagation, see go.opentelemetry.io/otel/propagation and go.opentelemetry.io/otel/baggage. */ diff --git a/tests/vendor/go.opentelemetry.io/otel/internal/global/meter.go b/tests/vendor/go.opentelemetry.io/otel/internal/global/meter.go index cfd1df9bf..e3db438a0 100644 --- a/tests/vendor/go.opentelemetry.io/otel/internal/global/meter.go +++ b/tests/vendor/go.opentelemetry.io/otel/internal/global/meter.go @@ -5,8 +5,8 @@ package global // import "go.opentelemetry.io/otel/internal/global" import ( "container/list" + "reflect" "sync" - "sync/atomic" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/embedded" @@ -76,7 +76,7 @@ func (p *meterProvider) Meter(name string, opts ...metric.MeterOption) metric.Me return val } - t := &meter{name: name, opts: opts} + t := &meter{name: name, opts: opts, instruments: make(map[instID]delegatedInstrument)} p.meters[key] = t return t } @@ -92,17 +92,29 @@ type meter struct { opts []metric.MeterOption mtx sync.Mutex - instruments []delegatedInstrument + instruments map[instID]delegatedInstrument registry list.List - delegate atomic.Value // metric.Meter + delegate metric.Meter } type delegatedInstrument interface { setDelegate(metric.Meter) } +// instID are the identifying properties of a instrument. +type instID struct { + // name is the name of the stream. + name string + // description is the description of the stream. + description string + // kind defines the functional group of the instrument. + kind reflect.Type + // unit is the unit of the stream. + unit string +} + // setDelegate configures m to delegate all Meter functionality to Meters // created by provider. // @@ -110,12 +122,12 @@ type delegatedInstrument interface { // // It is guaranteed by the caller that this happens only once. func (m *meter) setDelegate(provider metric.MeterProvider) { - meter := provider.Meter(m.name, m.opts...) - m.delegate.Store(meter) - m.mtx.Lock() defer m.mtx.Unlock() + meter := provider.Meter(m.name, m.opts...) + m.delegate = meter + for _, inst := range m.instruments { inst.setDelegate(meter) } @@ -133,169 +145,337 @@ func (m *meter) setDelegate(provider metric.MeterProvider) { } func (m *meter) Int64Counter(name string, options ...metric.Int64CounterOption) (metric.Int64Counter, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Int64Counter(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Int64Counter(name, options...) + } + + cfg := metric.NewInt64CounterConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*siCounter)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Int64Counter), nil + } i := &siCounter{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Int64UpDownCounter(name string, options ...metric.Int64UpDownCounterOption) (metric.Int64UpDownCounter, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Int64UpDownCounter(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Int64UpDownCounter(name, options...) + } + + cfg := metric.NewInt64UpDownCounterConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*siUpDownCounter)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Int64UpDownCounter), nil + } i := &siUpDownCounter{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Int64Histogram(name string, options ...metric.Int64HistogramOption) (metric.Int64Histogram, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Int64Histogram(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Int64Histogram(name, options...) + } + + cfg := metric.NewInt64HistogramConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*siHistogram)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Int64Histogram), nil + } i := &siHistogram{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Int64Gauge(name string, options ...metric.Int64GaugeOption) (metric.Int64Gauge, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Int64Gauge(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Int64Gauge(name, options...) + } + + cfg := metric.NewInt64GaugeConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*siGauge)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Int64Gauge), nil + } i := &siGauge{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Int64ObservableCounter(name string, options ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Int64ObservableCounter(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Int64ObservableCounter(name, options...) + } + + cfg := metric.NewInt64ObservableCounterConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*aiCounter)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Int64ObservableCounter), nil + } i := &aiCounter{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Int64ObservableUpDownCounter(name string, options ...metric.Int64ObservableUpDownCounterOption) (metric.Int64ObservableUpDownCounter, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Int64ObservableUpDownCounter(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Int64ObservableUpDownCounter(name, options...) + } + + cfg := metric.NewInt64ObservableUpDownCounterConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*aiUpDownCounter)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Int64ObservableUpDownCounter), nil + } i := &aiUpDownCounter{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Int64ObservableGauge(name string, options ...metric.Int64ObservableGaugeOption) (metric.Int64ObservableGauge, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Int64ObservableGauge(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Int64ObservableGauge(name, options...) + } + + cfg := metric.NewInt64ObservableGaugeConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*aiGauge)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Int64ObservableGauge), nil + } i := &aiGauge{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Float64Counter(name string, options ...metric.Float64CounterOption) (metric.Float64Counter, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Float64Counter(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Float64Counter(name, options...) + } + + cfg := metric.NewFloat64CounterConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*sfCounter)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Float64Counter), nil + } i := &sfCounter{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Float64UpDownCounter(name string, options ...metric.Float64UpDownCounterOption) (metric.Float64UpDownCounter, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Float64UpDownCounter(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Float64UpDownCounter(name, options...) + } + + cfg := metric.NewFloat64UpDownCounterConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*sfUpDownCounter)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Float64UpDownCounter), nil + } i := &sfUpDownCounter{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Float64Histogram(name string, options ...metric.Float64HistogramOption) (metric.Float64Histogram, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Float64Histogram(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Float64Histogram(name, options...) + } + + cfg := metric.NewFloat64HistogramConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*sfHistogram)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Float64Histogram), nil + } i := &sfHistogram{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Float64Gauge(name string, options ...metric.Float64GaugeOption) (metric.Float64Gauge, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Float64Gauge(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Float64Gauge(name, options...) + } + + cfg := metric.NewFloat64GaugeConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*sfGauge)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Float64Gauge), nil + } i := &sfGauge{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Float64ObservableCounter(name string, options ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Float64ObservableCounter(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Float64ObservableCounter(name, options...) + } + + cfg := metric.NewFloat64ObservableCounterConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*afCounter)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Float64ObservableCounter), nil + } i := &afCounter{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Float64ObservableUpDownCounter(name string, options ...metric.Float64ObservableUpDownCounterOption) (metric.Float64ObservableUpDownCounter, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Float64ObservableUpDownCounter(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Float64ObservableUpDownCounter(name, options...) + } + + cfg := metric.NewFloat64ObservableUpDownCounterConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*afUpDownCounter)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Float64ObservableUpDownCounter), nil + } i := &afUpDownCounter{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } func (m *meter) Float64ObservableGauge(name string, options ...metric.Float64ObservableGaugeOption) (metric.Float64ObservableGauge, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - return del.Float64ObservableGauge(name, options...) - } m.mtx.Lock() defer m.mtx.Unlock() + + if m.delegate != nil { + return m.delegate.Float64ObservableGauge(name, options...) + } + + cfg := metric.NewFloat64ObservableGaugeConfig(options...) + id := instID{ + name: name, + kind: reflect.TypeOf((*afGauge)(nil)), + description: cfg.Description(), + unit: cfg.Unit(), + } + if f, ok := m.instruments[id]; ok { + return f.(metric.Float64ObservableGauge), nil + } i := &afGauge{name: name, opts: options} - m.instruments = append(m.instruments, i) + m.instruments[id] = i return i, nil } // RegisterCallback captures the function that will be called during Collect. func (m *meter) RegisterCallback(f metric.Callback, insts ...metric.Observable) (metric.Registration, error) { - if del, ok := m.delegate.Load().(metric.Meter); ok { - insts = unwrapInstruments(insts) - return del.RegisterCallback(f, insts...) - } - m.mtx.Lock() defer m.mtx.Unlock() + if m.delegate != nil { + insts = unwrapInstruments(insts) + return m.delegate.RegisterCallback(f, insts...) + } + reg := ®istration{instruments: insts, function: f} e := m.registry.PushBack(reg) reg.unreg = func() error { @@ -349,6 +529,7 @@ func (c *registration) setDelegate(m metric.Meter) { reg, err := m.RegisterCallback(c.function, insts...) if err != nil { GetErrorHandler().Handle(err) + return } c.unreg = reg.Unregister diff --git a/tests/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go b/tests/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go index 3e7bb3b35..b2fe3e41d 100644 --- a/tests/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go +++ b/tests/vendor/go.opentelemetry.io/otel/internal/rawhelpers.go @@ -20,11 +20,13 @@ func RawToBool(r uint64) bool { } func Int64ToRaw(i int64) uint64 { - return uint64(i) + // Assumes original was a valid int64 (overflow not checked). + return uint64(i) // nolint: gosec } func RawToInt64(r uint64) int64 { - return int64(r) + // Assumes original was a valid int64 (overflow not checked). + return int64(r) // nolint: gosec } func Float64ToRaw(f float64) uint64 { @@ -36,9 +38,11 @@ func RawToFloat64(r uint64) float64 { } func RawPtrToFloat64Ptr(r *uint64) *float64 { - return (*float64)(unsafe.Pointer(r)) + // Assumes original was a valid *float64 (overflow not checked). + return (*float64)(unsafe.Pointer(r)) // nolint: gosec } func RawPtrToInt64Ptr(r *uint64) *int64 { - return (*int64)(unsafe.Pointer(r)) + // Assumes original was a valid *int64 (overflow not checked). + return (*int64)(unsafe.Pointer(r)) // nolint: gosec } diff --git a/tests/vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go b/tests/vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go index cf23db778..f8435d8f2 100644 --- a/tests/vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go +++ b/tests/vendor/go.opentelemetry.io/otel/metric/asyncfloat64.go @@ -213,7 +213,7 @@ type Float64Observer interface { } // Float64Callback is a function registered with a Meter that makes -// observations for a Float64Observerable instrument it is registered with. +// observations for a Float64Observable instrument it is registered with. // Calls to the Float64Observer record measurement values for the // Float64Observable. // diff --git a/tests/vendor/go.opentelemetry.io/otel/metric/asyncint64.go b/tests/vendor/go.opentelemetry.io/otel/metric/asyncint64.go index c82ba5324..e079aaef1 100644 --- a/tests/vendor/go.opentelemetry.io/otel/metric/asyncint64.go +++ b/tests/vendor/go.opentelemetry.io/otel/metric/asyncint64.go @@ -212,7 +212,7 @@ type Int64Observer interface { } // Int64Callback is a function registered with a Meter that makes observations -// for an Int64Observerable instrument it is registered with. Calls to the +// for an Int64Observable instrument it is registered with. Calls to the // Int64Observer record measurement values for the Int64Observable. // // The function needs to complete in a finite amount of time and the deadline diff --git a/tests/vendor/go.opentelemetry.io/otel/metric/instrument.go b/tests/vendor/go.opentelemetry.io/otel/metric/instrument.go index ea52e4023..a535782e1 100644 --- a/tests/vendor/go.opentelemetry.io/otel/metric/instrument.go +++ b/tests/vendor/go.opentelemetry.io/otel/metric/instrument.go @@ -351,7 +351,7 @@ func WithAttributeSet(attributes attribute.Set) MeasurementOption { // // cp := make([]attribute.KeyValue, len(attributes)) // copy(cp, attributes) -// WithAttributes(attribute.NewSet(cp...)) +// WithAttributeSet(attribute.NewSet(cp...)) // // [attribute.NewSet] may modify the passed attributes so this will make a copy // of attributes before creating a set in order to ensure this function is diff --git a/tests/vendor/go.opentelemetry.io/otel/metric/meter.go b/tests/vendor/go.opentelemetry.io/otel/metric/meter.go index 6a7991e01..14e08c24a 100644 --- a/tests/vendor/go.opentelemetry.io/otel/metric/meter.go +++ b/tests/vendor/go.opentelemetry.io/otel/metric/meter.go @@ -52,6 +52,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Int64Counter(name string, options ...Int64CounterOption) (Int64Counter, error) + // Int64UpDownCounter returns a new Int64UpDownCounter instrument // identified by name and configured with options. The instrument is used // to synchronously record int64 measurements during a computational @@ -61,6 +62,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Int64UpDownCounter(name string, options ...Int64UpDownCounterOption) (Int64UpDownCounter, error) + // Int64Histogram returns a new Int64Histogram instrument identified by // name and configured with options. The instrument is used to // synchronously record the distribution of int64 measurements during a @@ -70,6 +72,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Int64Histogram(name string, options ...Int64HistogramOption) (Int64Histogram, error) + // Int64Gauge returns a new Int64Gauge instrument identified by name and // configured with options. The instrument is used to synchronously record // instantaneous int64 measurements during a computational operation. @@ -78,6 +81,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Int64Gauge(name string, options ...Int64GaugeOption) (Int64Gauge, error) + // Int64ObservableCounter returns a new Int64ObservableCounter identified // by name and configured with options. The instrument is used to // asynchronously record increasing int64 measurements once per a @@ -92,6 +96,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Int64ObservableCounter(name string, options ...Int64ObservableCounterOption) (Int64ObservableCounter, error) + // Int64ObservableUpDownCounter returns a new Int64ObservableUpDownCounter // instrument identified by name and configured with options. The // instrument is used to asynchronously record int64 measurements once per @@ -106,6 +111,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Int64ObservableUpDownCounter(name string, options ...Int64ObservableUpDownCounterOption) (Int64ObservableUpDownCounter, error) + // Int64ObservableGauge returns a new Int64ObservableGauge instrument // identified by name and configured with options. The instrument is used // to asynchronously record instantaneous int64 measurements once per a @@ -130,6 +136,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Float64Counter(name string, options ...Float64CounterOption) (Float64Counter, error) + // Float64UpDownCounter returns a new Float64UpDownCounter instrument // identified by name and configured with options. The instrument is used // to synchronously record float64 measurements during a computational @@ -139,6 +146,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Float64UpDownCounter(name string, options ...Float64UpDownCounterOption) (Float64UpDownCounter, error) + // Float64Histogram returns a new Float64Histogram instrument identified by // name and configured with options. The instrument is used to // synchronously record the distribution of float64 measurements during a @@ -148,6 +156,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Float64Histogram(name string, options ...Float64HistogramOption) (Float64Histogram, error) + // Float64Gauge returns a new Float64Gauge instrument identified by name and // configured with options. The instrument is used to synchronously record // instantaneous float64 measurements during a computational operation. @@ -156,6 +165,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Float64Gauge(name string, options ...Float64GaugeOption) (Float64Gauge, error) + // Float64ObservableCounter returns a new Float64ObservableCounter // instrument identified by name and configured with options. The // instrument is used to asynchronously record increasing float64 @@ -170,6 +180,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Float64ObservableCounter(name string, options ...Float64ObservableCounterOption) (Float64ObservableCounter, error) + // Float64ObservableUpDownCounter returns a new // Float64ObservableUpDownCounter instrument identified by name and // configured with options. The instrument is used to asynchronously record @@ -184,6 +195,7 @@ type Meter interface { // See the Instrument Name section of the package documentation for more // information. Float64ObservableUpDownCounter(name string, options ...Float64ObservableUpDownCounterOption) (Float64ObservableUpDownCounter, error) + // Float64ObservableGauge returns a new Float64ObservableGauge instrument // identified by name and configured with options. The instrument is used // to asynchronously record instantaneous float64 measurements once per a @@ -242,6 +254,7 @@ type Observer interface { // ObserveFloat64 records the float64 value for obsrv. ObserveFloat64(obsrv Float64Observable, value float64, opts ...ObserveOption) + // ObserveInt64 records the int64 value for obsrv. ObserveInt64(obsrv Int64Observable, value int64, opts ...ObserveOption) } diff --git a/tests/vendor/go.opentelemetry.io/otel/renovate.json b/tests/vendor/go.opentelemetry.io/otel/renovate.json index 8c5ac55ca..0a29a2f13 100644 --- a/tests/vendor/go.opentelemetry.io/otel/renovate.json +++ b/tests/vendor/go.opentelemetry.io/otel/renovate.json @@ -19,6 +19,14 @@ "matchManagers": ["gomod"], "matchDepTypes": ["indirect"], "enabled": false + }, + { + "matchPackageNames": ["google.golang.org/genproto/googleapis/**"], + "groupName": "googleapis" + }, + { + "matchPackageNames": ["golang.org/x/**"], + "groupName": "golang.org/x" } ] } diff --git a/tests/vendor/go.opentelemetry.io/otel/trace/context.go b/tests/vendor/go.opentelemetry.io/otel/trace/context.go index 5650a174b..8c45a7107 100644 --- a/tests/vendor/go.opentelemetry.io/otel/trace/context.go +++ b/tests/vendor/go.opentelemetry.io/otel/trace/context.go @@ -22,7 +22,7 @@ func ContextWithSpanContext(parent context.Context, sc SpanContext) context.Cont return ContextWithSpan(parent, nonRecordingSpan{sc: sc}) } -// ContextWithRemoteSpanContext returns a copy of parent with rsc set explicly +// ContextWithRemoteSpanContext returns a copy of parent with rsc set explicitly // as a remote SpanContext and as the current Span. The Span implementation // that wraps rsc is non-recording and performs no operations other than to // return rsc as the SpanContext from the SpanContext method. diff --git a/tests/vendor/go.opentelemetry.io/otel/trace/doc.go b/tests/vendor/go.opentelemetry.io/otel/trace/doc.go index d661c5d10..cdbf41d6d 100644 --- a/tests/vendor/go.opentelemetry.io/otel/trace/doc.go +++ b/tests/vendor/go.opentelemetry.io/otel/trace/doc.go @@ -96,7 +96,7 @@ can embed the API interface directly. This option is not recommended. It will lead to publishing packages that contain runtime panics when users update to newer versions of -[go.opentelemetry.io/otel/trace], which may be done with a trasitive +[go.opentelemetry.io/otel/trace], which may be done with a transitive dependency. Finally, an author can embed another implementation in theirs. The embedded diff --git a/tests/vendor/go.opentelemetry.io/otel/trace/provider.go b/tests/vendor/go.opentelemetry.io/otel/trace/provider.go new file mode 100644 index 000000000..ef85cb70c --- /dev/null +++ b/tests/vendor/go.opentelemetry.io/otel/trace/provider.go @@ -0,0 +1,59 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package trace // import "go.opentelemetry.io/otel/trace" + +import "go.opentelemetry.io/otel/trace/embedded" + +// TracerProvider provides Tracers that are used by instrumentation code to +// trace computational workflows. +// +// A TracerProvider is the collection destination of all Spans from Tracers it +// provides, it represents a unique telemetry collection pipeline. How that +// pipeline is defined, meaning how those Spans are collected, processed, and +// where they are exported, depends on its implementation. Instrumentation +// authors do not need to define this implementation, rather just use the +// provided Tracers to instrument code. +// +// Commonly, instrumentation code will accept a TracerProvider implementation +// at runtime from its users or it can simply use the globally registered one +// (see https://pkg.go.dev/go.opentelemetry.io/otel#GetTracerProvider). +// +// Warning: Methods may be added to this interface in minor releases. See +// package documentation on API implementation for information on how to set +// default behavior for unimplemented methods. +type TracerProvider interface { + // Users of the interface can ignore this. This embedded type is only used + // by implementations of this interface. See the "API Implementations" + // section of the package documentation for more information. + embedded.TracerProvider + + // Tracer returns a unique Tracer scoped to be used by instrumentation code + // to trace computational workflows. The scope and identity of that + // instrumentation code is uniquely defined by the name and options passed. + // + // The passed name needs to uniquely identify instrumentation code. + // Therefore, it is recommended that name is the Go package name of the + // library providing instrumentation (note: not the code being + // instrumented). Instrumentation libraries can have multiple versions, + // therefore, the WithInstrumentationVersion option should be used to + // distinguish these different codebases. Additionally, instrumentation + // libraries may sometimes use traces to communicate different domains of + // workflow data (i.e. using spans to communicate workflow events only). If + // this is the case, the WithScopeAttributes option should be used to + // uniquely identify Tracers that handle the different domains of workflow + // data. + // + // If the same name and options are passed multiple times, the same Tracer + // will be returned (it is up to the implementation if this will be the + // same underlying instance of that Tracer or not). It is not necessary to + // call this multiple times with the same name and options to get an + // up-to-date Tracer. All implementations will ensure any TracerProvider + // configuration changes are propagated to all provided Tracers. + // + // If name is empty, then an implementation defined default name will be + // used instead. + // + // This method is safe to call concurrently. + Tracer(name string, options ...TracerOption) Tracer +} diff --git a/tests/vendor/go.opentelemetry.io/otel/trace/span.go b/tests/vendor/go.opentelemetry.io/otel/trace/span.go new file mode 100644 index 000000000..d3aa476ee --- /dev/null +++ b/tests/vendor/go.opentelemetry.io/otel/trace/span.go @@ -0,0 +1,177 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package trace // import "go.opentelemetry.io/otel/trace" + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace/embedded" +) + +// Span is the individual component of a trace. It represents a single named +// and timed operation of a workflow that is traced. A Tracer is used to +// create a Span and it is then up to the operation the Span represents to +// properly end the Span when the operation itself ends. +// +// Warning: Methods may be added to this interface in minor releases. See +// package documentation on API implementation for information on how to set +// default behavior for unimplemented methods. +type Span interface { + // Users of the interface can ignore this. This embedded type is only used + // by implementations of this interface. See the "API Implementations" + // section of the package documentation for more information. + embedded.Span + + // End completes the Span. The Span is considered complete and ready to be + // delivered through the rest of the telemetry pipeline after this method + // is called. Therefore, updates to the Span are not allowed after this + // method has been called. + End(options ...SpanEndOption) + + // AddEvent adds an event with the provided name and options. + AddEvent(name string, options ...EventOption) + + // AddLink adds a link. + // Adding links at span creation using WithLinks is preferred to calling AddLink + // later, for contexts that are available during span creation, because head + // sampling decisions can only consider information present during span creation. + AddLink(link Link) + + // IsRecording returns the recording state of the Span. It will return + // true if the Span is active and events can be recorded. + IsRecording() bool + + // RecordError will record err as an exception span event for this span. An + // additional call to SetStatus is required if the Status of the Span should + // be set to Error, as this method does not change the Span status. If this + // span is not being recorded or err is nil then this method does nothing. + RecordError(err error, options ...EventOption) + + // SpanContext returns the SpanContext of the Span. The returned SpanContext + // is usable even after the End method has been called for the Span. + SpanContext() SpanContext + + // SetStatus sets the status of the Span in the form of a code and a + // description, provided the status hasn't already been set to a higher + // value before (OK > Error > Unset). The description is only included in a + // status when the code is for an error. + SetStatus(code codes.Code, description string) + + // SetName sets the Span name. + SetName(name string) + + // SetAttributes sets kv as attributes of the Span. If a key from kv + // already exists for an attribute of the Span it will be overwritten with + // the value contained in kv. + SetAttributes(kv ...attribute.KeyValue) + + // TracerProvider returns a TracerProvider that can be used to generate + // additional Spans on the same telemetry pipeline as the current Span. + TracerProvider() TracerProvider +} + +// Link is the relationship between two Spans. The relationship can be within +// the same Trace or across different Traces. +// +// For example, a Link is used in the following situations: +// +// 1. Batch Processing: A batch of operations may contain operations +// associated with one or more traces/spans. Since there can only be one +// parent SpanContext, a Link is used to keep reference to the +// SpanContext of all operations in the batch. +// 2. Public Endpoint: A SpanContext for an in incoming client request on a +// public endpoint should be considered untrusted. In such a case, a new +// trace with its own identity and sampling decision needs to be created, +// but this new trace needs to be related to the original trace in some +// form. A Link is used to keep reference to the original SpanContext and +// track the relationship. +type Link struct { + // SpanContext of the linked Span. + SpanContext SpanContext + + // Attributes describe the aspects of the link. + Attributes []attribute.KeyValue +} + +// LinkFromContext returns a link encapsulating the SpanContext in the provided +// ctx. +func LinkFromContext(ctx context.Context, attrs ...attribute.KeyValue) Link { + return Link{ + SpanContext: SpanContextFromContext(ctx), + Attributes: attrs, + } +} + +// SpanKind is the role a Span plays in a Trace. +type SpanKind int + +// As a convenience, these match the proto definition, see +// https://github.com/open-telemetry/opentelemetry-proto/blob/30d237e1ff3ab7aa50e0922b5bebdd93505090af/opentelemetry/proto/trace/v1/trace.proto#L101-L129 +// +// The unspecified value is not a valid `SpanKind`. Use `ValidateSpanKind()` +// to coerce a span kind to a valid value. +const ( + // SpanKindUnspecified is an unspecified SpanKind and is not a valid + // SpanKind. SpanKindUnspecified should be replaced with SpanKindInternal + // if it is received. + SpanKindUnspecified SpanKind = 0 + // SpanKindInternal is a SpanKind for a Span that represents an internal + // operation within an application. + SpanKindInternal SpanKind = 1 + // SpanKindServer is a SpanKind for a Span that represents the operation + // of handling a request from a client. + SpanKindServer SpanKind = 2 + // SpanKindClient is a SpanKind for a Span that represents the operation + // of client making a request to a server. + SpanKindClient SpanKind = 3 + // SpanKindProducer is a SpanKind for a Span that represents the operation + // of a producer sending a message to a message broker. Unlike + // SpanKindClient and SpanKindServer, there is often no direct + // relationship between this kind of Span and a SpanKindConsumer kind. A + // SpanKindProducer Span will end once the message is accepted by the + // message broker which might not overlap with the processing of that + // message. + SpanKindProducer SpanKind = 4 + // SpanKindConsumer is a SpanKind for a Span that represents the operation + // of a consumer receiving a message from a message broker. Like + // SpanKindProducer Spans, there is often no direct relationship between + // this Span and the Span that produced the message. + SpanKindConsumer SpanKind = 5 +) + +// ValidateSpanKind returns a valid span kind value. This will coerce +// invalid values into the default value, SpanKindInternal. +func ValidateSpanKind(spanKind SpanKind) SpanKind { + switch spanKind { + case SpanKindInternal, + SpanKindServer, + SpanKindClient, + SpanKindProducer, + SpanKindConsumer: + // valid + return spanKind + default: + return SpanKindInternal + } +} + +// String returns the specified name of the SpanKind in lower-case. +func (sk SpanKind) String() string { + switch sk { + case SpanKindInternal: + return "internal" + case SpanKindServer: + return "server" + case SpanKindClient: + return "client" + case SpanKindProducer: + return "producer" + case SpanKindConsumer: + return "consumer" + default: + return "unspecified" + } +} diff --git a/tests/vendor/go.opentelemetry.io/otel/trace/trace.go b/tests/vendor/go.opentelemetry.io/otel/trace/trace.go index 28877d4ab..d49adf671 100644 --- a/tests/vendor/go.opentelemetry.io/otel/trace/trace.go +++ b/tests/vendor/go.opentelemetry.io/otel/trace/trace.go @@ -5,13 +5,8 @@ package trace // import "go.opentelemetry.io/otel/trace" import ( "bytes" - "context" "encoding/hex" "encoding/json" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/trace/embedded" ) const ( @@ -326,247 +321,3 @@ func (sc SpanContext) MarshalJSON() ([]byte, error) { Remote: sc.remote, }) } - -// Span is the individual component of a trace. It represents a single named -// and timed operation of a workflow that is traced. A Tracer is used to -// create a Span and it is then up to the operation the Span represents to -// properly end the Span when the operation itself ends. -// -// Warning: Methods may be added to this interface in minor releases. See -// package documentation on API implementation for information on how to set -// default behavior for unimplemented methods. -type Span interface { - // Users of the interface can ignore this. This embedded type is only used - // by implementations of this interface. See the "API Implementations" - // section of the package documentation for more information. - embedded.Span - - // End completes the Span. The Span is considered complete and ready to be - // delivered through the rest of the telemetry pipeline after this method - // is called. Therefore, updates to the Span are not allowed after this - // method has been called. - End(options ...SpanEndOption) - - // AddEvent adds an event with the provided name and options. - AddEvent(name string, options ...EventOption) - - // AddLink adds a link. - // Adding links at span creation using WithLinks is preferred to calling AddLink - // later, for contexts that are available during span creation, because head - // sampling decisions can only consider information present during span creation. - AddLink(link Link) - - // IsRecording returns the recording state of the Span. It will return - // true if the Span is active and events can be recorded. - IsRecording() bool - - // RecordError will record err as an exception span event for this span. An - // additional call to SetStatus is required if the Status of the Span should - // be set to Error, as this method does not change the Span status. If this - // span is not being recorded or err is nil then this method does nothing. - RecordError(err error, options ...EventOption) - - // SpanContext returns the SpanContext of the Span. The returned SpanContext - // is usable even after the End method has been called for the Span. - SpanContext() SpanContext - - // SetStatus sets the status of the Span in the form of a code and a - // description, provided the status hasn't already been set to a higher - // value before (OK > Error > Unset). The description is only included in a - // status when the code is for an error. - SetStatus(code codes.Code, description string) - - // SetName sets the Span name. - SetName(name string) - - // SetAttributes sets kv as attributes of the Span. If a key from kv - // already exists for an attribute of the Span it will be overwritten with - // the value contained in kv. - SetAttributes(kv ...attribute.KeyValue) - - // TracerProvider returns a TracerProvider that can be used to generate - // additional Spans on the same telemetry pipeline as the current Span. - TracerProvider() TracerProvider -} - -// Link is the relationship between two Spans. The relationship can be within -// the same Trace or across different Traces. -// -// For example, a Link is used in the following situations: -// -// 1. Batch Processing: A batch of operations may contain operations -// associated with one or more traces/spans. Since there can only be one -// parent SpanContext, a Link is used to keep reference to the -// SpanContext of all operations in the batch. -// 2. Public Endpoint: A SpanContext for an in incoming client request on a -// public endpoint should be considered untrusted. In such a case, a new -// trace with its own identity and sampling decision needs to be created, -// but this new trace needs to be related to the original trace in some -// form. A Link is used to keep reference to the original SpanContext and -// track the relationship. -type Link struct { - // SpanContext of the linked Span. - SpanContext SpanContext - - // Attributes describe the aspects of the link. - Attributes []attribute.KeyValue -} - -// LinkFromContext returns a link encapsulating the SpanContext in the provided ctx. -func LinkFromContext(ctx context.Context, attrs ...attribute.KeyValue) Link { - return Link{ - SpanContext: SpanContextFromContext(ctx), - Attributes: attrs, - } -} - -// SpanKind is the role a Span plays in a Trace. -type SpanKind int - -// As a convenience, these match the proto definition, see -// https://github.com/open-telemetry/opentelemetry-proto/blob/30d237e1ff3ab7aa50e0922b5bebdd93505090af/opentelemetry/proto/trace/v1/trace.proto#L101-L129 -// -// The unspecified value is not a valid `SpanKind`. Use `ValidateSpanKind()` -// to coerce a span kind to a valid value. -const ( - // SpanKindUnspecified is an unspecified SpanKind and is not a valid - // SpanKind. SpanKindUnspecified should be replaced with SpanKindInternal - // if it is received. - SpanKindUnspecified SpanKind = 0 - // SpanKindInternal is a SpanKind for a Span that represents an internal - // operation within an application. - SpanKindInternal SpanKind = 1 - // SpanKindServer is a SpanKind for a Span that represents the operation - // of handling a request from a client. - SpanKindServer SpanKind = 2 - // SpanKindClient is a SpanKind for a Span that represents the operation - // of client making a request to a server. - SpanKindClient SpanKind = 3 - // SpanKindProducer is a SpanKind for a Span that represents the operation - // of a producer sending a message to a message broker. Unlike - // SpanKindClient and SpanKindServer, there is often no direct - // relationship between this kind of Span and a SpanKindConsumer kind. A - // SpanKindProducer Span will end once the message is accepted by the - // message broker which might not overlap with the processing of that - // message. - SpanKindProducer SpanKind = 4 - // SpanKindConsumer is a SpanKind for a Span that represents the operation - // of a consumer receiving a message from a message broker. Like - // SpanKindProducer Spans, there is often no direct relationship between - // this Span and the Span that produced the message. - SpanKindConsumer SpanKind = 5 -) - -// ValidateSpanKind returns a valid span kind value. This will coerce -// invalid values into the default value, SpanKindInternal. -func ValidateSpanKind(spanKind SpanKind) SpanKind { - switch spanKind { - case SpanKindInternal, - SpanKindServer, - SpanKindClient, - SpanKindProducer, - SpanKindConsumer: - // valid - return spanKind - default: - return SpanKindInternal - } -} - -// String returns the specified name of the SpanKind in lower-case. -func (sk SpanKind) String() string { - switch sk { - case SpanKindInternal: - return "internal" - case SpanKindServer: - return "server" - case SpanKindClient: - return "client" - case SpanKindProducer: - return "producer" - case SpanKindConsumer: - return "consumer" - default: - return "unspecified" - } -} - -// Tracer is the creator of Spans. -// -// Warning: Methods may be added to this interface in minor releases. See -// package documentation on API implementation for information on how to set -// default behavior for unimplemented methods. -type Tracer interface { - // Users of the interface can ignore this. This embedded type is only used - // by implementations of this interface. See the "API Implementations" - // section of the package documentation for more information. - embedded.Tracer - - // Start creates a span and a context.Context containing the newly-created span. - // - // If the context.Context provided in `ctx` contains a Span then the newly-created - // Span will be a child of that span, otherwise it will be a root span. This behavior - // can be overridden by providing `WithNewRoot()` as a SpanOption, causing the - // newly-created Span to be a root span even if `ctx` contains a Span. - // - // When creating a Span it is recommended to provide all known span attributes using - // the `WithAttributes()` SpanOption as samplers will only have access to the - // attributes provided when a Span is created. - // - // Any Span that is created MUST also be ended. This is the responsibility of the user. - // Implementations of this API may leak memory or other resources if Spans are not ended. - Start(ctx context.Context, spanName string, opts ...SpanStartOption) (context.Context, Span) -} - -// TracerProvider provides Tracers that are used by instrumentation code to -// trace computational workflows. -// -// A TracerProvider is the collection destination of all Spans from Tracers it -// provides, it represents a unique telemetry collection pipeline. How that -// pipeline is defined, meaning how those Spans are collected, processed, and -// where they are exported, depends on its implementation. Instrumentation -// authors do not need to define this implementation, rather just use the -// provided Tracers to instrument code. -// -// Commonly, instrumentation code will accept a TracerProvider implementation -// at runtime from its users or it can simply use the globally registered one -// (see https://pkg.go.dev/go.opentelemetry.io/otel#GetTracerProvider). -// -// Warning: Methods may be added to this interface in minor releases. See -// package documentation on API implementation for information on how to set -// default behavior for unimplemented methods. -type TracerProvider interface { - // Users of the interface can ignore this. This embedded type is only used - // by implementations of this interface. See the "API Implementations" - // section of the package documentation for more information. - embedded.TracerProvider - - // Tracer returns a unique Tracer scoped to be used by instrumentation code - // to trace computational workflows. The scope and identity of that - // instrumentation code is uniquely defined by the name and options passed. - // - // The passed name needs to uniquely identify instrumentation code. - // Therefore, it is recommended that name is the Go package name of the - // library providing instrumentation (note: not the code being - // instrumented). Instrumentation libraries can have multiple versions, - // therefore, the WithInstrumentationVersion option should be used to - // distinguish these different codebases. Additionally, instrumentation - // libraries may sometimes use traces to communicate different domains of - // workflow data (i.e. using spans to communicate workflow events only). If - // this is the case, the WithScopeAttributes option should be used to - // uniquely identify Tracers that handle the different domains of workflow - // data. - // - // If the same name and options are passed multiple times, the same Tracer - // will be returned (it is up to the implementation if this will be the - // same underlying instance of that Tracer or not). It is not necessary to - // call this multiple times with the same name and options to get an - // up-to-date Tracer. All implementations will ensure any TracerProvider - // configuration changes are propagated to all provided Tracers. - // - // If name is empty, then an implementation defined default name will be - // used instead. - // - // This method is safe to call concurrently. - Tracer(name string, options ...TracerOption) Tracer -} diff --git a/tests/vendor/go.opentelemetry.io/otel/trace/tracer.go b/tests/vendor/go.opentelemetry.io/otel/trace/tracer.go new file mode 100644 index 000000000..77952d2a0 --- /dev/null +++ b/tests/vendor/go.opentelemetry.io/otel/trace/tracer.go @@ -0,0 +1,37 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package trace // import "go.opentelemetry.io/otel/trace" + +import ( + "context" + + "go.opentelemetry.io/otel/trace/embedded" +) + +// Tracer is the creator of Spans. +// +// Warning: Methods may be added to this interface in minor releases. See +// package documentation on API implementation for information on how to set +// default behavior for unimplemented methods. +type Tracer interface { + // Users of the interface can ignore this. This embedded type is only used + // by implementations of this interface. See the "API Implementations" + // section of the package documentation for more information. + embedded.Tracer + + // Start creates a span and a context.Context containing the newly-created span. + // + // If the context.Context provided in `ctx` contains a Span then the newly-created + // Span will be a child of that span, otherwise it will be a root span. This behavior + // can be overridden by providing `WithNewRoot()` as a SpanOption, causing the + // newly-created Span to be a root span even if `ctx` contains a Span. + // + // When creating a Span it is recommended to provide all known span attributes using + // the `WithAttributes()` SpanOption as samplers will only have access to the + // attributes provided when a Span is created. + // + // Any Span that is created MUST also be ended. This is the responsibility of the user. + // Implementations of this API may leak memory or other resources if Spans are not ended. + Start(ctx context.Context, spanName string, opts ...SpanStartOption) (context.Context, Span) +} diff --git a/tests/vendor/go.opentelemetry.io/otel/trace/tracestate.go b/tests/vendor/go.opentelemetry.io/otel/trace/tracestate.go index 20b5cf243..dc5e34cad 100644 --- a/tests/vendor/go.opentelemetry.io/otel/trace/tracestate.go +++ b/tests/vendor/go.opentelemetry.io/otel/trace/tracestate.go @@ -260,6 +260,16 @@ func (ts TraceState) Get(key string) string { return "" } +// Walk walks all key value pairs in the TraceState by calling f +// Iteration stops if f returns false. +func (ts TraceState) Walk(f func(key, value string) bool) { + for _, m := range ts.list { + if !f(m.Key, m.Value) { + break + } + } +} + // Insert adds a new list-member defined by the key/value pair to the // TraceState. If a list-member already exists for the given key, that // list-member's value is updated. The new or updated list-member is always diff --git a/tests/vendor/go.opentelemetry.io/otel/verify_examples.sh b/tests/vendor/go.opentelemetry.io/otel/verify_examples.sh deleted file mode 100644 index e57bf57fc..000000000 --- a/tests/vendor/go.opentelemetry.io/otel/verify_examples.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash - -# Copyright The OpenTelemetry Authors -# SPDX-License-Identifier: Apache-2.0 - -set -euo pipefail - -cd $(dirname $0) -TOOLS_DIR=$(pwd)/.tools - -if [ -z "${GOPATH}" ] ; then - printf "GOPATH is not defined.\n" - exit -1 -fi - -if [ ! -d "${GOPATH}" ] ; then - printf "GOPATH ${GOPATH} is invalid \n" - exit -1 -fi - -# Pre-requisites -if ! git diff --quiet; then \ - git status - printf "\n\nError: working tree is not clean\n" - exit -1 -fi - -if [ "$(git tag --contains $(git log -1 --pretty=format:"%H"))" = "" ] ; then - printf "$(git log -1)" - printf "\n\nError: HEAD is not pointing to a tagged version" -fi - -make ${TOOLS_DIR}/gojq - -DIR_TMP="${GOPATH}/src/oteltmp/" -rm -rf $DIR_TMP -mkdir -p $DIR_TMP - -printf "Copy examples to ${DIR_TMP}\n" -cp -a ./example ${DIR_TMP} - -# Update go.mod files -printf "Update go.mod: rename module and remove replace\n" - -PACKAGE_DIRS=$(find . -mindepth 2 -type f -name 'go.mod' -exec dirname {} \; | egrep 'example' | sed 's/^\.\///' | sort) - -for dir in $PACKAGE_DIRS; do - printf " Update go.mod for $dir\n" - (cd "${DIR_TMP}/${dir}" && \ - # replaces is ("mod1" "mod2" …) - replaces=($(go mod edit -json | ${TOOLS_DIR}/gojq '.Replace[].Old.Path')) && \ - # strip double quotes - replaces=("${replaces[@]%\"}") && \ - replaces=("${replaces[@]#\"}") && \ - # make an array (-dropreplace=mod1 -dropreplace=mod2 …) - dropreplaces=("${replaces[@]/#/-dropreplace=}") && \ - go mod edit -module "oteltmp/${dir}" "${dropreplaces[@]}" && \ - go mod tidy) -done -printf "Update done:\n\n" - -# Build directories that contain main package. These directories are different than -# directories that contain go.mod files. -printf "Build examples:\n" -EXAMPLES=$(./get_main_pkgs.sh ./example) -for ex in $EXAMPLES; do - printf " Build $ex in ${DIR_TMP}/${ex}\n" - (cd "${DIR_TMP}/${ex}" && \ - go build .) -done - -# Cleanup -printf "Remove copied files.\n" -rm -rf $DIR_TMP diff --git a/tests/vendor/go.opentelemetry.io/otel/verify_released_changelog.sh b/tests/vendor/go.opentelemetry.io/otel/verify_released_changelog.sh new file mode 100644 index 000000000..c9b7cdbbf --- /dev/null +++ b/tests/vendor/go.opentelemetry.io/otel/verify_released_changelog.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +TARGET="${1:?Must provide target ref}" + +FILE="CHANGELOG.md" +TEMP_DIR=$(mktemp -d) +echo "Temp folder: $TEMP_DIR" + +# Only the latest commit of the feature branch is available +# automatically. To diff with the base branch, we need to +# fetch that too (and we only need its latest commit). +git fetch origin "${TARGET}" --depth=1 + +# Checkout the previous version on the base branch of the changelog to tmpfolder +git --work-tree="$TEMP_DIR" checkout FETCH_HEAD $FILE + +PREVIOUS_FILE="$TEMP_DIR/$FILE" +CURRENT_FILE="$FILE" +PREVIOUS_LOCKED_FILE="$TEMP_DIR/previous_locked_section.md" +CURRENT_LOCKED_FILE="$TEMP_DIR/current_locked_section.md" + +# Extract released sections from the previous version +awk '/^/ {flag=1} /^/ {flag=0} flag' "$PREVIOUS_FILE" > "$PREVIOUS_LOCKED_FILE" + +# Extract released sections from the current version +awk '/^/ {flag=1} /^/ {flag=0} flag' "$CURRENT_FILE" > "$CURRENT_LOCKED_FILE" + +# Compare the released sections +if ! diff -q "$PREVIOUS_LOCKED_FILE" "$CURRENT_LOCKED_FILE"; then + echo "Error: The released sections of the changelog file have been modified." + diff "$PREVIOUS_LOCKED_FILE" "$CURRENT_LOCKED_FILE" + rm -rf "$TEMP_DIR" + false +fi + +rm -rf "$TEMP_DIR" +echo "The released sections remain unchanged." diff --git a/tests/vendor/go.opentelemetry.io/otel/version.go b/tests/vendor/go.opentelemetry.io/otel/version.go index ab2896052..6d3c7b1f4 100644 --- a/tests/vendor/go.opentelemetry.io/otel/version.go +++ b/tests/vendor/go.opentelemetry.io/otel/version.go @@ -5,5 +5,5 @@ package otel // import "go.opentelemetry.io/otel" // Version is the current release version of OpenTelemetry in use. func Version() string { - return "1.28.0" + return "1.31.0" } diff --git a/tests/vendor/go.opentelemetry.io/otel/versions.yaml b/tests/vendor/go.opentelemetry.io/otel/versions.yaml index 241cfc82a..cdebdb5eb 100644 --- a/tests/vendor/go.opentelemetry.io/otel/versions.yaml +++ b/tests/vendor/go.opentelemetry.io/otel/versions.yaml @@ -3,7 +3,7 @@ module-sets: stable-v1: - version: v1.28.0 + version: v1.31.0 modules: - go.opentelemetry.io/otel - go.opentelemetry.io/otel/bridge/opencensus @@ -29,21 +29,21 @@ module-sets: - go.opentelemetry.io/otel/sdk/metric - go.opentelemetry.io/otel/trace experimental-metrics: - version: v0.50.0 + version: v0.53.0 modules: - go.opentelemetry.io/otel/example/prometheus - go.opentelemetry.io/otel/exporters/prometheus experimental-logs: - version: v0.4.0 + version: v0.7.0 modules: - go.opentelemetry.io/otel/log - go.opentelemetry.io/otel/sdk/log + - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp - go.opentelemetry.io/otel/exporters/stdout/stdoutlog experimental-schema: - version: v0.0.8 + version: v0.0.10 modules: - go.opentelemetry.io/otel/schema excluded-modules: - go.opentelemetry.io/otel/internal/tools - - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc diff --git a/tests/vendor/go.starlark.net/LICENSE b/tests/vendor/go.starlark.net/LICENSE deleted file mode 100644 index a6609a143..000000000 --- a/tests/vendor/go.starlark.net/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (c) 2017 The Bazel Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the - distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/vendor/go.starlark.net/internal/compile/compile.go b/tests/vendor/go.starlark.net/internal/compile/compile.go deleted file mode 100644 index ecf689f05..000000000 --- a/tests/vendor/go.starlark.net/internal/compile/compile.go +++ /dev/null @@ -1,1927 +0,0 @@ -// Package compile defines the Starlark bytecode compiler. -// It is an internal package of the Starlark interpreter and is not directly accessible to clients. -// -// The compiler generates byte code with optional uint32 operands for a -// virtual machine with the following components: -// - a program counter, which is an index into the byte code array. -// - an operand stack, whose maximum size is computed for each function by the compiler. -// - an stack of active iterators. -// - an array of local variables. -// The number of local variables and their indices are computed by the resolver. -// Locals (possibly including parameters) that are shared with nested functions -// are 'cells': their locals array slot will contain a value of type 'cell', -// an indirect value in a box that is explicitly read/updated by instructions. -// - an array of free variables, for nested functions. -// Free variables are a subset of the ancestors' cell variables. -// As with locals and cells, these are computed by the resolver. -// - an array of global variables, shared among all functions in the same module. -// All elements are initially nil. -// - two maps of predeclared and universal identifiers. -// -// Each function has a line number table that maps each program counter -// offset to a source position, including the column number. -// -// Operands, logically uint32s, are encoded using little-endian 7-bit -// varints, the top bit indicating that more bytes follow. -package compile // import "go.starlark.net/internal/compile" - -import ( - "bytes" - "fmt" - "log" - "os" - "path/filepath" - "strconv" - "strings" - "sync" - - "go.starlark.net/resolve" - "go.starlark.net/syntax" -) - -// Disassemble causes the assembly code for each function -// to be printed to stderr as it is generated. -var Disassemble = false - -const debug = false // make code generation verbose, for debugging the compiler - -// Increment this to force recompilation of saved bytecode files. -const Version = 14 - -type Opcode uint8 - -// "x DUP x x" is a "stack picture" that describes the state of the -// stack before and after execution of the instruction. -// -// OP indicates an immediate operand that is an index into the -// specified table: locals, names, freevars, constants. -const ( - NOP Opcode = iota // - NOP - - - // stack operations - DUP // x DUP x x - DUP2 // x y DUP2 x y x y - POP // x POP - - EXCH // x y EXCH y x - - // binary comparisons - // (order must match Token) - LT - GT - GE - LE - EQL - NEQ - - // binary arithmetic - // (order must match Token) - PLUS - MINUS - STAR - SLASH - SLASHSLASH - PERCENT - AMP - PIPE - CIRCUMFLEX - LTLT - GTGT - - IN - - // unary operators - UPLUS // x UPLUS x - UMINUS // x UMINUS -x - TILDE // x TILDE ~x - - NONE // - NONE None - TRUE // - TRUE True - FALSE // - FALSE False - MANDATORY // - MANDATORY Mandatory [sentinel value for required kwonly args] - - ITERPUSH // iterable ITERPUSH - [pushes the iterator stack] - ITERPOP // - ITERPOP - [pops the iterator stack] - NOT // value NOT bool - RETURN // value RETURN - - SETINDEX // a i new SETINDEX - - INDEX // a i INDEX elem - SETDICT // dict key value SETDICT - - SETDICTUNIQ // dict key value SETDICTUNIQ - - APPEND // list elem APPEND - - SLICE // x lo hi step SLICE slice - INPLACE_ADD // x y INPLACE_ADD z where z is x+y or x.extend(y) - INPLACE_PIPE // x y INPLACE_PIPE z where z is x|y - MAKEDICT // - MAKEDICT dict - - // --- opcodes with an argument must go below this line --- - - // control flow - JMP // - JMP - - CJMP // cond CJMP - - ITERJMP // - ITERJMP elem (and fall through) [acts on topmost iterator] - // or: - ITERJMP - (and jump) - - CONSTANT // - CONSTANT value - MAKETUPLE // x1 ... xn MAKETUPLE tuple - MAKELIST // x1 ... xn MAKELIST list - MAKEFUNC // defaults+freevars MAKEFUNC fn - LOAD // from1 ... fromN module LOAD v1 ... vN - SETLOCAL // value SETLOCAL - - SETGLOBAL // value SETGLOBAL - - LOCAL // - LOCAL value - FREE // - FREE cell - FREECELL // - FREECELL value (content of FREE cell) - LOCALCELL // - LOCALCELL value (content of LOCAL cell) - SETLOCALCELL // value SETLOCALCELL - (set content of LOCAL cell) - GLOBAL // - GLOBAL value - PREDECLARED // - PREDECLARED value - UNIVERSAL // - UNIVERSAL value - ATTR // x ATTR y y = x.name - SETFIELD // x y SETFIELD - x.name = y - UNPACK // iterable UNPACK vn ... v1 - - // n>>8 is #positional args and n&0xff is #named args (pairs). - CALL // fn positional named CALL result - CALL_VAR // fn positional named *args CALL_VAR result - CALL_KW // fn positional named **kwargs CALL_KW result - CALL_VAR_KW // fn positional named *args **kwargs CALL_VAR_KW result - - OpcodeArgMin = JMP - OpcodeMax = CALL_VAR_KW -) - -// TODO(adonovan): add dynamic checks for missing opcodes in the tables below. - -var opcodeNames = [...]string{ - AMP: "amp", - APPEND: "append", - ATTR: "attr", - CALL: "call", - CALL_KW: "call_kw ", - CALL_VAR: "call_var", - CALL_VAR_KW: "call_var_kw", - CIRCUMFLEX: "circumflex", - CJMP: "cjmp", - CONSTANT: "constant", - DUP2: "dup2", - DUP: "dup", - EQL: "eql", - EXCH: "exch", - FALSE: "false", - FREE: "free", - FREECELL: "freecell", - GE: "ge", - GLOBAL: "global", - GT: "gt", - GTGT: "gtgt", - IN: "in", - INDEX: "index", - INPLACE_ADD: "inplace_add", - INPLACE_PIPE: "inplace_pipe", - ITERJMP: "iterjmp", - ITERPOP: "iterpop", - ITERPUSH: "iterpush", - JMP: "jmp", - LE: "le", - LOAD: "load", - LOCAL: "local", - LOCALCELL: "localcell", - LT: "lt", - LTLT: "ltlt", - MAKEDICT: "makedict", - MAKEFUNC: "makefunc", - MAKELIST: "makelist", - MAKETUPLE: "maketuple", - MANDATORY: "mandatory", - MINUS: "minus", - NEQ: "neq", - NONE: "none", - NOP: "nop", - NOT: "not", - PERCENT: "percent", - PIPE: "pipe", - PLUS: "plus", - POP: "pop", - PREDECLARED: "predeclared", - RETURN: "return", - SETDICT: "setdict", - SETDICTUNIQ: "setdictuniq", - SETFIELD: "setfield", - SETGLOBAL: "setglobal", - SETINDEX: "setindex", - SETLOCAL: "setlocal", - SETLOCALCELL: "setlocalcell", - SLASH: "slash", - SLASHSLASH: "slashslash", - SLICE: "slice", - STAR: "star", - TILDE: "tilde", - TRUE: "true", - UMINUS: "uminus", - UNIVERSAL: "universal", - UNPACK: "unpack", - UPLUS: "uplus", -} - -const variableStackEffect = 0x7f - -// stackEffect records the effect on the size of the operand stack of -// each kind of instruction. For some instructions this requires computation. -var stackEffect = [...]int8{ - AMP: -1, - APPEND: -2, - ATTR: 0, - CALL: variableStackEffect, - CALL_KW: variableStackEffect, - CALL_VAR: variableStackEffect, - CALL_VAR_KW: variableStackEffect, - CIRCUMFLEX: -1, - CJMP: -1, - CONSTANT: +1, - DUP2: +2, - DUP: +1, - EQL: -1, - FALSE: +1, - FREE: +1, - FREECELL: +1, - GE: -1, - GLOBAL: +1, - GT: -1, - GTGT: -1, - IN: -1, - INDEX: -1, - INPLACE_ADD: -1, - INPLACE_PIPE: -1, - ITERJMP: variableStackEffect, - ITERPOP: 0, - ITERPUSH: -1, - JMP: 0, - LE: -1, - LOAD: -1, - LOCAL: +1, - LOCALCELL: +1, - LT: -1, - LTLT: -1, - MAKEDICT: +1, - MAKEFUNC: 0, - MAKELIST: variableStackEffect, - MAKETUPLE: variableStackEffect, - MANDATORY: +1, - MINUS: -1, - NEQ: -1, - NONE: +1, - NOP: 0, - NOT: 0, - PERCENT: -1, - PIPE: -1, - PLUS: -1, - POP: -1, - PREDECLARED: +1, - RETURN: -1, - SETLOCALCELL: -1, - SETDICT: -3, - SETDICTUNIQ: -3, - SETFIELD: -2, - SETGLOBAL: -1, - SETINDEX: -3, - SETLOCAL: -1, - SLASH: -1, - SLASHSLASH: -1, - SLICE: -3, - STAR: -1, - TRUE: +1, - UMINUS: 0, - UNIVERSAL: +1, - UNPACK: variableStackEffect, - UPLUS: 0, -} - -func (op Opcode) String() string { - if op < OpcodeMax { - if name := opcodeNames[op]; name != "" { - return name - } - } - return fmt.Sprintf("illegal op (%d)", op) -} - -// A Program is a Starlark file in executable form. -// -// Programs are serialized by the Program.Encode method, -// which must be updated whenever this declaration is changed. -type Program struct { - Loads []Binding // name (really, string) and position of each load stmt - Names []string // names of attributes and predeclared variables - Constants []interface{} // = string | int64 | float64 | *big.Int | Bytes - Functions []*Funcode - Globals []Binding // for error messages and tracing - Toplevel *Funcode // module initialization function - Recursion bool // disable recursion check for functions in this file -} - -// The type of a bytes literal value, to distinguish from text string. -type Bytes string - -// A Funcode is the code of a compiled Starlark function. -// -// Funcodes are serialized by the encoder.function method, -// which must be updated whenever this declaration is changed. -type Funcode struct { - Prog *Program - Pos syntax.Position // position of def or lambda token - Name string // name of this function - Doc string // docstring of this function - Code []byte // the byte code - pclinetab []uint16 // mapping from pc to linenum - Locals []Binding // locals, parameters first - Cells []int // indices of Locals that require cells - Freevars []Binding // for tracing - MaxStack int - NumParams int - NumKwonlyParams int - HasVarargs, HasKwargs bool - - // -- transient state -- - - lntOnce sync.Once - lnt []pclinecol // decoded line number table -} - -type pclinecol struct { - pc uint32 - line, col int32 -} - -// A Binding is the name and position of a binding identifier. -type Binding struct { - Name string - Pos syntax.Position -} - -// A pcomp holds the compiler state for a Program. -type pcomp struct { - prog *Program // what we're building - - names map[string]uint32 - constants map[interface{}]uint32 - functions map[*Funcode]uint32 -} - -// An fcomp holds the compiler state for a Funcode. -type fcomp struct { - fn *Funcode // what we're building - - pcomp *pcomp - pos syntax.Position // current position of generated code - loops []loop - block *block -} - -type loop struct { - break_, continue_ *block -} - -type block struct { - insns []insn - - // If the last insn is a RETURN, jmp and cjmp are nil. - // If the last insn is a CJMP or ITERJMP, - // cjmp and jmp are the "true" and "false" successors. - // Otherwise, jmp is the sole successor. - jmp, cjmp *block - - initialstack int // for stack depth computation - - // Used during encoding - index int // -1 => not encoded yet - addr uint32 -} - -type insn struct { - op Opcode - arg uint32 - line, col int32 -} - -// Position returns the source position for program counter pc. -func (fn *Funcode) Position(pc uint32) syntax.Position { - fn.lntOnce.Do(fn.decodeLNT) - - // Binary search to find last LNT entry not greater than pc. - // To avoid dynamic dispatch, this is a specialization of - // sort.Search using this predicate: - // !(i < len(fn.lnt)-1 && fn.lnt[i+1].pc <= pc) - n := len(fn.lnt) - i, j := 0, n - for i < j { - h := int(uint(i+j) >> 1) - if !(h >= n-1 || fn.lnt[h+1].pc > pc) { - i = h + 1 - } else { - j = h - } - } - - var line, col int32 - if i < n { - line = fn.lnt[i].line - col = fn.lnt[i].col - } - - pos := fn.Pos // copy the (annoyingly inaccessible) filename - pos.Col = col - pos.Line = line - return pos -} - -// decodeLNT decodes the line number table and populates fn.lnt. -// It is called at most once. -func (fn *Funcode) decodeLNT() { - // Conceptually the table contains rows of the form - // (pc uint32, line int32, col int32), sorted by pc. - // We use a delta encoding, since the differences - // between successive pc, line, and column values - // are typically small and positive (though line and - // especially column differences may be negative). - // The delta encoding starts from - // {pc: 0, line: fn.Pos.Line, col: fn.Pos.Col}. - // - // Each entry is packed into one or more 16-bit values: - // Δpc uint4 - // Δline int5 - // Δcol int6 - // incomplete uint1 - // The top 4 bits are the unsigned delta pc. - // The next 5 bits are the signed line number delta. - // The next 6 bits are the signed column number delta. - // The bottom bit indicates that more rows follow because - // one of the deltas was maxed out. - // These field widths were chosen from a sample of real programs, - // and allow >97% of rows to be encoded in a single uint16. - - fn.lnt = make([]pclinecol, 0, len(fn.pclinetab)) // a minor overapproximation - entry := pclinecol{ - pc: 0, - line: fn.Pos.Line, - col: fn.Pos.Col, - } - for _, x := range fn.pclinetab { - entry.pc += uint32(x) >> 12 - entry.line += int32((int16(x) << 4) >> (16 - 5)) // sign extend Δline - entry.col += int32((int16(x) << 9) >> (16 - 6)) // sign extend Δcol - if (x & 1) == 0 { - fn.lnt = append(fn.lnt, entry) - } - } -} - -// bindings converts resolve.Bindings to compiled form. -func bindings(bindings []*resolve.Binding) []Binding { - res := make([]Binding, len(bindings)) - for i, bind := range bindings { - res[i].Name = bind.First.Name - res[i].Pos = bind.First.NamePos - } - return res -} - -// Expr compiles an expression to a program whose toplevel function evaluates it. -// The options must be consistent with those used when parsing expr. -func Expr(opts *syntax.FileOptions, expr syntax.Expr, name string, locals []*resolve.Binding) *Program { - pos := syntax.Start(expr) - stmts := []syntax.Stmt{&syntax.ReturnStmt{Result: expr}} - return File(opts, stmts, pos, name, locals, nil) -} - -// File compiles the statements of a file into a program. -// The options must be consistent with those used when parsing stmts. -func File(opts *syntax.FileOptions, stmts []syntax.Stmt, pos syntax.Position, name string, locals, globals []*resolve.Binding) *Program { - pcomp := &pcomp{ - prog: &Program{ - Globals: bindings(globals), - Recursion: opts.Recursion, - }, - names: make(map[string]uint32), - constants: make(map[interface{}]uint32), - functions: make(map[*Funcode]uint32), - } - pcomp.prog.Toplevel = pcomp.function(name, pos, stmts, locals, nil) - - return pcomp.prog -} - -func (pcomp *pcomp) function(name string, pos syntax.Position, stmts []syntax.Stmt, locals, freevars []*resolve.Binding) *Funcode { - fcomp := &fcomp{ - pcomp: pcomp, - pos: pos, - fn: &Funcode{ - Prog: pcomp.prog, - Pos: pos, - Name: name, - Doc: docStringFromBody(stmts), - Locals: bindings(locals), - Freevars: bindings(freevars), - }, - } - - // Record indices of locals that require cells. - for i, local := range locals { - if local.Scope == resolve.Cell { - fcomp.fn.Cells = append(fcomp.fn.Cells, i) - } - } - - if debug { - fmt.Fprintf(os.Stderr, "start function(%s @ %s)\n", name, pos) - } - - // Convert AST to a CFG of instructions. - entry := fcomp.newBlock() - fcomp.block = entry - fcomp.stmts(stmts) - if fcomp.block != nil { - fcomp.emit(NONE) - fcomp.emit(RETURN) - } - - var oops bool // something bad happened - - setinitialstack := func(b *block, depth int) { - if b.initialstack == -1 { - b.initialstack = depth - } else if b.initialstack != depth { - fmt.Fprintf(os.Stderr, "%d: setinitialstack: depth mismatch: %d vs %d\n", - b.index, b.initialstack, depth) - oops = true - } - } - - // Linearize the CFG: - // compute order, address, and initial - // stack depth of each reachable block. - var pc uint32 - var blocks []*block - var maxstack int - var visit func(b *block) - visit = func(b *block) { - if b.index >= 0 { - return // already visited - } - b.index = len(blocks) - b.addr = pc - blocks = append(blocks, b) - - stack := b.initialstack - if debug { - fmt.Fprintf(os.Stderr, "%s block %d: (stack = %d)\n", name, b.index, stack) - } - var cjmpAddr *uint32 - var isiterjmp int - for i, insn := range b.insns { - pc++ - - // Compute size of argument. - if insn.op >= OpcodeArgMin { - switch insn.op { - case ITERJMP: - isiterjmp = 1 - fallthrough - case CJMP: - cjmpAddr = &b.insns[i].arg - pc += 4 - default: - pc += uint32(argLen(insn.arg)) - } - } - - // Compute effect on stack. - se := insn.stackeffect() - if debug { - fmt.Fprintln(os.Stderr, "\t", insn.op, stack, stack+se) - } - stack += se - if stack < 0 { - fmt.Fprintf(os.Stderr, "After pc=%d: stack underflow\n", pc) - oops = true - } - if stack+isiterjmp > maxstack { - maxstack = stack + isiterjmp - } - } - - if debug { - fmt.Fprintf(os.Stderr, "successors of block %d (start=%d):\n", - b.addr, b.index) - if b.jmp != nil { - fmt.Fprintf(os.Stderr, "jmp to %d\n", b.jmp.index) - } - if b.cjmp != nil { - fmt.Fprintf(os.Stderr, "cjmp to %d\n", b.cjmp.index) - } - } - - // Place the jmp block next. - if b.jmp != nil { - // jump threading (empty cycles are impossible) - for b.jmp.insns == nil { - b.jmp = b.jmp.jmp - } - - setinitialstack(b.jmp, stack+isiterjmp) - if b.jmp.index < 0 { - // Successor is not yet visited: - // place it next and fall through. - visit(b.jmp) - } else { - // Successor already visited; - // explicit backward jump required. - pc += 5 - } - } - - // Then the cjmp block. - if b.cjmp != nil { - // jump threading (empty cycles are impossible) - for b.cjmp.insns == nil { - b.cjmp = b.cjmp.jmp - } - - setinitialstack(b.cjmp, stack) - visit(b.cjmp) - - // Patch the CJMP/ITERJMP, if present. - if cjmpAddr != nil { - *cjmpAddr = b.cjmp.addr - } - } - } - setinitialstack(entry, 0) - visit(entry) - - fn := fcomp.fn - fn.MaxStack = maxstack - - // Emit bytecode (and position table). - if Disassemble { - fmt.Fprintf(os.Stderr, "Function %s: (%d blocks, %d bytes)\n", name, len(blocks), pc) - } - fcomp.generate(blocks, pc) - - if debug { - fmt.Fprintf(os.Stderr, "code=%d maxstack=%d\n", fn.Code, fn.MaxStack) - } - - // Don't panic until we've completed printing of the function. - if oops { - panic("internal error") - } - - if debug { - fmt.Fprintf(os.Stderr, "end function(%s @ %s)\n", name, pos) - } - - return fn -} - -func docStringFromBody(body []syntax.Stmt) string { - if len(body) == 0 { - return "" - } - expr, ok := body[0].(*syntax.ExprStmt) - if !ok { - return "" - } - lit, ok := expr.X.(*syntax.Literal) - if !ok { - return "" - } - if lit.Token != syntax.STRING { - return "" - } - return lit.Value.(string) -} - -func (insn *insn) stackeffect() int { - se := int(stackEffect[insn.op]) - if se == variableStackEffect { - arg := int(insn.arg) - switch insn.op { - case CALL, CALL_KW, CALL_VAR, CALL_VAR_KW: - se = -int(2*(insn.arg&0xff) + insn.arg>>8) - if insn.op != CALL { - se-- - } - if insn.op == CALL_VAR_KW { - se-- - } - case ITERJMP: - // Stack effect differs by successor: - // +1 for jmp/false/ok - // 0 for cjmp/true/exhausted - // Handled specially in caller. - se = 0 - case MAKELIST, MAKETUPLE: - se = 1 - arg - case UNPACK: - se = arg - 1 - default: - panic(insn.op) - } - } - return se -} - -// generate emits the linear instruction stream from the CFG, -// and builds the PC-to-line number table. -func (fcomp *fcomp) generate(blocks []*block, codelen uint32) { - code := make([]byte, 0, codelen) - var pclinetab []uint16 - prev := pclinecol{ - pc: 0, - line: fcomp.fn.Pos.Line, - col: fcomp.fn.Pos.Col, - } - - for _, b := range blocks { - if Disassemble { - fmt.Fprintf(os.Stderr, "%d:\n", b.index) - } - pc := b.addr - for _, insn := range b.insns { - if insn.line != 0 { - // Instruction has a source position. Delta-encode it. - // See Funcode.Position for the encoding. - for { - var incomplete uint16 - - // Δpc, uint4 - deltapc := pc - prev.pc - if deltapc > 0x0f { - deltapc = 0x0f - incomplete = 1 - } - prev.pc += deltapc - - // Δline, int5 - deltaline, ok := clip(insn.line-prev.line, -0x10, 0x0f) - if !ok { - incomplete = 1 - } - prev.line += deltaline - - // Δcol, int6 - deltacol, ok := clip(insn.col-prev.col, -0x20, 0x1f) - if !ok { - incomplete = 1 - } - prev.col += deltacol - - entry := uint16(deltapc<<12) | uint16(deltaline&0x1f)<<7 | uint16(deltacol&0x3f)<<1 | incomplete - pclinetab = append(pclinetab, entry) - if incomplete == 0 { - break - } - } - - if Disassemble { - fmt.Fprintf(os.Stderr, "\t\t\t\t\t; %s:%d:%d\n", - filepath.Base(fcomp.fn.Pos.Filename()), insn.line, insn.col) - } - } - if Disassemble { - PrintOp(fcomp.fn, pc, insn.op, insn.arg) - } - code = append(code, byte(insn.op)) - pc++ - if insn.op >= OpcodeArgMin { - if insn.op == CJMP || insn.op == ITERJMP { - code = addUint32(code, insn.arg, 4) // pad arg to 4 bytes - } else { - code = addUint32(code, insn.arg, 0) - } - pc = uint32(len(code)) - } - } - - if b.jmp != nil && b.jmp.index != b.index+1 { - addr := b.jmp.addr - if Disassemble { - fmt.Fprintf(os.Stderr, "\t%d\tjmp\t\t%d\t; block %d\n", - pc, addr, b.jmp.index) - } - code = append(code, byte(JMP)) - code = addUint32(code, addr, 4) - } - } - if len(code) != int(codelen) { - panic("internal error: wrong code length") - } - - fcomp.fn.pclinetab = pclinetab - fcomp.fn.Code = code -} - -// clip returns the value nearest x in the range [min...max], -// and whether it equals x. -func clip(x, min, max int32) (int32, bool) { - if x > max { - return max, false - } else if x < min { - return min, false - } else { - return x, true - } -} - -// addUint32 encodes x as 7-bit little-endian varint. -// TODO(adonovan): opt: steal top two bits of opcode -// to encode the number of complete bytes that follow. -func addUint32(code []byte, x uint32, min int) []byte { - end := len(code) + min - for x >= 0x80 { - code = append(code, byte(x)|0x80) - x >>= 7 - } - code = append(code, byte(x)) - // Pad the operand with NOPs to exactly min bytes. - for len(code) < end { - code = append(code, byte(NOP)) - } - return code -} - -func argLen(x uint32) int { - n := 0 - for x >= 0x80 { - n++ - x >>= 7 - } - return n + 1 -} - -// PrintOp prints an instruction. -// It is provided for debugging. -func PrintOp(fn *Funcode, pc uint32, op Opcode, arg uint32) { - if op < OpcodeArgMin { - fmt.Fprintf(os.Stderr, "\t%d\t%s\n", pc, op) - return - } - - var comment string - switch op { - case CONSTANT: - switch x := fn.Prog.Constants[arg].(type) { - case string: - comment = strconv.Quote(x) - case Bytes: - comment = "b" + strconv.Quote(string(x)) - default: - comment = fmt.Sprint(x) - } - case MAKEFUNC: - comment = fn.Prog.Functions[arg].Name - case SETLOCAL, LOCAL: - comment = fn.Locals[arg].Name - case SETGLOBAL, GLOBAL: - comment = fn.Prog.Globals[arg].Name - case ATTR, SETFIELD, PREDECLARED, UNIVERSAL: - comment = fn.Prog.Names[arg] - case FREE: - comment = fn.Freevars[arg].Name - case CALL, CALL_VAR, CALL_KW, CALL_VAR_KW: - comment = fmt.Sprintf("%d pos, %d named", arg>>8, arg&0xff) - default: - // JMP, CJMP, ITERJMP, MAKETUPLE, MAKELIST, LOAD, UNPACK: - // arg is just a number - } - var buf bytes.Buffer - fmt.Fprintf(&buf, "\t%d\t%-10s\t%d", pc, op, arg) - if comment != "" { - fmt.Fprint(&buf, "\t; ", comment) - } - fmt.Fprintln(&buf) - os.Stderr.Write(buf.Bytes()) -} - -// newBlock returns a new block. -func (fcomp) newBlock() *block { - return &block{index: -1, initialstack: -1} -} - -// emit emits an instruction to the current block. -func (fcomp *fcomp) emit(op Opcode) { - if op >= OpcodeArgMin { - panic("missing arg: " + op.String()) - } - insn := insn{op: op, line: fcomp.pos.Line, col: fcomp.pos.Col} - fcomp.block.insns = append(fcomp.block.insns, insn) - fcomp.pos.Line = 0 - fcomp.pos.Col = 0 -} - -// emit1 emits an instruction with an immediate operand. -func (fcomp *fcomp) emit1(op Opcode, arg uint32) { - if op < OpcodeArgMin { - panic("unwanted arg: " + op.String()) - } - insn := insn{op: op, arg: arg, line: fcomp.pos.Line, col: fcomp.pos.Col} - fcomp.block.insns = append(fcomp.block.insns, insn) - fcomp.pos.Line = 0 - fcomp.pos.Col = 0 -} - -// jump emits a jump to the specified block. -// On return, the current block is unset. -func (fcomp *fcomp) jump(b *block) { - if b == fcomp.block { - panic("self-jump") // unreachable: Starlark has no arbitrary looping constructs - } - fcomp.block.jmp = b - fcomp.block = nil -} - -// condjump emits a conditional jump (CJMP or ITERJMP) -// to the specified true/false blocks. -// (For ITERJMP, the cases are jmp/f/ok and cjmp/t/exhausted.) -// On return, the current block is unset. -func (fcomp *fcomp) condjump(op Opcode, t, f *block) { - if !(op == CJMP || op == ITERJMP) { - panic("not a conditional jump: " + op.String()) - } - fcomp.emit1(op, 0) // fill in address later - fcomp.block.cjmp = t - fcomp.jump(f) -} - -// nameIndex returns the index of the specified name -// within the name pool, adding it if necessary. -func (pcomp *pcomp) nameIndex(name string) uint32 { - index, ok := pcomp.names[name] - if !ok { - index = uint32(len(pcomp.prog.Names)) - pcomp.names[name] = index - pcomp.prog.Names = append(pcomp.prog.Names, name) - } - return index -} - -// constantIndex returns the index of the specified constant -// within the constant pool, adding it if necessary. -func (pcomp *pcomp) constantIndex(v interface{}) uint32 { - index, ok := pcomp.constants[v] - if !ok { - index = uint32(len(pcomp.prog.Constants)) - pcomp.constants[v] = index - pcomp.prog.Constants = append(pcomp.prog.Constants, v) - } - return index -} - -// functionIndex returns the index of the specified function -// AST the nestedfun pool, adding it if necessary. -func (pcomp *pcomp) functionIndex(fn *Funcode) uint32 { - index, ok := pcomp.functions[fn] - if !ok { - index = uint32(len(pcomp.prog.Functions)) - pcomp.functions[fn] = index - pcomp.prog.Functions = append(pcomp.prog.Functions, fn) - } - return index -} - -// string emits code to push the specified string. -func (fcomp *fcomp) string(s string) { - fcomp.emit1(CONSTANT, fcomp.pcomp.constantIndex(s)) -} - -// setPos sets the current source position. -// It should be called prior to any operation that can fail dynamically. -// All positions are assumed to belong to the same file. -func (fcomp *fcomp) setPos(pos syntax.Position) { - fcomp.pos = pos -} - -// set emits code to store the top-of-stack value -// to the specified local, cell, or global variable. -func (fcomp *fcomp) set(id *syntax.Ident) { - bind := id.Binding.(*resolve.Binding) - switch bind.Scope { - case resolve.Local: - fcomp.emit1(SETLOCAL, uint32(bind.Index)) - case resolve.Cell: - fcomp.emit1(SETLOCALCELL, uint32(bind.Index)) - case resolve.Global: - fcomp.emit1(SETGLOBAL, uint32(bind.Index)) - default: - log.Panicf("%s: set(%s): not global/local/cell (%d)", id.NamePos, id.Name, bind.Scope) - } -} - -// lookup emits code to push the value of the specified variable. -func (fcomp *fcomp) lookup(id *syntax.Ident) { - bind := id.Binding.(*resolve.Binding) - if bind.Scope != resolve.Universal { // (universal lookup can't fail) - fcomp.setPos(id.NamePos) - } - switch bind.Scope { - case resolve.Local: - fcomp.emit1(LOCAL, uint32(bind.Index)) - case resolve.Free: - fcomp.emit1(FREECELL, uint32(bind.Index)) - case resolve.Cell: - fcomp.emit1(LOCALCELL, uint32(bind.Index)) - case resolve.Global: - fcomp.emit1(GLOBAL, uint32(bind.Index)) - case resolve.Predeclared: - fcomp.emit1(PREDECLARED, fcomp.pcomp.nameIndex(id.Name)) - case resolve.Universal: - fcomp.emit1(UNIVERSAL, fcomp.pcomp.nameIndex(id.Name)) - default: - log.Panicf("%s: compiler.lookup(%s): scope = %d", id.NamePos, id.Name, bind.Scope) - } -} - -func (fcomp *fcomp) stmts(stmts []syntax.Stmt) { - for _, stmt := range stmts { - fcomp.stmt(stmt) - } -} - -func (fcomp *fcomp) stmt(stmt syntax.Stmt) { - switch stmt := stmt.(type) { - case *syntax.ExprStmt: - if _, ok := stmt.X.(*syntax.Literal); ok { - // Opt: don't compile doc comments only to pop them. - return - } - fcomp.expr(stmt.X) - fcomp.emit(POP) - - case *syntax.BranchStmt: - // Resolver invariant: break/continue appear only within loops. - switch stmt.Token { - case syntax.PASS: - // no-op - case syntax.BREAK: - b := fcomp.loops[len(fcomp.loops)-1].break_ - fcomp.jump(b) - fcomp.block = fcomp.newBlock() // dead code - case syntax.CONTINUE: - b := fcomp.loops[len(fcomp.loops)-1].continue_ - fcomp.jump(b) - fcomp.block = fcomp.newBlock() // dead code - } - - case *syntax.IfStmt: - // Keep consistent with CondExpr. - t := fcomp.newBlock() - f := fcomp.newBlock() - done := fcomp.newBlock() - - fcomp.ifelse(stmt.Cond, t, f) - - fcomp.block = t - fcomp.stmts(stmt.True) - fcomp.jump(done) - - fcomp.block = f - fcomp.stmts(stmt.False) - fcomp.jump(done) - - fcomp.block = done - - case *syntax.AssignStmt: - switch stmt.Op { - case syntax.EQ: - // simple assignment: x = y - fcomp.expr(stmt.RHS) - fcomp.assign(stmt.OpPos, stmt.LHS) - - case syntax.PLUS_EQ, - syntax.MINUS_EQ, - syntax.STAR_EQ, - syntax.SLASH_EQ, - syntax.SLASHSLASH_EQ, - syntax.PERCENT_EQ, - syntax.AMP_EQ, - syntax.PIPE_EQ, - syntax.CIRCUMFLEX_EQ, - syntax.LTLT_EQ, - syntax.GTGT_EQ: - // augmented assignment: x += y - - var set func() - - // Evaluate "address" of x exactly once to avoid duplicate side-effects. - switch lhs := unparen(stmt.LHS).(type) { - case *syntax.Ident: - // x = ... - fcomp.lookup(lhs) - set = func() { - fcomp.set(lhs) - } - - case *syntax.IndexExpr: - // x[y] = ... - fcomp.expr(lhs.X) - fcomp.expr(lhs.Y) - fcomp.emit(DUP2) - fcomp.setPos(lhs.Lbrack) - fcomp.emit(INDEX) - set = func() { - fcomp.setPos(lhs.Lbrack) - fcomp.emit(SETINDEX) - } - - case *syntax.DotExpr: - // x.f = ... - fcomp.expr(lhs.X) - fcomp.emit(DUP) - name := fcomp.pcomp.nameIndex(lhs.Name.Name) - fcomp.setPos(lhs.Dot) - fcomp.emit1(ATTR, name) - set = func() { - fcomp.setPos(lhs.Dot) - fcomp.emit1(SETFIELD, name) - } - - default: - panic(lhs) - } - - fcomp.expr(stmt.RHS) - - // In-place x+=y and x|=y have special semantics: - // the resulting x aliases the original x. - switch stmt.Op { - case syntax.PLUS_EQ: - fcomp.setPos(stmt.OpPos) - fcomp.emit(INPLACE_ADD) - case syntax.PIPE_EQ: - fcomp.setPos(stmt.OpPos) - fcomp.emit(INPLACE_PIPE) - default: - fcomp.binop(stmt.OpPos, stmt.Op-syntax.PLUS_EQ+syntax.PLUS) - } - set() - } - - case *syntax.DefStmt: - fcomp.function(stmt.Function.(*resolve.Function)) - fcomp.set(stmt.Name) - - case *syntax.ForStmt: - // Keep consistent with ForClause. - head := fcomp.newBlock() - body := fcomp.newBlock() - tail := fcomp.newBlock() - - fcomp.expr(stmt.X) - fcomp.setPos(stmt.For) - fcomp.emit(ITERPUSH) - fcomp.jump(head) - - fcomp.block = head - fcomp.condjump(ITERJMP, tail, body) - - fcomp.block = body - fcomp.assign(stmt.For, stmt.Vars) - fcomp.loops = append(fcomp.loops, loop{break_: tail, continue_: head}) - fcomp.stmts(stmt.Body) - fcomp.loops = fcomp.loops[:len(fcomp.loops)-1] - fcomp.jump(head) - - fcomp.block = tail - fcomp.emit(ITERPOP) - - case *syntax.WhileStmt: - head := fcomp.newBlock() - body := fcomp.newBlock() - done := fcomp.newBlock() - - fcomp.jump(head) - fcomp.block = head - fcomp.ifelse(stmt.Cond, body, done) - - fcomp.block = body - fcomp.loops = append(fcomp.loops, loop{break_: done, continue_: head}) - fcomp.stmts(stmt.Body) - fcomp.loops = fcomp.loops[:len(fcomp.loops)-1] - fcomp.jump(head) - - fcomp.block = done - - case *syntax.ReturnStmt: - if stmt.Result != nil { - fcomp.expr(stmt.Result) - } else { - fcomp.emit(NONE) - } - fcomp.emit(RETURN) - fcomp.block = fcomp.newBlock() // dead code - - case *syntax.LoadStmt: - for i := range stmt.From { - fcomp.string(stmt.From[i].Name) - } - module := stmt.Module.Value.(string) - fcomp.pcomp.prog.Loads = append(fcomp.pcomp.prog.Loads, Binding{ - Name: module, - Pos: stmt.Module.TokenPos, - }) - fcomp.string(module) - fcomp.setPos(stmt.Load) - fcomp.emit1(LOAD, uint32(len(stmt.From))) - for i := range stmt.To { - fcomp.set(stmt.To[len(stmt.To)-1-i]) - } - - default: - start, _ := stmt.Span() - log.Panicf("%s: exec: unexpected statement %T", start, stmt) - } -} - -// assign implements lhs = rhs for arbitrary expressions lhs. -// RHS is on top of stack, consumed. -func (fcomp *fcomp) assign(pos syntax.Position, lhs syntax.Expr) { - switch lhs := lhs.(type) { - case *syntax.ParenExpr: - // (lhs) = rhs - fcomp.assign(pos, lhs.X) - - case *syntax.Ident: - // x = rhs - fcomp.set(lhs) - - case *syntax.TupleExpr: - // x, y = rhs - fcomp.assignSequence(pos, lhs.List) - - case *syntax.ListExpr: - // [x, y] = rhs - fcomp.assignSequence(pos, lhs.List) - - case *syntax.IndexExpr: - // x[y] = rhs - fcomp.expr(lhs.X) - fcomp.emit(EXCH) - fcomp.expr(lhs.Y) - fcomp.emit(EXCH) - fcomp.setPos(lhs.Lbrack) - fcomp.emit(SETINDEX) - - case *syntax.DotExpr: - // x.f = rhs - fcomp.expr(lhs.X) - fcomp.emit(EXCH) - fcomp.setPos(lhs.Dot) - fcomp.emit1(SETFIELD, fcomp.pcomp.nameIndex(lhs.Name.Name)) - - default: - panic(lhs) - } -} - -func (fcomp *fcomp) assignSequence(pos syntax.Position, lhs []syntax.Expr) { - fcomp.setPos(pos) - fcomp.emit1(UNPACK, uint32(len(lhs))) - for i := range lhs { - fcomp.assign(pos, lhs[i]) - } -} - -func (fcomp *fcomp) expr(e syntax.Expr) { - switch e := e.(type) { - case *syntax.ParenExpr: - fcomp.expr(e.X) - - case *syntax.Ident: - fcomp.lookup(e) - - case *syntax.Literal: - // e.Value is int64, float64, *bigInt, string - v := e.Value - if e.Token == syntax.BYTES { - v = Bytes(v.(string)) - } - fcomp.emit1(CONSTANT, fcomp.pcomp.constantIndex(v)) - - case *syntax.ListExpr: - for _, x := range e.List { - fcomp.expr(x) - } - fcomp.emit1(MAKELIST, uint32(len(e.List))) - - case *syntax.CondExpr: - // Keep consistent with IfStmt. - t := fcomp.newBlock() - f := fcomp.newBlock() - done := fcomp.newBlock() - - fcomp.ifelse(e.Cond, t, f) - - fcomp.block = t - fcomp.expr(e.True) - fcomp.jump(done) - - fcomp.block = f - fcomp.expr(e.False) - fcomp.jump(done) - - fcomp.block = done - - case *syntax.IndexExpr: - fcomp.expr(e.X) - fcomp.expr(e.Y) - fcomp.setPos(e.Lbrack) - fcomp.emit(INDEX) - - case *syntax.SliceExpr: - fcomp.setPos(e.Lbrack) - fcomp.expr(e.X) - if e.Lo != nil { - fcomp.expr(e.Lo) - } else { - fcomp.emit(NONE) - } - if e.Hi != nil { - fcomp.expr(e.Hi) - } else { - fcomp.emit(NONE) - } - if e.Step != nil { - fcomp.expr(e.Step) - } else { - fcomp.emit(NONE) - } - fcomp.emit(SLICE) - - case *syntax.Comprehension: - if e.Curly { - fcomp.emit(MAKEDICT) - } else { - fcomp.emit1(MAKELIST, 0) - } - fcomp.comprehension(e, 0) - - case *syntax.TupleExpr: - fcomp.tuple(e.List) - - case *syntax.DictExpr: - fcomp.emit(MAKEDICT) - for _, entry := range e.List { - entry := entry.(*syntax.DictEntry) - fcomp.emit(DUP) - fcomp.expr(entry.Key) - fcomp.expr(entry.Value) - fcomp.setPos(entry.Colon) - fcomp.emit(SETDICTUNIQ) - } - - case *syntax.UnaryExpr: - fcomp.expr(e.X) - fcomp.setPos(e.OpPos) - switch e.Op { - case syntax.MINUS: - fcomp.emit(UMINUS) - case syntax.PLUS: - fcomp.emit(UPLUS) - case syntax.NOT: - fcomp.emit(NOT) - case syntax.TILDE: - fcomp.emit(TILDE) - default: - log.Panicf("%s: unexpected unary op: %s", e.OpPos, e.Op) - } - - case *syntax.BinaryExpr: - switch e.Op { - // short-circuit operators - // TODO(adonovan): use ifelse to simplify conditions. - case syntax.OR: - // x or y => if x then x else y - done := fcomp.newBlock() - y := fcomp.newBlock() - - fcomp.expr(e.X) - fcomp.emit(DUP) - fcomp.condjump(CJMP, done, y) - - fcomp.block = y - fcomp.emit(POP) // discard X - fcomp.expr(e.Y) - fcomp.jump(done) - - fcomp.block = done - - case syntax.AND: - // x and y => if x then y else x - done := fcomp.newBlock() - y := fcomp.newBlock() - - fcomp.expr(e.X) - fcomp.emit(DUP) - fcomp.condjump(CJMP, y, done) - - fcomp.block = y - fcomp.emit(POP) // discard X - fcomp.expr(e.Y) - fcomp.jump(done) - - fcomp.block = done - - case syntax.PLUS: - fcomp.plus(e) - - default: - // all other strict binary operator (includes comparisons) - fcomp.expr(e.X) - fcomp.expr(e.Y) - fcomp.binop(e.OpPos, e.Op) - } - - case *syntax.DotExpr: - fcomp.expr(e.X) - fcomp.setPos(e.Dot) - fcomp.emit1(ATTR, fcomp.pcomp.nameIndex(e.Name.Name)) - - case *syntax.CallExpr: - fcomp.call(e) - - case *syntax.LambdaExpr: - fcomp.function(e.Function.(*resolve.Function)) - - default: - start, _ := e.Span() - log.Panicf("%s: unexpected expr %T", start, e) - } -} - -type summand struct { - x syntax.Expr - plusPos syntax.Position -} - -// plus emits optimized code for ((a+b)+...)+z that avoids naive -// quadratic behavior for strings, tuples, and lists, -// and folds together adjacent literals of the same type. -func (fcomp *fcomp) plus(e *syntax.BinaryExpr) { - // Gather all the right operands of the left tree of plusses. - // A tree (((a+b)+c)+d) becomes args=[a +b +c +d]. - args := make([]summand, 0, 2) // common case: 2 operands - for plus := e; ; { - args = append(args, summand{unparen(plus.Y), plus.OpPos}) - left := unparen(plus.X) - x, ok := left.(*syntax.BinaryExpr) - if !ok || x.Op != syntax.PLUS { - args = append(args, summand{x: left}) - break - } - plus = x - } - // Reverse args to syntactic order. - for i, n := 0, len(args)/2; i < n; i++ { - j := len(args) - 1 - i - args[i], args[j] = args[j], args[i] - } - - // Fold sums of adjacent literals of the same type: ""+"", []+[], ()+(). - out := args[:0] // compact in situ - for i := 0; i < len(args); { - j := i + 1 - if code := addable(args[i].x); code != 0 { - for j < len(args) && addable(args[j].x) == code { - j++ - } - if j > i+1 { - args[i].x = add(code, args[i:j]) - } - } - out = append(out, args[i]) - i = j - } - args = out - - // Emit code for an n-ary sum (n > 0). - fcomp.expr(args[0].x) - for _, summand := range args[1:] { - fcomp.expr(summand.x) - fcomp.setPos(summand.plusPos) - fcomp.emit(PLUS) - } - - // If len(args) > 2, use of an accumulator instead of a chain of - // PLUS operations may be more efficient. - // However, no gain was measured on a workload analogous to Bazel loading; - // TODO(adonovan): opt: re-evaluate on a Bazel analysis-like workload. - // - // We cannot use a single n-ary SUM operation - // a b c SUM<3> - // because we need to report a distinct error for each - // individual '+' operation, so three additional operations are - // needed: - // - // ACCSTART => create buffer and append to it - // ACCUM => append to buffer - // ACCEND => get contents of buffer - // - // For string, list, and tuple values, the interpreter can - // optimize these operations by using a mutable buffer. - // For all other types, ACCSTART and ACCEND would behave like - // the identity function and ACCUM behaves like PLUS. - // ACCUM must correctly support user-defined operations - // such as list+foo. - // - // fcomp.emit(ACCSTART) - // for _, summand := range args[1:] { - // fcomp.expr(summand.x) - // fcomp.setPos(summand.plusPos) - // fcomp.emit(ACCUM) - // } - // fcomp.emit(ACCEND) -} - -// addable reports whether e is a statically addable -// expression: a [s]tring, [b]ytes, [l]ist, or [t]uple. -func addable(e syntax.Expr) rune { - switch e := e.(type) { - case *syntax.Literal: - // TODO(adonovan): opt: support INT/FLOAT/BIGINT constant folding. - switch e.Token { - case syntax.STRING: - return 's' - case syntax.BYTES: - return 'b' - } - case *syntax.ListExpr: - return 'l' - case *syntax.TupleExpr: - return 't' - } - return 0 -} - -// add returns an expression denoting the sum of args, -// which are all addable values of the type indicated by code. -// The resulting syntax is degenerate, lacking position, etc. -func add(code rune, args []summand) syntax.Expr { - switch code { - case 's', 'b': - var buf strings.Builder - for _, arg := range args { - buf.WriteString(arg.x.(*syntax.Literal).Value.(string)) - } - tok := syntax.STRING - if code == 'b' { - tok = syntax.BYTES - } - return &syntax.Literal{Token: tok, Value: buf.String()} - case 'l': - var elems []syntax.Expr - for _, arg := range args { - elems = append(elems, arg.x.(*syntax.ListExpr).List...) - } - return &syntax.ListExpr{List: elems} - case 't': - var elems []syntax.Expr - for _, arg := range args { - elems = append(elems, arg.x.(*syntax.TupleExpr).List...) - } - return &syntax.TupleExpr{List: elems} - } - panic(code) -} - -func unparen(e syntax.Expr) syntax.Expr { - if p, ok := e.(*syntax.ParenExpr); ok { - return unparen(p.X) - } - return e -} - -func (fcomp *fcomp) binop(pos syntax.Position, op syntax.Token) { - // TODO(adonovan): simplify by assuming syntax and compiler constants align. - fcomp.setPos(pos) - switch op { - // arithmetic - case syntax.PLUS: - fcomp.emit(PLUS) - case syntax.MINUS: - fcomp.emit(MINUS) - case syntax.STAR: - fcomp.emit(STAR) - case syntax.SLASH: - fcomp.emit(SLASH) - case syntax.SLASHSLASH: - fcomp.emit(SLASHSLASH) - case syntax.PERCENT: - fcomp.emit(PERCENT) - case syntax.AMP: - fcomp.emit(AMP) - case syntax.PIPE: - fcomp.emit(PIPE) - case syntax.CIRCUMFLEX: - fcomp.emit(CIRCUMFLEX) - case syntax.LTLT: - fcomp.emit(LTLT) - case syntax.GTGT: - fcomp.emit(GTGT) - case syntax.IN: - fcomp.emit(IN) - case syntax.NOT_IN: - fcomp.emit(IN) - fcomp.emit(NOT) - - // comparisons - case syntax.EQL, - syntax.NEQ, - syntax.GT, - syntax.LT, - syntax.LE, - syntax.GE: - fcomp.emit(Opcode(op-syntax.EQL) + EQL) - - default: - log.Panicf("%s: unexpected binary op: %s", pos, op) - } -} - -func (fcomp *fcomp) call(call *syntax.CallExpr) { - // TODO(adonovan): opt: Use optimized path for calling methods - // of built-ins: x.f(...) to avoid materializing a closure. - // if dot, ok := call.Fcomp.(*syntax.DotExpr); ok { - // fcomp.expr(dot.X) - // fcomp.args(call) - // fcomp.emit1(CALL_ATTR, fcomp.name(dot.Name.Name)) - // return - // } - - // usual case - fcomp.expr(call.Fn) - op, arg := fcomp.args(call) - fcomp.setPos(call.Lparen) - fcomp.emit1(op, arg) -} - -// args emits code to push a tuple of positional arguments -// and a tuple of named arguments containing alternating keys and values. -// Either or both tuples may be empty (TODO(adonovan): optimize). -func (fcomp *fcomp) args(call *syntax.CallExpr) (op Opcode, arg uint32) { - var callmode int - // Compute the number of each kind of parameter. - var p, n int // number of positional, named arguments - var varargs, kwargs syntax.Expr - for _, arg := range call.Args { - if binary, ok := arg.(*syntax.BinaryExpr); ok && binary.Op == syntax.EQ { - - // named argument (name, value) - fcomp.string(binary.X.(*syntax.Ident).Name) - fcomp.expr(binary.Y) - n++ - continue - } - if unary, ok := arg.(*syntax.UnaryExpr); ok { - if unary.Op == syntax.STAR { - callmode |= 1 - varargs = unary.X - continue - } else if unary.Op == syntax.STARSTAR { - callmode |= 2 - kwargs = unary.X - continue - } - } - - // positional argument - fcomp.expr(arg) - p++ - } - - // Python2 and Python3 both permit named arguments - // to appear both before and after a *args argument: - // f(1, 2, x=3, *[4], y=5, **dict(z=6)) - // - // They also differ in their evaluation order: - // Python2: 1 2 3 5 4 6 (*args and **kwargs evaluated last) - // Python3: 1 2 4 3 5 6 (positional args evaluated before named args) - // Starlark-in-Java historically used a third order: - // Lexical: 1 2 3 4 5 6 (all args evaluated left-to-right) - // - // After discussion in github.com/bazelbuild/starlark#13, the - // spec now requires Starlark to statically reject named - // arguments after *args (e.g. y=5), and to use Python2-style - // evaluation order. This is both easy to implement and - // consistent with lexical order: - // - // f(1, 2, x=3, *[4], **dict(z=6)) # 1 2 3 4 6 - - // *args - if varargs != nil { - fcomp.expr(varargs) - } - - // **kwargs - if kwargs != nil { - fcomp.expr(kwargs) - } - - // TODO(adonovan): avoid this with a more flexible encoding. - if p >= 256 || n >= 256 { - // resolve already checked this; should be unreachable - panic("too many arguments in call") - } - - return CALL + Opcode(callmode), uint32(p<<8 | n) -} - -func (fcomp *fcomp) tuple(elems []syntax.Expr) { - for _, elem := range elems { - fcomp.expr(elem) - } - fcomp.emit1(MAKETUPLE, uint32(len(elems))) -} - -func (fcomp *fcomp) comprehension(comp *syntax.Comprehension, clauseIndex int) { - if clauseIndex == len(comp.Clauses) { - fcomp.emit(DUP) // accumulator - if comp.Curly { - // dict: {k:v for ...} - // Parser ensures that body is of form k:v. - // Python-style set comprehensions {body for vars in x} - // are not supported. - entry := comp.Body.(*syntax.DictEntry) - fcomp.expr(entry.Key) - fcomp.expr(entry.Value) - fcomp.setPos(entry.Colon) - fcomp.emit(SETDICT) - } else { - // list: [body for vars in x] - fcomp.expr(comp.Body) - fcomp.emit(APPEND) - } - return - } - - clause := comp.Clauses[clauseIndex] - switch clause := clause.(type) { - case *syntax.IfClause: - t := fcomp.newBlock() - done := fcomp.newBlock() - fcomp.ifelse(clause.Cond, t, done) - - fcomp.block = t - fcomp.comprehension(comp, clauseIndex+1) - fcomp.jump(done) - - fcomp.block = done - return - - case *syntax.ForClause: - // Keep consistent with ForStmt. - head := fcomp.newBlock() - body := fcomp.newBlock() - tail := fcomp.newBlock() - - fcomp.expr(clause.X) - fcomp.setPos(clause.For) - fcomp.emit(ITERPUSH) - fcomp.jump(head) - - fcomp.block = head - fcomp.condjump(ITERJMP, tail, body) - - fcomp.block = body - fcomp.assign(clause.For, clause.Vars) - fcomp.comprehension(comp, clauseIndex+1) - fcomp.jump(head) - - fcomp.block = tail - fcomp.emit(ITERPOP) - return - } - - start, _ := clause.Span() - log.Panicf("%s: unexpected comprehension clause %T", start, clause) -} - -func (fcomp *fcomp) function(f *resolve.Function) { - // Evaluation of the defaults may fail, so record the position. - fcomp.setPos(f.Pos) - - // To reduce allocation, we emit a combined tuple - // for the defaults and the freevars. - // The function knows where to split it at run time. - - // Generate tuple of parameter defaults. For: - // def f(p1, p2=dp2, p3=dp3, *, k1, k2=dk2, k3, **kwargs) - // the tuple is: - // (dp2, dp3, MANDATORY, dk2, MANDATORY). - ndefaults := 0 - seenStar := false - for _, param := range f.Params { - switch param := param.(type) { - case *syntax.BinaryExpr: - fcomp.expr(param.Y) - ndefaults++ - case *syntax.UnaryExpr: - seenStar = true // * or *args (also **kwargs) - case *syntax.Ident: - if seenStar { - fcomp.emit(MANDATORY) - ndefaults++ - } - } - } - - // Capture the cells of the function's - // free variables from the lexical environment. - for _, freevar := range f.FreeVars { - // Don't call fcomp.lookup because we want - // the cell itself, not its content. - switch freevar.Scope { - case resolve.Free: - fcomp.emit1(FREE, uint32(freevar.Index)) - case resolve.Cell: - fcomp.emit1(LOCAL, uint32(freevar.Index)) - } - } - - fcomp.emit1(MAKETUPLE, uint32(ndefaults+len(f.FreeVars))) - - funcode := fcomp.pcomp.function(f.Name, f.Pos, f.Body, f.Locals, f.FreeVars) - - if debug { - // TODO(adonovan): do compilations sequentially not as a tree, - // to make the log easier to read. - // Simplify by identifying Toplevel and functionIndex 0. - fmt.Fprintf(os.Stderr, "resuming %s @ %s\n", fcomp.fn.Name, fcomp.pos) - } - - // def f(a, *, b=1) has only 2 parameters. - numParams := len(f.Params) - if f.NumKwonlyParams > 0 && !f.HasVarargs { - numParams-- - } - - funcode.NumParams = numParams - funcode.NumKwonlyParams = f.NumKwonlyParams - funcode.HasVarargs = f.HasVarargs - funcode.HasKwargs = f.HasKwargs - fcomp.emit1(MAKEFUNC, fcomp.pcomp.functionIndex(funcode)) -} - -// ifelse emits a Boolean control flow decision. -// On return, the current block is unset. -func (fcomp *fcomp) ifelse(cond syntax.Expr, t, f *block) { - switch cond := cond.(type) { - case *syntax.UnaryExpr: - if cond.Op == syntax.NOT { - // if not x then goto t else goto f - // => - // if x then goto f else goto t - fcomp.ifelse(cond.X, f, t) - return - } - - case *syntax.BinaryExpr: - switch cond.Op { - case syntax.AND: - // if x and y then goto t else goto f - // => - // if x then ifelse(y, t, f) else goto f - fcomp.expr(cond.X) - y := fcomp.newBlock() - fcomp.condjump(CJMP, y, f) - - fcomp.block = y - fcomp.ifelse(cond.Y, t, f) - return - - case syntax.OR: - // if x or y then goto t else goto f - // => - // if x then goto t else ifelse(y, t, f) - fcomp.expr(cond.X) - y := fcomp.newBlock() - fcomp.condjump(CJMP, t, y) - - fcomp.block = y - fcomp.ifelse(cond.Y, t, f) - return - case syntax.NOT_IN: - // if x not in y then goto t else goto f - // => - // if x in y then goto f else goto t - copy := *cond - copy.Op = syntax.IN - fcomp.expr(©) - fcomp.condjump(CJMP, f, t) - return - } - } - - // general case - fcomp.expr(cond) - fcomp.condjump(CJMP, t, f) -} diff --git a/tests/vendor/go.starlark.net/internal/compile/serial.go b/tests/vendor/go.starlark.net/internal/compile/serial.go deleted file mode 100644 index 4d71738cc..000000000 --- a/tests/vendor/go.starlark.net/internal/compile/serial.go +++ /dev/null @@ -1,399 +0,0 @@ -package compile - -// This file defines functions to read and write a compile.Program to a file. -// -// It is the client's responsibility to avoid version skew between the -// compiler used to produce a file and the interpreter that consumes it. -// The version number is provided as a constant. -// Incompatible protocol changes should also increment the version number. -// -// Encoding -// -// Program: -// "sky!" [4]byte # magic number -// str uint32le # offset of section -// version varint # must match Version -// filename string -// numloads varint -// loads []Ident -// numnames varint -// names []string -// numconsts varint -// consts []Constant -// numglobals varint -// globals []Ident -// toplevel Funcode -// numfuncs varint -// funcs []Funcode -// recursion varint (0 or 1) -// []byte # concatenation of all referenced strings -// EOF -// -// Funcode: -// id Ident -// code []byte -// pclinetablen varint -// pclinetab []varint -// numlocals varint -// locals []Ident -// numcells varint -// cells []int -// numfreevars varint -// freevar []Ident -// maxstack varint -// numparams varint -// numkwonlyparams varint -// hasvarargs varint (0 or 1) -// haskwargs varint (0 or 1) -// -// Ident: -// filename string -// line, col varint -// -// Constant: # type data -// type varint # 0=string string -// data ... # 1=bytes string -// # 2=int varint -// # 3=float varint (bits as uint64) -// # 4=bigint string (decimal ASCII text) -// -// The encoding starts with a four-byte magic number. -// The next four bytes are a little-endian uint32 -// that provides the offset of the string section -// at the end of the file, which contains the ordered -// concatenation of all strings referenced by the -// program. This design permits the decoder to read -// the first and second parts of the file into different -// memory allocations: the first (the encoded program) -// is transient, but the second (the strings) persists -// for the life of the Program. -// -// Within the encoded program, all strings are referred -// to by their length. As the encoder and decoder process -// the entire file sequentially, they are in lock step, -// so the start offset of each string is implicit. -// -// Program.Code is represented as a []byte slice to permit -// modification when breakpoints are set. All other strings -// are represented as strings. They all (unsafely) share the -// same backing byte slice. -// -// Aside from the str field, all integers are encoded as varints. - -import ( - "encoding/binary" - "fmt" - "math" - "math/big" - debugpkg "runtime/debug" - "unsafe" - - "go.starlark.net/syntax" -) - -const magic = "!sky" - -// Encode encodes a compiled Starlark program. -func (prog *Program) Encode() []byte { - var e encoder - e.p = append(e.p, magic...) - e.p = append(e.p, "????"...) // string data offset; filled in later - e.int(Version) - e.string(prog.Toplevel.Pos.Filename()) - e.bindings(prog.Loads) - e.int(len(prog.Names)) - for _, name := range prog.Names { - e.string(name) - } - e.int(len(prog.Constants)) - for _, c := range prog.Constants { - switch c := c.(type) { - case string: - e.int(0) - e.string(c) - case Bytes: - e.int(1) - e.string(string(c)) - case int64: - e.int(2) - e.int64(c) - case float64: - e.int(3) - e.uint64(math.Float64bits(c)) - case *big.Int: - e.int(4) - e.string(c.Text(10)) - } - } - e.bindings(prog.Globals) - e.function(prog.Toplevel) - e.int(len(prog.Functions)) - for _, fn := range prog.Functions { - e.function(fn) - } - e.int(b2i(prog.Recursion)) - - // Patch in the offset of the string data section. - binary.LittleEndian.PutUint32(e.p[4:8], uint32(len(e.p))) - - return append(e.p, e.s...) -} - -type encoder struct { - p []byte // encoded program - s []byte // strings - tmp [binary.MaxVarintLen64]byte -} - -func (e *encoder) int(x int) { - e.int64(int64(x)) -} - -func (e *encoder) int64(x int64) { - n := binary.PutVarint(e.tmp[:], x) - e.p = append(e.p, e.tmp[:n]...) -} - -func (e *encoder) uint64(x uint64) { - n := binary.PutUvarint(e.tmp[:], x) - e.p = append(e.p, e.tmp[:n]...) -} - -func (e *encoder) string(s string) { - e.int(len(s)) - e.s = append(e.s, s...) -} - -func (e *encoder) bytes(b []byte) { - e.int(len(b)) - e.s = append(e.s, b...) -} - -func (e *encoder) binding(bind Binding) { - e.string(bind.Name) - e.int(int(bind.Pos.Line)) - e.int(int(bind.Pos.Col)) -} - -func (e *encoder) bindings(binds []Binding) { - e.int(len(binds)) - for _, bind := range binds { - e.binding(bind) - } -} - -func (e *encoder) function(fn *Funcode) { - e.binding(Binding{fn.Name, fn.Pos}) - e.string(fn.Doc) - e.bytes(fn.Code) - e.int(len(fn.pclinetab)) - for _, x := range fn.pclinetab { - e.int64(int64(x)) - } - e.bindings(fn.Locals) - e.int(len(fn.Cells)) - for _, index := range fn.Cells { - e.int(index) - } - e.bindings(fn.Freevars) - e.int(fn.MaxStack) - e.int(fn.NumParams) - e.int(fn.NumKwonlyParams) - e.int(b2i(fn.HasVarargs)) - e.int(b2i(fn.HasKwargs)) -} - -func b2i(b bool) int { - if b { - return 1 - } else { - return 0 - } -} - -// DecodeProgram decodes a compiled Starlark program from data. -func DecodeProgram(data []byte) (_ *Program, err error) { - if len(data) < len(magic) { - return nil, fmt.Errorf("not a compiled module: no magic number") - } - if got := string(data[:4]); got != magic { - return nil, fmt.Errorf("not a compiled module: got magic number %q, want %q", - got, magic) - } - defer func() { - if x := recover(); x != nil { - debugpkg.PrintStack() - err = fmt.Errorf("internal error while decoding program: %v", x) - } - }() - - offset := binary.LittleEndian.Uint32(data[4:8]) - d := decoder{ - p: data[8:offset], - s: append([]byte(nil), data[offset:]...), // allocate a copy, which will persist - } - - if v := d.int(); v != Version { - return nil, fmt.Errorf("version mismatch: read %d, want %d", v, Version) - } - - filename := d.string() - d.filename = &filename - - loads := d.bindings() - - names := make([]string, d.int()) - for i := range names { - names[i] = d.string() - } - - // constants - constants := make([]interface{}, d.int()) - for i := range constants { - var c interface{} - switch d.int() { - case 0: - c = d.string() - case 1: - c = Bytes(d.string()) - case 2: - c = d.int64() - case 3: - c = math.Float64frombits(d.uint64()) - case 4: - c, _ = new(big.Int).SetString(d.string(), 10) - } - constants[i] = c - } - - globals := d.bindings() - toplevel := d.function() - funcs := make([]*Funcode, d.int()) - for i := range funcs { - funcs[i] = d.function() - } - recursion := d.int() != 0 - - prog := &Program{ - Loads: loads, - Names: names, - Constants: constants, - Globals: globals, - Functions: funcs, - Toplevel: toplevel, - Recursion: recursion, - } - toplevel.Prog = prog - for _, f := range funcs { - f.Prog = prog - } - - if len(d.p)+len(d.s) > 0 { - return nil, fmt.Errorf("internal error: unconsumed data during decoding") - } - - return prog, nil -} - -type decoder struct { - p []byte // encoded program - s []byte // strings - filename *string // (indirect to avoid keeping decoder live) -} - -func (d *decoder) int() int { - return int(d.int64()) -} - -func (d *decoder) int64() int64 { - x, len := binary.Varint(d.p[:]) - d.p = d.p[len:] - return x -} - -func (d *decoder) uint64() uint64 { - x, len := binary.Uvarint(d.p[:]) - d.p = d.p[len:] - return x -} - -func (d *decoder) string() (s string) { - if slice := d.bytes(); len(slice) > 0 { - // Avoid a memory allocation for each string - // by unsafely aliasing slice. - type string struct { - data *byte - len int - } - ptr := (*string)(unsafe.Pointer(&s)) - ptr.data = &slice[0] - ptr.len = len(slice) - } - return s -} - -func (d *decoder) bytes() []byte { - len := d.int() - r := d.s[:len:len] - d.s = d.s[len:] - return r -} - -func (d *decoder) binding() Binding { - name := d.string() - line := int32(d.int()) - col := int32(d.int()) - return Binding{Name: name, Pos: syntax.MakePosition(d.filename, line, col)} -} - -func (d *decoder) bindings() []Binding { - bindings := make([]Binding, d.int()) - for i := range bindings { - bindings[i] = d.binding() - } - return bindings -} - -func (d *decoder) ints() []int { - ints := make([]int, d.int()) - for i := range ints { - ints[i] = d.int() - } - return ints -} - -func (d *decoder) bool() bool { return d.int() != 0 } - -func (d *decoder) function() *Funcode { - id := d.binding() - doc := d.string() - code := d.bytes() - pclinetab := make([]uint16, d.int()) - for i := range pclinetab { - pclinetab[i] = uint16(d.int()) - } - locals := d.bindings() - cells := d.ints() - freevars := d.bindings() - maxStack := d.int() - numParams := d.int() - numKwonlyParams := d.int() - hasVarargs := d.int() != 0 - hasKwargs := d.int() != 0 - return &Funcode{ - // Prog is filled in later. - Pos: id.Pos, - Name: id.Name, - Doc: doc, - Code: code, - pclinetab: pclinetab, - Locals: locals, - Cells: cells, - Freevars: freevars, - MaxStack: maxStack, - NumParams: numParams, - NumKwonlyParams: numKwonlyParams, - HasVarargs: hasVarargs, - HasKwargs: hasKwargs, - } -} diff --git a/tests/vendor/go.starlark.net/internal/spell/spell.go b/tests/vendor/go.starlark.net/internal/spell/spell.go deleted file mode 100644 index 7739fabaa..000000000 --- a/tests/vendor/go.starlark.net/internal/spell/spell.go +++ /dev/null @@ -1,115 +0,0 @@ -// Package spell file defines a simple spelling checker for use in attribute errors -// such as "no such field .foo; did you mean .food?". -package spell - -import ( - "strings" - "unicode" -) - -// Nearest returns the element of candidates -// nearest to x using the Levenshtein metric, -// or "" if none were promising. -func Nearest(x string, candidates []string) string { - // Ignore underscores and case when matching. - fold := func(s string) string { - return strings.Map(func(r rune) rune { - if r == '_' { - return -1 - } - return unicode.ToLower(r) - }, s) - } - - x = fold(x) - - var best string - bestD := (len(x) + 1) / 2 // allow up to 50% typos - for _, c := range candidates { - d := levenshtein(x, fold(c), bestD) - if d < bestD { - bestD = d - best = c - } - } - return best -} - -// levenshtein returns the non-negative Levenshtein edit distance -// between the byte strings x and y. -// -// If the computed distance exceeds max, -// the function may return early with an approximate value > max. -func levenshtein(x, y string, max int) int { - // This implementation is derived from one by Laurent Le Brun in - // Bazel that uses the single-row space efficiency trick - // described at bitbucket.org/clearer/iosifovich. - - // Let x be the shorter string. - if len(x) > len(y) { - x, y = y, x - } - - // Remove common prefix. - for i := 0; i < len(x); i++ { - if x[i] != y[i] { - x = x[i:] - y = y[i:] - break - } - } - if x == "" { - return len(y) - } - - if d := abs(len(x) - len(y)); d > max { - return d // excessive length divergence - } - - row := make([]int, len(y)+1) - for i := range row { - row[i] = i - } - - for i := 1; i <= len(x); i++ { - row[0] = i - best := i - prev := i - 1 - for j := 1; j <= len(y); j++ { - a := prev + b2i(x[i-1] != y[j-1]) // substitution - b := 1 + row[j-1] // deletion - c := 1 + row[j] // insertion - k := min(a, min(b, c)) - prev, row[j] = row[j], k - best = min(best, k) - } - if best > max { - return best - } - } - return row[len(y)] -} - -func b2i(b bool) int { - if b { - return 1 - } else { - return 0 - } -} - -func min(x, y int) int { - if x < y { - return x - } else { - return y - } -} - -func abs(x int) int { - if x >= 0 { - return x - } else { - return -x - } -} diff --git a/tests/vendor/go.starlark.net/resolve/binding.go b/tests/vendor/go.starlark.net/resolve/binding.go deleted file mode 100644 index 8507e64c7..000000000 --- a/tests/vendor/go.starlark.net/resolve/binding.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package resolve - -import "go.starlark.net/syntax" - -// This file defines resolver data types saved in the syntax tree. -// We cannot guarantee API stability for these types -// as they are closely tied to the implementation. - -// A Binding contains resolver information about an identifier. -// The resolver populates the Binding field of each syntax.Identifier. -// The Binding ties together all identifiers that denote the same variable. -type Binding struct { - Scope Scope - - // Index records the index into the enclosing - // - {DefStmt,File}.Locals, if Scope==Local - // - DefStmt.FreeVars, if Scope==Free - // - File.Globals, if Scope==Global. - // It is zero if Scope is Predeclared, Universal, or Undefined. - Index int - - First *syntax.Ident // first binding use (iff Scope==Local/Free/Global) -} - -// The Scope of Binding indicates what kind of scope it has. -type Scope uint8 - -const ( - Undefined Scope = iota // name is not defined - Local // name is local to its function or file - Cell // name is function-local but shared with a nested function - Free // name is cell of some enclosing function - Global // name is global to module - Predeclared // name is predeclared for this module (e.g. glob) - Universal // name is universal (e.g. len) -) - -var scopeNames = [...]string{ - Undefined: "undefined", - Local: "local", - Cell: "cell", - Free: "free", - Global: "global", - Predeclared: "predeclared", - Universal: "universal", -} - -func (scope Scope) String() string { return scopeNames[scope] } - -// A Module contains resolver information about a file. -// The resolver populates the Module field of each syntax.File. -type Module struct { - Locals []*Binding // the file's (comprehension-)local variables - Globals []*Binding // the file's global variables -} - -// A Function contains resolver information about a named or anonymous function. -// The resolver populates the Function field of each syntax.DefStmt and syntax.LambdaExpr. -type Function struct { - Pos syntax.Position // of DEF or LAMBDA - Name string // name of def, or "lambda" - Params []syntax.Expr // param = ident | ident=expr | * | *ident | **ident - Body []syntax.Stmt // contains synthetic 'return expr' for lambda - - HasVarargs bool // whether params includes *args (convenience) - HasKwargs bool // whether params includes **kwargs (convenience) - NumKwonlyParams int // number of keyword-only optional parameters - Locals []*Binding // this function's local/cell variables, parameters first - FreeVars []*Binding // enclosing cells to capture in closure -} diff --git a/tests/vendor/go.starlark.net/resolve/resolve.go b/tests/vendor/go.starlark.net/resolve/resolve.go deleted file mode 100644 index c576a6baf..000000000 --- a/tests/vendor/go.starlark.net/resolve/resolve.go +++ /dev/null @@ -1,981 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package resolve defines a name-resolution pass for Starlark abstract -// syntax trees. -// -// The resolver sets the Locals and FreeVars arrays of each DefStmt and -// the LocalIndex field of each syntax.Ident that refers to a local or -// free variable. It also sets the Locals array of a File for locals -// bound by top-level comprehensions and load statements. -// Identifiers for global variables do not get an index. -package resolve // import "go.starlark.net/resolve" - -// All references to names are statically resolved. Names may be -// predeclared, global, or local to a function or file. -// File-local variables include those bound by top-level comprehensions -// and by load statements. ("Top-level" means "outside of any function".) -// The resolver maps each global name to a small integer and each local -// name to a small integer; these integers enable a fast and compact -// representation of globals and locals in the evaluator. -// -// As an optimization, the resolver classifies each predeclared name as -// either universal (e.g. None, len) or per-module (e.g. glob in Bazel's -// build language), enabling the evaluator to share the representation -// of the universal environment across all modules. -// -// The lexical environment is a tree of blocks with the file block at -// its root. The file's child blocks may be of two kinds: functions -// and comprehensions, and these may have further children of either -// kind. -// -// Python-style resolution requires multiple passes because a name is -// determined to be local to a function only if the function contains a -// "binding" use of it; similarly, a name is determined to be global (as -// opposed to predeclared) if the module contains a top-level binding use. -// Unlike ordinary top-level assignments, the bindings created by load -// statements are local to the file block. -// A non-binding use may lexically precede the binding to which it is resolved. -// In the first pass, we inspect each function, recording in -// 'uses' each identifier and the environment block in which it occurs. -// If a use of a name is binding, such as a function parameter or -// assignment, we add the name to the block's bindings mapping and add a -// local variable to the enclosing function. -// -// As we finish resolving each function, we inspect all the uses within -// that function and discard ones that were found to be function-local. The -// remaining ones must be either free (local to some lexically enclosing -// function), or top-level (global, predeclared, or file-local), but we cannot tell -// which until we have finished inspecting the outermost enclosing -// function. At that point, we can distinguish local from top-level names -// (and this is when Python would compute free variables). -// -// However, Starlark additionally requires that all references to global -// names are satisfied by some declaration in the current module; -// Starlark permits a function to forward-reference a global or file-local -// that has not -// been declared yet so long as it is declared before the end of the -// module. So, instead of re-resolving the unresolved references after -// each top-level function, we defer this until the end of the module -// and ensure that all such references are satisfied by some definition. -// -// At the end of the module, we visit each of the nested function blocks -// in bottom-up order, doing a recursive lexical lookup for each -// unresolved name. If the name is found to be local to some enclosing -// function, we must create a DefStmt.FreeVar (capture) parameter for -// each intervening function. We enter these synthetic bindings into -// the bindings map so that we create at most one freevar per name. If -// the name was not local, we check that it was defined at module level. -// -// We resolve all uses of locals in the module (due to load statements -// and comprehensions) in a similar way and compute the file's set of -// local variables. -// -// Starlark enforces that all global names are assigned at most once on -// all control flow paths by forbidding if/else statements and loops at -// top level. A global may be used before it is defined, leading to a -// dynamic error. However, the AllowGlobalReassign flag (really: allow -// top-level reassign) makes the resolver allow multiple to a variable -// at top-level. It also allows if-, for-, and while-loops at top-level, -// which in turn may make the evaluator dynamically assign multiple -// values to a variable at top-level. (These two roles should be separated.) - -import ( - "fmt" - "log" - "sort" - "strings" - - "go.starlark.net/internal/spell" - "go.starlark.net/syntax" -) - -const debug = false -const doesnt = "this Starlark dialect does not " - -// global options -// These features are either not standard Starlark (yet), or deprecated -// features of the BUILD language, so we put them behind flags. -// -// Deprecated: use an explicit [syntax.FileOptions] argument instead, -// as it avoids all the usual problems of global variables. -var ( - AllowSet = false // allow the 'set' built-in - AllowGlobalReassign = false // allow reassignment to top-level names; also, allow if/for/while at top-level - AllowRecursion = false // allow while statements and recursive functions - LoadBindsGlobally = false // load creates global not file-local bindings (deprecated) - - // obsolete flags for features that are now standard. No effect. - AllowNestedDef = true - AllowLambda = true - AllowFloat = true - AllowBitwise = true -) - -// File resolves the specified file and records information about the -// module in file.Module. -// -// The isPredeclared and isUniversal predicates report whether a name is -// a pre-declared identifier (visible in the current module) or a -// universal identifier (visible in every module). -// Clients should typically pass predeclared.Has for the first and -// starlark.Universe.Has for the second, where predeclared is the -// module's StringDict of predeclared names and starlark.Universe is the -// standard set of built-ins. -// The isUniverse predicate is supplied a parameter to avoid a cyclic -// dependency upon starlark.Universe, not because users should ever need -// to redefine it. -func File(file *syntax.File, isPredeclared, isUniversal func(name string) bool) error { - return REPLChunk(file, nil, isPredeclared, isUniversal) -} - -// REPLChunk is a generalization of the File function that supports a -// non-empty initial global block, as occurs in a REPL. -func REPLChunk(file *syntax.File, isGlobal, isPredeclared, isUniversal func(name string) bool) error { - r := newResolver(file.Options, isGlobal, isPredeclared, isUniversal) - r.stmts(file.Stmts) - - r.env.resolveLocalUses() - - // At the end of the module, resolve all non-local variable references, - // computing closures. - // Function bodies may contain forward references to later global declarations. - r.resolveNonLocalUses(r.env) - - file.Module = &Module{ - Locals: r.moduleLocals, - Globals: r.moduleGlobals, - } - - if len(r.errors) > 0 { - return r.errors - } - return nil -} - -// Expr calls [ExprOptions] using [syntax.LegacyFileOptions]. -// Deprecated: relies on legacy global variables. -func Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) { - return ExprOptions(syntax.LegacyFileOptions(), expr, isPredeclared, isUniversal) -} - -// ExprOptions resolves the specified expression. -// It returns the local variables bound within the expression. -// -// The isPredeclared and isUniversal predicates behave as for the File function -func ExprOptions(opts *syntax.FileOptions, expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) { - r := newResolver(opts, nil, isPredeclared, isUniversal) - r.expr(expr) - r.env.resolveLocalUses() - r.resolveNonLocalUses(r.env) // globals & universals - if len(r.errors) > 0 { - return nil, r.errors - } - return r.moduleLocals, nil -} - -// An ErrorList is a non-empty list of resolver error messages. -type ErrorList []Error // len > 0 - -func (e ErrorList) Error() string { return e[0].Error() } - -// An Error describes the nature and position of a resolver error. -type Error struct { - Pos syntax.Position - Msg string -} - -func (e Error) Error() string { return e.Pos.String() + ": " + e.Msg } - -func newResolver(options *syntax.FileOptions, isGlobal, isPredeclared, isUniversal func(name string) bool) *resolver { - file := new(block) - return &resolver{ - options: options, - file: file, - env: file, - isGlobal: isGlobal, - isPredeclared: isPredeclared, - isUniversal: isUniversal, - globals: make(map[string]*Binding), - predeclared: make(map[string]*Binding), - } -} - -type resolver struct { - options *syntax.FileOptions - - // env is the current local environment: - // a linked list of blocks, innermost first. - // The tail of the list is the file block. - env *block - file *block // file block (contains load bindings) - - // moduleLocals contains the local variables of the module - // (due to load statements and comprehensions outside any function). - // moduleGlobals contains the global variables of the module. - moduleLocals []*Binding - moduleGlobals []*Binding - - // globals maps each global name in the module to its binding. - // predeclared does the same for predeclared and universal names. - globals map[string]*Binding - predeclared map[string]*Binding - - // These predicates report whether a name is - // pre-declared, either in this module or universally, - // or already declared in the module globals (as in a REPL). - // isGlobal may be nil. - isGlobal, isPredeclared, isUniversal func(name string) bool - - loops int // number of enclosing for/while loops - ifstmts int // number of enclosing if statements loops - - errors ErrorList -} - -// container returns the innermost enclosing "container" block: -// a function (function != nil) or file (function == nil). -// Container blocks accumulate local variable bindings. -func (r *resolver) container() *block { - for b := r.env; ; b = b.parent { - if b.function != nil || b == r.file { - return b - } - } -} - -func (r *resolver) push(b *block) { - r.env.children = append(r.env.children, b) - b.parent = r.env - r.env = b -} - -func (r *resolver) pop() { r.env = r.env.parent } - -type block struct { - parent *block // nil for file block - - // In the file (root) block, both these fields are nil. - function *Function // only for function blocks - comp *syntax.Comprehension // only for comprehension blocks - - // bindings maps a name to its binding. - // A local binding has an index into its innermost enclosing container's locals array. - // A free binding has an index into its innermost enclosing function's freevars array. - bindings map[string]*Binding - - // children records the child blocks of the current one. - children []*block - - // uses records all identifiers seen in this container (function or file), - // and a reference to the environment in which they appear. - // As we leave each container block, we resolve them, - // so that only free and global ones remain. - // At the end of each top-level function we compute closures. - uses []use -} - -func (b *block) bind(name string, bind *Binding) { - if b.bindings == nil { - b.bindings = make(map[string]*Binding) - } - b.bindings[name] = bind -} - -func (b *block) String() string { - if b.function != nil { - return "function block at " + fmt.Sprint(b.function.Pos) - } - if b.comp != nil { - return "comprehension block at " + fmt.Sprint(b.comp.Span()) - } - return "file block" -} - -func (r *resolver) errorf(posn syntax.Position, format string, args ...interface{}) { - r.errors = append(r.errors, Error{posn, fmt.Sprintf(format, args...)}) -} - -// A use records an identifier and the environment in which it appears. -type use struct { - id *syntax.Ident - env *block -} - -// bind creates a binding for id: a global (not file-local) -// binding at top-level, a local binding otherwise. -// At top-level, it reports an error if a global or file-local -// binding already exists, unless AllowGlobalReassign. -// It sets id.Binding to the binding (whether old or new), -// and returns whether a binding already existed. -func (r *resolver) bind(id *syntax.Ident) bool { - // Binding outside any local (comprehension/function) block? - if r.env == r.file { - bind, ok := r.file.bindings[id.Name] - if !ok { - bind, ok = r.globals[id.Name] - if !ok { - // first global binding of this name - bind = &Binding{ - First: id, - Scope: Global, - Index: len(r.moduleGlobals), - } - r.globals[id.Name] = bind - r.moduleGlobals = append(r.moduleGlobals, bind) - } - } - if ok && !r.options.GlobalReassign { - r.errorf(id.NamePos, "cannot reassign %s %s declared at %s", - bind.Scope, id.Name, bind.First.NamePos) - } - id.Binding = bind - return ok - } - - return r.bindLocal(id) -} - -func (r *resolver) bindLocal(id *syntax.Ident) bool { - // Mark this name as local to current block. - // Assign it a new local (positive) index in the current container. - _, ok := r.env.bindings[id.Name] - if !ok { - var locals *[]*Binding - if fn := r.container().function; fn != nil { - locals = &fn.Locals - } else { - locals = &r.moduleLocals - } - bind := &Binding{ - First: id, - Scope: Local, - Index: len(*locals), - } - r.env.bind(id.Name, bind) - *locals = append(*locals, bind) - } - - r.use(id) - return ok -} - -func (r *resolver) use(id *syntax.Ident) { - use := use{id, r.env} - - // The spec says that if there is a global binding of a name - // then all references to that name in that block refer to the - // global, even if the use precedes the def---just as for locals. - // For example, in this code, - // - // print(len); len=1; print(len) - // - // both occurrences of len refer to the len=1 binding, which - // completely shadows the predeclared len function. - // - // The rationale for these semantics, which differ from Python, - // is that the static meaning of len (a reference to a global) - // does not change depending on where it appears in the file. - // Of course, its dynamic meaning does change, from an error - // into a valid reference, so it's not clear these semantics - // have any practical advantage. - // - // In any case, the Bazel implementation lags behind the spec - // and follows Python behavior, so the first use of len refers - // to the predeclared function. This typically used in a BUILD - // file that redefines a predeclared name half way through, - // for example: - // - // proto_library(...) # built-in rule - // load("myproto.bzl", "proto_library") - // proto_library(...) # user-defined rule - // - // We will piggyback support for the legacy semantics on the - // AllowGlobalReassign flag, which is loosely related and also - // required for Bazel. - if r.options.GlobalReassign && r.env == r.file { - r.useToplevel(use) - return - } - - b := r.container() - b.uses = append(b.uses, use) -} - -// useToplevel resolves use.id as a reference to a name visible at top-level. -// The use.env field captures the original environment for error reporting. -func (r *resolver) useToplevel(use use) (bind *Binding) { - id := use.id - - if prev, ok := r.file.bindings[id.Name]; ok { - // use of load-defined name in file block - bind = prev - } else if prev, ok := r.globals[id.Name]; ok { - // use of global declared by module - bind = prev - } else if r.isGlobal != nil && r.isGlobal(id.Name) { - // use of global defined in a previous REPL chunk - bind = &Binding{ - First: id, // wrong: this is not even a binding use - Scope: Global, - Index: len(r.moduleGlobals), - } - r.globals[id.Name] = bind - r.moduleGlobals = append(r.moduleGlobals, bind) - } else if prev, ok := r.predeclared[id.Name]; ok { - // repeated use of predeclared or universal - bind = prev - } else if r.isPredeclared(id.Name) { - // use of pre-declared name - bind = &Binding{Scope: Predeclared} - r.predeclared[id.Name] = bind // save it - } else if r.isUniversal(id.Name) { - // use of universal name - if !r.options.Set && id.Name == "set" { - r.errorf(id.NamePos, doesnt+"support sets") - } - bind = &Binding{Scope: Universal} - r.predeclared[id.Name] = bind // save it - } else { - bind = &Binding{Scope: Undefined} - var hint string - if n := r.spellcheck(use); n != "" { - hint = fmt.Sprintf(" (did you mean %s?)", n) - } - r.errorf(id.NamePos, "undefined: %s%s", id.Name, hint) - } - id.Binding = bind - return bind -} - -// spellcheck returns the most likely misspelling of -// the name use.id in the environment use.env. -func (r *resolver) spellcheck(use use) string { - var names []string - - // locals - for b := use.env; b != nil; b = b.parent { - for name := range b.bindings { - names = append(names, name) - } - } - - // globals - // - // We have no way to enumerate the sets whose membership - // tests are isPredeclared, isUniverse, and isGlobal, - // which includes prior names in the REPL session. - for _, bind := range r.moduleGlobals { - names = append(names, bind.First.Name) - } - - sort.Strings(names) - return spell.Nearest(use.id.Name, names) -} - -// resolveLocalUses is called when leaving a container (function/module) -// block. It resolves all uses of locals/cells within that block. -func (b *block) resolveLocalUses() { - unresolved := b.uses[:0] - for _, use := range b.uses { - if bind := lookupLocal(use); bind != nil && (bind.Scope == Local || bind.Scope == Cell) { - use.id.Binding = bind - } else { - unresolved = append(unresolved, use) - } - } - b.uses = unresolved -} - -func (r *resolver) stmts(stmts []syntax.Stmt) { - for _, stmt := range stmts { - r.stmt(stmt) - } -} - -func (r *resolver) stmt(stmt syntax.Stmt) { - switch stmt := stmt.(type) { - case *syntax.ExprStmt: - r.expr(stmt.X) - - case *syntax.BranchStmt: - if r.loops == 0 && (stmt.Token == syntax.BREAK || stmt.Token == syntax.CONTINUE) { - r.errorf(stmt.TokenPos, "%s not in a loop", stmt.Token) - } - - case *syntax.IfStmt: - if !r.options.TopLevelControl && r.container().function == nil { - r.errorf(stmt.If, "if statement not within a function") - } - r.expr(stmt.Cond) - r.ifstmts++ - r.stmts(stmt.True) - r.stmts(stmt.False) - r.ifstmts-- - - case *syntax.AssignStmt: - r.expr(stmt.RHS) - isAugmented := stmt.Op != syntax.EQ - r.assign(stmt.LHS, isAugmented) - - case *syntax.DefStmt: - r.bind(stmt.Name) - fn := &Function{ - Name: stmt.Name.Name, - Pos: stmt.Def, - Params: stmt.Params, - Body: stmt.Body, - } - stmt.Function = fn - r.function(fn, stmt.Def) - - case *syntax.ForStmt: - if !r.options.TopLevelControl && r.container().function == nil { - r.errorf(stmt.For, "for loop not within a function") - } - r.expr(stmt.X) - const isAugmented = false - r.assign(stmt.Vars, isAugmented) - r.loops++ - r.stmts(stmt.Body) - r.loops-- - - case *syntax.WhileStmt: - if !r.options.While { - r.errorf(stmt.While, doesnt+"support while loops") - } - if !r.options.TopLevelControl && r.container().function == nil { - r.errorf(stmt.While, "while loop not within a function") - } - r.expr(stmt.Cond) - r.loops++ - r.stmts(stmt.Body) - r.loops-- - - case *syntax.ReturnStmt: - if r.container().function == nil { - r.errorf(stmt.Return, "return statement not within a function") - } - if stmt.Result != nil { - r.expr(stmt.Result) - } - - case *syntax.LoadStmt: - // A load statement may not be nested in any other statement. - if r.container().function != nil { - r.errorf(stmt.Load, "load statement within a function") - } else if r.loops > 0 { - r.errorf(stmt.Load, "load statement within a loop") - } else if r.ifstmts > 0 { - r.errorf(stmt.Load, "load statement within a conditional") - } - - for i, from := range stmt.From { - if from.Name == "" { - r.errorf(from.NamePos, "load: empty identifier") - continue - } - if from.Name[0] == '_' { - r.errorf(from.NamePos, "load: names with leading underscores are not exported: %s", from.Name) - } - - id := stmt.To[i] - if r.options.LoadBindsGlobally { - r.bind(id) - } else if r.bindLocal(id) && !r.options.GlobalReassign { - // "Global" in AllowGlobalReassign is a misnomer for "toplevel". - // Sadly we can't report the previous declaration - // as id.Binding may not be set yet. - r.errorf(id.NamePos, "cannot reassign top-level %s", id.Name) - } - } - - default: - log.Panicf("unexpected stmt %T", stmt) - } -} - -func (r *resolver) assign(lhs syntax.Expr, isAugmented bool) { - switch lhs := lhs.(type) { - case *syntax.Ident: - // x = ... - r.bind(lhs) - - case *syntax.IndexExpr: - // x[i] = ... - r.expr(lhs.X) - r.expr(lhs.Y) - - case *syntax.DotExpr: - // x.f = ... - r.expr(lhs.X) - - case *syntax.TupleExpr: - // (x, y) = ... - if isAugmented { - r.errorf(syntax.Start(lhs), "can't use tuple expression in augmented assignment") - } - for _, elem := range lhs.List { - r.assign(elem, isAugmented) - } - - case *syntax.ListExpr: - // [x, y, z] = ... - if isAugmented { - r.errorf(syntax.Start(lhs), "can't use list expression in augmented assignment") - } - for _, elem := range lhs.List { - r.assign(elem, isAugmented) - } - - case *syntax.ParenExpr: - r.assign(lhs.X, isAugmented) - - default: - name := strings.ToLower(strings.TrimPrefix(fmt.Sprintf("%T", lhs), "*syntax.")) - r.errorf(syntax.Start(lhs), "can't assign to %s", name) - } -} - -func (r *resolver) expr(e syntax.Expr) { - switch e := e.(type) { - case *syntax.Ident: - r.use(e) - - case *syntax.Literal: - - case *syntax.ListExpr: - for _, x := range e.List { - r.expr(x) - } - - case *syntax.CondExpr: - r.expr(e.Cond) - r.expr(e.True) - r.expr(e.False) - - case *syntax.IndexExpr: - r.expr(e.X) - r.expr(e.Y) - - case *syntax.DictEntry: - r.expr(e.Key) - r.expr(e.Value) - - case *syntax.SliceExpr: - r.expr(e.X) - if e.Lo != nil { - r.expr(e.Lo) - } - if e.Hi != nil { - r.expr(e.Hi) - } - if e.Step != nil { - r.expr(e.Step) - } - - case *syntax.Comprehension: - // The 'in' operand of the first clause (always a ForClause) - // is resolved in the outer block; consider: [x for x in x]. - clause := e.Clauses[0].(*syntax.ForClause) - r.expr(clause.X) - - // A list/dict comprehension defines a new lexical block. - // Locals defined within the block will be allotted - // distinct slots in the locals array of the innermost - // enclosing container (function/module) block. - r.push(&block{comp: e}) - - const isAugmented = false - r.assign(clause.Vars, isAugmented) - - for _, clause := range e.Clauses[1:] { - switch clause := clause.(type) { - case *syntax.IfClause: - r.expr(clause.Cond) - case *syntax.ForClause: - r.assign(clause.Vars, isAugmented) - r.expr(clause.X) - } - } - r.expr(e.Body) // body may be *DictEntry - r.pop() - - case *syntax.TupleExpr: - for _, x := range e.List { - r.expr(x) - } - - case *syntax.DictExpr: - for _, entry := range e.List { - entry := entry.(*syntax.DictEntry) - r.expr(entry.Key) - r.expr(entry.Value) - } - - case *syntax.UnaryExpr: - r.expr(e.X) - - case *syntax.BinaryExpr: - r.expr(e.X) - r.expr(e.Y) - - case *syntax.DotExpr: - r.expr(e.X) - // ignore e.Name - - case *syntax.CallExpr: - r.expr(e.Fn) - var seenVarargs, seenKwargs bool - var seenName map[string]bool - var n, p int - for _, arg := range e.Args { - pos, _ := arg.Span() - if unop, ok := arg.(*syntax.UnaryExpr); ok && unop.Op == syntax.STARSTAR { - // **kwargs - if seenKwargs { - r.errorf(pos, "multiple **kwargs not allowed") - } - seenKwargs = true - r.expr(arg) - } else if ok && unop.Op == syntax.STAR { - // *args - if seenKwargs { - r.errorf(pos, "*args may not follow **kwargs") - } else if seenVarargs { - r.errorf(pos, "multiple *args not allowed") - } - seenVarargs = true - r.expr(arg) - } else if binop, ok := arg.(*syntax.BinaryExpr); ok && binop.Op == syntax.EQ { - // k=v - n++ - if seenKwargs { - r.errorf(pos, "keyword argument may not follow **kwargs") - } else if seenVarargs { - r.errorf(pos, "keyword argument may not follow *args") - } - x := binop.X.(*syntax.Ident) - if seenName[x.Name] { - r.errorf(x.NamePos, "keyword argument %q is repeated", x.Name) - } else { - if seenName == nil { - seenName = make(map[string]bool) - } - seenName[x.Name] = true - } - r.expr(binop.Y) - } else { - // positional argument - p++ - if seenVarargs { - r.errorf(pos, "positional argument may not follow *args") - } else if seenKwargs { - r.errorf(pos, "positional argument may not follow **kwargs") - } else if len(seenName) > 0 { - r.errorf(pos, "positional argument may not follow named") - } - r.expr(arg) - } - } - - // Fail gracefully if compiler-imposed limit is exceeded. - if p >= 256 { - pos, _ := e.Span() - r.errorf(pos, "%v positional arguments in call, limit is 255", p) - } - if n >= 256 { - pos, _ := e.Span() - r.errorf(pos, "%v keyword arguments in call, limit is 255", n) - } - - case *syntax.LambdaExpr: - fn := &Function{ - Name: "lambda", - Pos: e.Lambda, - Params: e.Params, - Body: []syntax.Stmt{&syntax.ReturnStmt{Result: e.Body}}, - } - e.Function = fn - r.function(fn, e.Lambda) - - case *syntax.ParenExpr: - r.expr(e.X) - - default: - log.Panicf("unexpected expr %T", e) - } -} - -func (r *resolver) function(function *Function, pos syntax.Position) { - // Resolve defaults in enclosing environment. - for _, param := range function.Params { - if binary, ok := param.(*syntax.BinaryExpr); ok { - r.expr(binary.Y) - } - } - - // Enter function block. - b := &block{function: function} - r.push(b) - - var seenOptional bool - var star *syntax.UnaryExpr // * or *args param - var starStar *syntax.Ident // **kwargs ident - var numKwonlyParams int - for _, param := range function.Params { - switch param := param.(type) { - case *syntax.Ident: - // e.g. x - if starStar != nil { - r.errorf(param.NamePos, "required parameter may not follow **%s", starStar.Name) - } else if star != nil { - numKwonlyParams++ - } else if seenOptional { - r.errorf(param.NamePos, "required parameter may not follow optional") - } - if r.bind(param) { - r.errorf(param.NamePos, "duplicate parameter: %s", param.Name) - } - - case *syntax.BinaryExpr: - // e.g. y=dflt - if starStar != nil { - r.errorf(param.OpPos, "optional parameter may not follow **%s", starStar.Name) - } else if star != nil { - numKwonlyParams++ - } - if id := param.X.(*syntax.Ident); r.bind(id) { - r.errorf(param.OpPos, "duplicate parameter: %s", id.Name) - } - seenOptional = true - - case *syntax.UnaryExpr: - // * or *args or **kwargs - if param.Op == syntax.STAR { - if starStar != nil { - r.errorf(param.OpPos, "* parameter may not follow **%s", starStar.Name) - } else if star != nil { - r.errorf(param.OpPos, "multiple * parameters not allowed") - } else { - star = param - } - } else { - if starStar != nil { - r.errorf(param.OpPos, "multiple ** parameters not allowed") - } - starStar = param.X.(*syntax.Ident) - } - } - } - - // Bind the *args and **kwargs parameters at the end, - // so that regular parameters a/b/c are contiguous and - // there is no hole for the "*": - // def f(a, b, *args, c=0, **kwargs) - // def f(a, b, *, c=0, **kwargs) - if star != nil { - if id, _ := star.X.(*syntax.Ident); id != nil { - // *args - if r.bind(id) { - r.errorf(id.NamePos, "duplicate parameter: %s", id.Name) - } - function.HasVarargs = true - } else if numKwonlyParams == 0 { - r.errorf(star.OpPos, "bare * must be followed by keyword-only parameters") - } - } - if starStar != nil { - if r.bind(starStar) { - r.errorf(starStar.NamePos, "duplicate parameter: %s", starStar.Name) - } - function.HasKwargs = true - } - - function.NumKwonlyParams = numKwonlyParams - r.stmts(function.Body) - - // Resolve all uses of this function's local vars, - // and keep just the remaining uses of free/global vars. - b.resolveLocalUses() - - // Leave function block. - r.pop() - - // References within the function body to globals are not - // resolved until the end of the module. -} - -func (r *resolver) resolveNonLocalUses(b *block) { - // First resolve inner blocks. - for _, child := range b.children { - r.resolveNonLocalUses(child) - } - for _, use := range b.uses { - use.id.Binding = r.lookupLexical(use, use.env) - } -} - -// lookupLocal looks up an identifier within its immediately enclosing function. -func lookupLocal(use use) *Binding { - for env := use.env; env != nil; env = env.parent { - if bind, ok := env.bindings[use.id.Name]; ok { - if bind.Scope == Free { - // shouldn't exist till later - log.Panicf("%s: internal error: %s, %v", use.id.NamePos, use.id.Name, bind) - } - return bind // found - } - if env.function != nil { - break - } - } - return nil // not found in this function -} - -// lookupLexical looks up an identifier use.id within its lexically enclosing environment. -// The use.env field captures the original environment for error reporting. -func (r *resolver) lookupLexical(use use, env *block) (bind *Binding) { - if debug { - fmt.Printf("lookupLexical %s in %s = ...\n", use.id.Name, env) - defer func() { fmt.Printf("= %v\n", bind) }() - } - - // Is this the file block? - if env == r.file { - return r.useToplevel(use) // file-local, global, predeclared, or not found - } - - // Defined in this block? - bind, ok := env.bindings[use.id.Name] - if !ok { - // Defined in parent block? - bind = r.lookupLexical(use, env.parent) - if env.function != nil && (bind.Scope == Local || bind.Scope == Free || bind.Scope == Cell) { - // Found in parent block, which belongs to enclosing function. - // Add the parent's binding to the function's freevars, - // and add a new 'free' binding to the inner function's block, - // and turn the parent's local into cell. - if bind.Scope == Local { - bind.Scope = Cell - } - index := len(env.function.FreeVars) - env.function.FreeVars = append(env.function.FreeVars, bind) - bind = &Binding{ - First: bind.First, - Scope: Free, - Index: index, - } - if debug { - fmt.Printf("creating freevar %v in function at %s: %s\n", - len(env.function.FreeVars), env.function.Pos, use.id.Name) - } - } - - // Memoize, to avoid duplicate free vars - // and redundant global (failing) lookups. - env.bind(use.id.Name, bind) - } - return bind -} diff --git a/tests/vendor/go.starlark.net/starlark/debug.go b/tests/vendor/go.starlark.net/starlark/debug.go deleted file mode 100644 index 22a21240f..000000000 --- a/tests/vendor/go.starlark.net/starlark/debug.go +++ /dev/null @@ -1,42 +0,0 @@ -package starlark - -import "go.starlark.net/syntax" - -// This file defines an experimental API for the debugging tools. -// Some of these declarations expose details of internal packages. -// (The debugger makes liberal use of exported fields of unexported types.) -// Breaking changes may occur without notice. - -// Local returns the value of the i'th local variable. -// It may be nil if not yet assigned. -// -// Local may be called only for frames whose Callable is a *Function (a -// function defined by Starlark source code), and only while the frame -// is active; it will panic otherwise. -// -// This function is provided only for debugging tools. -// -// THIS API IS EXPERIMENTAL AND MAY CHANGE WITHOUT NOTICE. -func (fr *frame) Local(i int) Value { return fr.locals[i] } - -// DebugFrame is the debugger API for a frame of the interpreter's call stack. -// -// Most applications have no need for this API; use CallFrame instead. -// -// Clients must not retain a DebugFrame nor call any of its methods once -// the current built-in call has returned or execution has resumed -// after a breakpoint as this may have unpredictable effects, including -// but not limited to retention of object that would otherwise be garbage. -type DebugFrame interface { - Callable() Callable // returns the frame's function - Local(i int) Value // returns the value of the (Starlark) frame's ith local variable - Position() syntax.Position // returns the current position of execution in this frame -} - -// DebugFrame returns the debugger interface for -// the specified frame of the interpreter's call stack. -// Frame numbering is as for Thread.CallFrame. -// -// This function is intended for use in debugging tools. -// Most applications should have no need for it; use CallFrame instead. -func (thread *Thread) DebugFrame(depth int) DebugFrame { return thread.frameAt(depth) } diff --git a/tests/vendor/go.starlark.net/starlark/empty.s b/tests/vendor/go.starlark.net/starlark/empty.s deleted file mode 100644 index 3b8216999..000000000 --- a/tests/vendor/go.starlark.net/starlark/empty.s +++ /dev/null @@ -1,3 +0,0 @@ -// The presence of this file allows the package to use the -// "go:linkname" hack to call non-exported functions in the -// Go runtime, such as hardware-accelerated string hashing. diff --git a/tests/vendor/go.starlark.net/starlark/eval.go b/tests/vendor/go.starlark.net/starlark/eval.go deleted file mode 100644 index 6c11bc47d..000000000 --- a/tests/vendor/go.starlark.net/starlark/eval.go +++ /dev/null @@ -1,1672 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package starlark - -import ( - "fmt" - "io" - "log" - "math/big" - "sort" - "strings" - "sync/atomic" - "time" - "unicode" - "unicode/utf8" - "unsafe" - - "go.starlark.net/internal/compile" - "go.starlark.net/internal/spell" - "go.starlark.net/resolve" - "go.starlark.net/syntax" -) - -// A Thread contains the state of a Starlark thread, -// such as its call stack and thread-local storage. -// The Thread is threaded throughout the evaluator. -type Thread struct { - // Name is an optional name that describes the thread, for debugging. - Name string - - // stack is the stack of (internal) call frames. - stack []*frame - - // Print is the client-supplied implementation of the Starlark - // 'print' function. If nil, fmt.Fprintln(os.Stderr, msg) is - // used instead. - Print func(thread *Thread, msg string) - - // Load is the client-supplied implementation of module loading. - // Repeated calls with the same module name must return the same - // module environment or error. - // The error message need not include the module name. - // - // See example_test.go for some example implementations of Load. - Load func(thread *Thread, module string) (StringDict, error) - - // OnMaxSteps is called when the thread reaches the limit set by SetMaxExecutionSteps. - // The default behavior is to call thread.Cancel("too many steps"). - OnMaxSteps func(thread *Thread) - - // Steps a count of abstract computation steps executed - // by this thread. It is incremented by the interpreter. It may be used - // as a measure of the approximate cost of Starlark execution, by - // computing the difference in its value before and after a computation. - // - // The precise meaning of "step" is not specified and may change. - Steps, maxSteps uint64 - - // cancelReason records the reason from the first call to Cancel. - cancelReason *string - - // locals holds arbitrary "thread-local" Go values belonging to the client. - // They are accessible to the client but not to any Starlark program. - locals map[string]interface{} - - // proftime holds the accumulated execution time since the last profile event. - proftime time.Duration -} - -// ExecutionSteps returns the current value of Steps. -func (thread *Thread) ExecutionSteps() uint64 { - return thread.Steps -} - -// SetMaxExecutionSteps sets a limit on the number of Starlark -// computation steps that may be executed by this thread. If the -// thread's step counter exceeds this limit, the interpreter calls -// the optional OnMaxSteps function or the default behavior -// of calling thread.Cancel("too many steps"). -func (thread *Thread) SetMaxExecutionSteps(max uint64) { - thread.maxSteps = max -} - -// Uncancel resets the cancellation state. -// -// Unlike most methods of Thread, it is safe to call Uncancel from any -// goroutine, even if the thread is actively executing. -func (thread *Thread) Uncancel() { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&thread.cancelReason)), nil) -} - -// Cancel causes execution of Starlark code in the specified thread to -// promptly fail with an EvalError that includes the specified reason. -// There may be a delay before the interpreter observes the cancellation -// if the thread is currently in a call to a built-in function. -// -// Call [Uncancel] to reset the cancellation state. -// -// Unlike most methods of Thread, it is safe to call Cancel from any -// goroutine, even if the thread is actively executing. -func (thread *Thread) Cancel(reason string) { - // Atomically set cancelReason, preserving earlier reason if any. - atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&thread.cancelReason)), nil, unsafe.Pointer(&reason)) -} - -// SetLocal sets the thread-local value associated with the specified key. -// It must not be called after execution begins. -func (thread *Thread) SetLocal(key string, value interface{}) { - if thread.locals == nil { - thread.locals = make(map[string]interface{}) - } - thread.locals[key] = value -} - -// Local returns the thread-local value associated with the specified key. -func (thread *Thread) Local(key string) interface{} { - return thread.locals[key] -} - -// CallFrame returns a copy of the specified frame of the callstack. -// It should only be used in built-ins called from Starlark code. -// Depth 0 means the frame of the built-in itself, 1 is its caller, and so on. -// -// It is equivalent to CallStack().At(depth), but more efficient. -func (thread *Thread) CallFrame(depth int) CallFrame { - return thread.frameAt(depth).asCallFrame() -} - -func (thread *Thread) frameAt(depth int) *frame { - return thread.stack[len(thread.stack)-1-depth] -} - -// CallStack returns a new slice containing the thread's stack of call frames. -func (thread *Thread) CallStack() CallStack { - frames := make([]CallFrame, len(thread.stack)) - for i, fr := range thread.stack { - frames[i] = fr.asCallFrame() - } - return frames -} - -// CallStackDepth returns the number of frames in the current call stack. -func (thread *Thread) CallStackDepth() int { return len(thread.stack) } - -// A StringDict is a mapping from names to values, and represents -// an environment such as the global variables of a module. -// It is not a true starlark.Value. -type StringDict map[string]Value - -// Keys returns a new sorted slice of d's keys. -func (d StringDict) Keys() []string { - names := make([]string, 0, len(d)) - for name := range d { - names = append(names, name) - } - sort.Strings(names) - return names -} - -func (d StringDict) String() string { - buf := new(strings.Builder) - buf.WriteByte('{') - sep := "" - for _, name := range d.Keys() { - buf.WriteString(sep) - buf.WriteString(name) - buf.WriteString(": ") - writeValue(buf, d[name], nil) - sep = ", " - } - buf.WriteByte('}') - return buf.String() -} - -func (d StringDict) Freeze() { - for _, v := range d { - v.Freeze() - } -} - -// Has reports whether the dictionary contains the specified key. -func (d StringDict) Has(key string) bool { _, ok := d[key]; return ok } - -// A frame records a call to a Starlark function (including module toplevel) -// or a built-in function or method. -type frame struct { - callable Callable // current function (or toplevel) or built-in - pc uint32 // program counter (Starlark frames only) - locals []Value // local variables (Starlark frames only) - spanStart int64 // start time of current profiler span -} - -// Position returns the source position of the current point of execution in this frame. -func (fr *frame) Position() syntax.Position { - switch c := fr.callable.(type) { - case *Function: - // Starlark function - return c.funcode.Position(fr.pc) - case callableWithPosition: - // If a built-in Callable defines - // a Position method, use it. - return c.Position() - } - return syntax.MakePosition(&builtinFilename, 0, 0) -} - -var builtinFilename = "" - -// Function returns the frame's function or built-in. -func (fr *frame) Callable() Callable { return fr.callable } - -// A CallStack is a stack of call frames, outermost first. -type CallStack []CallFrame - -// At returns a copy of the frame at depth i. -// At(0) returns the topmost frame. -func (stack CallStack) At(i int) CallFrame { return stack[len(stack)-1-i] } - -// Pop removes and returns the topmost frame. -func (stack *CallStack) Pop() CallFrame { - last := len(*stack) - 1 - top := (*stack)[last] - *stack = (*stack)[:last] - return top -} - -// String returns a user-friendly description of the stack. -func (stack CallStack) String() string { - out := new(strings.Builder) - if len(stack) > 0 { - fmt.Fprintf(out, "Traceback (most recent call last):\n") - } - for _, fr := range stack { - fmt.Fprintf(out, " %s: in %s\n", fr.Pos, fr.Name) - } - return out.String() -} - -// An EvalError is a Starlark evaluation error and -// a copy of the thread's stack at the moment of the error. -type EvalError struct { - Msg string - CallStack CallStack - cause error -} - -// A CallFrame represents the function name and current -// position of execution of an enclosing call frame. -type CallFrame struct { - Name string - Pos syntax.Position -} - -func (fr *frame) asCallFrame() CallFrame { - return CallFrame{ - Name: fr.Callable().Name(), - Pos: fr.Position(), - } -} - -func (thread *Thread) evalError(err error) *EvalError { - return &EvalError{ - Msg: err.Error(), - CallStack: thread.CallStack(), - cause: err, - } -} - -func (e *EvalError) Error() string { return e.Msg } - -// Backtrace returns a user-friendly error message describing the stack -// of calls that led to this error. -func (e *EvalError) Backtrace() string { - // If the topmost stack frame is a built-in function, - // remove it from the stack and add print "Error in fn:". - stack := e.CallStack - suffix := "" - if last := len(stack) - 1; last >= 0 && stack[last].Pos.Filename() == builtinFilename { - suffix = " in " + stack[last].Name - stack = stack[:last] - } - return fmt.Sprintf("%sError%s: %s", stack, suffix, e.Msg) -} - -func (e *EvalError) Unwrap() error { return e.cause } - -// A Program is a compiled Starlark program. -// -// Programs are immutable, and contain no Values. -// A Program may be created by parsing a source file (see SourceProgram) -// or by loading a previously saved compiled program (see CompiledProgram). -type Program struct { - compiled *compile.Program -} - -// CompilerVersion is the version number of the protocol for compiled -// files. Applications must not run programs compiled by one version -// with an interpreter at another version, and should thus incorporate -// the compiler version into the cache key when reusing compiled code. -const CompilerVersion = compile.Version - -// Filename returns the name of the file from which this program was loaded. -func (prog *Program) Filename() string { return prog.compiled.Toplevel.Pos.Filename() } - -func (prog *Program) String() string { return prog.Filename() } - -// NumLoads returns the number of load statements in the compiled program. -func (prog *Program) NumLoads() int { return len(prog.compiled.Loads) } - -// Load(i) returns the name and position of the i'th module directly -// loaded by this one, where 0 <= i < NumLoads(). -// The name is unresolved---exactly as it appears in the source. -func (prog *Program) Load(i int) (string, syntax.Position) { - id := prog.compiled.Loads[i] - return id.Name, id.Pos -} - -// WriteTo writes the compiled module to the specified output stream. -func (prog *Program) Write(out io.Writer) error { - data := prog.compiled.Encode() - _, err := out.Write(data) - return err -} - -// ExecFile calls [ExecFileOptions] using [syntax.LegacyFileOptions]. -// Deprecated: relies on legacy global variables. -func ExecFile(thread *Thread, filename string, src interface{}, predeclared StringDict) (StringDict, error) { - return ExecFileOptions(syntax.LegacyFileOptions(), thread, filename, src, predeclared) -} - -// ExecFileOptions parses, resolves, and executes a Starlark file in the -// specified global environment, which may be modified during execution. -// -// Thread is the state associated with the Starlark thread. -// -// The filename and src parameters are as for syntax.Parse: -// filename is the name of the file to execute, -// and the name that appears in error messages; -// src is an optional source of bytes to use -// instead of filename. -// -// predeclared defines the predeclared names specific to this module. -// Execution does not modify this dictionary, though it may mutate -// its values. -// -// If ExecFileOptions fails during evaluation, it returns an *EvalError -// containing a backtrace. -func ExecFileOptions(opts *syntax.FileOptions, thread *Thread, filename string, src interface{}, predeclared StringDict) (StringDict, error) { - // Parse, resolve, and compile a Starlark source file. - _, mod, err := SourceProgramOptions(opts, filename, src, predeclared.Has) - if err != nil { - return nil, err - } - - g, err := mod.Init(thread, predeclared) - g.Freeze() - return g, err -} - -// SourceProgram calls [SourceProgramOptions] using [syntax.LegacyFileOptions]. -// Deprecated: relies on legacy global variables. -func SourceProgram(filename string, src interface{}, isPredeclared func(string) bool) (*syntax.File, *Program, error) { - return SourceProgramOptions(syntax.LegacyFileOptions(), filename, src, isPredeclared) -} - -// SourceProgramOptions produces a new program by parsing, resolving, -// and compiling a Starlark source file. -// On success, it returns the parsed file and the compiled program. -// The filename and src parameters are as for syntax.Parse. -// -// The isPredeclared predicate reports whether a name is -// a pre-declared identifier of the current module. -// Its typical value is predeclared.Has, -// where predeclared is a StringDict of pre-declared values. -func SourceProgramOptions(opts *syntax.FileOptions, filename string, src interface{}, isPredeclared func(string) bool) (*syntax.File, *Program, error) { - f, err := opts.Parse(filename, src, 0) - if err != nil { - return nil, nil, err - } - prog, err := FileProgram(f, isPredeclared) - return f, prog, err -} - -// FileProgram produces a new program by resolving, -// and compiling the Starlark source file syntax tree. -// On success, it returns the compiled program. -// -// Resolving a syntax tree mutates it. -// Do not call FileProgram more than once on the same file. -// -// The isPredeclared predicate reports whether a name is -// a pre-declared identifier of the current module. -// Its typical value is predeclared.Has, -// where predeclared is a StringDict of pre-declared values. -func FileProgram(f *syntax.File, isPredeclared func(string) bool) (*Program, error) { - if err := resolve.File(f, isPredeclared, Universe.Has); err != nil { - return nil, err - } - - var pos syntax.Position - if len(f.Stmts) > 0 { - pos = syntax.Start(f.Stmts[0]) - } else { - pos = syntax.MakePosition(&f.Path, 1, 1) - } - - module := f.Module.(*resolve.Module) - compiled := compile.File(f.Options, f.Stmts, pos, "", module.Locals, module.Globals) - - return &Program{compiled}, nil -} - -// CompiledProgram produces a new program from the representation -// of a compiled program previously saved by Program.Write. -func CompiledProgram(in io.Reader) (*Program, error) { - data, err := io.ReadAll(in) - if err != nil { - return nil, err - } - compiled, err := compile.DecodeProgram(data) - if err != nil { - return nil, err - } - return &Program{compiled}, nil -} - -// Init creates a set of global variables for the program, -// executes the toplevel code of the specified program, -// and returns a new, unfrozen dictionary of the globals. -func (prog *Program) Init(thread *Thread, predeclared StringDict) (StringDict, error) { - toplevel := makeToplevelFunction(prog.compiled, predeclared) - - _, err := Call(thread, toplevel, nil, nil) - - // Convert the global environment to a map. - // We return a (partial) map even in case of error. - return toplevel.Globals(), err -} - -// ExecREPLChunk compiles and executes file f in the specified thread -// and global environment. This is a variant of ExecFile specialized to -// the needs of a REPL, in which a sequence of input chunks, each -// syntactically a File, manipulates the same set of module globals, -// which are not frozen after execution. -// -// This function is intended to support only go.starlark.net/repl. -// Its API stability is not guaranteed. -func ExecREPLChunk(f *syntax.File, thread *Thread, globals StringDict) error { - var predeclared StringDict - - // -- variant of FileProgram -- - - if err := resolve.REPLChunk(f, globals.Has, predeclared.Has, Universe.Has); err != nil { - return err - } - - var pos syntax.Position - if len(f.Stmts) > 0 { - pos = syntax.Start(f.Stmts[0]) - } else { - pos = syntax.MakePosition(&f.Path, 1, 1) - } - - module := f.Module.(*resolve.Module) - compiled := compile.File(f.Options, f.Stmts, pos, "", module.Locals, module.Globals) - prog := &Program{compiled} - - // -- variant of Program.Init -- - - toplevel := makeToplevelFunction(prog.compiled, predeclared) - - // Initialize module globals from parameter. - for i, id := range prog.compiled.Globals { - if v := globals[id.Name]; v != nil { - toplevel.module.globals[i] = v - } - } - - _, err := Call(thread, toplevel, nil, nil) - - // Reflect changes to globals back to parameter, even after an error. - for i, id := range prog.compiled.Globals { - if v := toplevel.module.globals[i]; v != nil { - globals[id.Name] = v - } - } - - return err -} - -func makeToplevelFunction(prog *compile.Program, predeclared StringDict) *Function { - // Create the Starlark value denoted by each program constant c. - constants := make([]Value, len(prog.Constants)) - for i, c := range prog.Constants { - var v Value - switch c := c.(type) { - case int64: - v = MakeInt64(c) - case *big.Int: - v = MakeBigInt(c) - case string: - v = String(c) - case compile.Bytes: - v = Bytes(c) - case float64: - v = Float(c) - default: - log.Panicf("unexpected constant %T: %v", c, c) - } - constants[i] = v - } - - return &Function{ - funcode: prog.Toplevel, - module: &module{ - program: prog, - predeclared: predeclared, - globals: make([]Value, len(prog.Globals)), - constants: constants, - }, - } -} - -// Eval calls [EvalOptions] using [syntax.LegacyFileOptions]. -// Deprecated: relies on legacy global variables. -func Eval(thread *Thread, filename string, src interface{}, env StringDict) (Value, error) { - return EvalOptions(syntax.LegacyFileOptions(), thread, filename, src, env) -} - -// EvalOptions parses, resolves, and evaluates an expression within the -// specified (predeclared) environment. -// -// Evaluation cannot mutate the environment dictionary itself, -// though it may modify variables reachable from the dictionary. -// -// The filename and src parameters are as for syntax.Parse. -// -// If EvalOptions fails during evaluation, it returns an *EvalError -// containing a backtrace. -func EvalOptions(opts *syntax.FileOptions, thread *Thread, filename string, src interface{}, env StringDict) (Value, error) { - expr, err := opts.ParseExpr(filename, src, 0) - if err != nil { - return nil, err - } - f, err := makeExprFunc(opts, expr, env) - if err != nil { - return nil, err - } - return Call(thread, f, nil, nil) -} - -// EvalExpr calls [EvalExprOptions] using [syntax.LegacyFileOptions]. -// Deprecated: relies on legacy global variables. -func EvalExpr(thread *Thread, expr syntax.Expr, env StringDict) (Value, error) { - return EvalExprOptions(syntax.LegacyFileOptions(), thread, expr, env) -} - -// EvalExprOptions resolves and evaluates an expression within the -// specified (predeclared) environment. -// Evaluating a comma-separated list of expressions yields a tuple value. -// -// Resolving an expression mutates it. -// Do not call EvalExprOptions more than once for the same expression. -// -// Evaluation cannot mutate the environment dictionary itself, -// though it may modify variables reachable from the dictionary. -// -// If EvalExprOptions fails during evaluation, it returns an *EvalError -// containing a backtrace. -func EvalExprOptions(opts *syntax.FileOptions, thread *Thread, expr syntax.Expr, env StringDict) (Value, error) { - fn, err := makeExprFunc(opts, expr, env) - if err != nil { - return nil, err - } - return Call(thread, fn, nil, nil) -} - -// ExprFunc calls [ExprFuncOptions] using [syntax.LegacyFileOptions]. -// Deprecated: relies on legacy global variables. -func ExprFunc(filename string, src interface{}, env StringDict) (*Function, error) { - return ExprFuncOptions(syntax.LegacyFileOptions(), filename, src, env) -} - -// ExprFunc returns a no-argument function -// that evaluates the expression whose source is src. -func ExprFuncOptions(options *syntax.FileOptions, filename string, src interface{}, env StringDict) (*Function, error) { - expr, err := options.ParseExpr(filename, src, 0) - if err != nil { - return nil, err - } - return makeExprFunc(options, expr, env) -} - -// makeExprFunc returns a no-argument function whose body is expr. -// The options must be consistent with those used when parsing expr. -func makeExprFunc(opts *syntax.FileOptions, expr syntax.Expr, env StringDict) (*Function, error) { - locals, err := resolve.ExprOptions(opts, expr, env.Has, Universe.Has) - if err != nil { - return nil, err - } - - return makeToplevelFunction(compile.Expr(opts, expr, "", locals), env), nil -} - -// The following functions are primitive operations of the byte code interpreter. - -// list += iterable -func listExtend(x *List, y Iterable) { - if ylist, ok := y.(*List); ok { - // fast path: list += list - x.elems = append(x.elems, ylist.elems...) - } else { - iter := y.Iterate() - defer iter.Done() - var z Value - for iter.Next(&z) { - x.elems = append(x.elems, z) - } - } -} - -// getAttr implements x.dot. -func getAttr(x Value, name string) (Value, error) { - hasAttr, ok := x.(HasAttrs) - if !ok { - return nil, fmt.Errorf("%s has no .%s field or method", x.Type(), name) - } - - var errmsg string - v, err := hasAttr.Attr(name) - if err == nil { - if v != nil { - return v, nil // success - } - // (nil, nil) => generic error - errmsg = fmt.Sprintf("%s has no .%s field or method", x.Type(), name) - } else if nsa, ok := err.(NoSuchAttrError); ok { - errmsg = string(nsa) - } else { - return nil, err // return error as is - } - - // add spelling hint - if n := spell.Nearest(name, hasAttr.AttrNames()); n != "" { - errmsg = fmt.Sprintf("%s (did you mean .%s?)", errmsg, n) - } - - return nil, fmt.Errorf("%s", errmsg) -} - -// setField implements x.name = y. -func setField(x Value, name string, y Value) error { - if x, ok := x.(HasSetField); ok { - err := x.SetField(name, y) - if _, ok := err.(NoSuchAttrError); ok { - // No such field: check spelling. - if n := spell.Nearest(name, x.AttrNames()); n != "" { - err = fmt.Errorf("%s (did you mean .%s?)", err, n) - } - } - return err - } - - return fmt.Errorf("can't assign to .%s field of %s", name, x.Type()) -} - -// getIndex implements x[y]. -func getIndex(x, y Value) (Value, error) { - switch x := x.(type) { - case Mapping: // dict - z, found, err := x.Get(y) - if err != nil { - return nil, err - } - if !found { - return nil, fmt.Errorf("key %v not in %s", y, x.Type()) - } - return z, nil - - case Indexable: // string, list, tuple - n := x.Len() - i, err := AsInt32(y) - if err != nil { - return nil, fmt.Errorf("%s index: %s", x.Type(), err) - } - origI := i - if i < 0 { - i += n - } - if i < 0 || i >= n { - return nil, outOfRange(origI, n, x) - } - return x.Index(i), nil - } - return nil, fmt.Errorf("unhandled index operation %s[%s]", x.Type(), y.Type()) -} - -func outOfRange(i, n int, x Value) error { - if n == 0 { - return fmt.Errorf("index %d out of range: empty %s", i, x.Type()) - } else { - return fmt.Errorf("%s index %d out of range [%d:%d]", x.Type(), i, -n, n-1) - } -} - -// setIndex implements x[y] = z. -func setIndex(x, y, z Value) error { - switch x := x.(type) { - case HasSetKey: - if err := x.SetKey(y, z); err != nil { - return err - } - - case HasSetIndex: - n := x.Len() - i, err := AsInt32(y) - if err != nil { - return err - } - origI := i - if i < 0 { - i += n - } - if i < 0 || i >= n { - return outOfRange(origI, n, x) - } - return x.SetIndex(i, z) - - default: - return fmt.Errorf("%s value does not support item assignment", x.Type()) - } - return nil -} - -// Unary applies a unary operator (+, -, ~, not) to its operand. -func Unary(op syntax.Token, x Value) (Value, error) { - // The NOT operator is not customizable. - if op == syntax.NOT { - return !x.Truth(), nil - } - - // Int, Float, and user-defined types - if x, ok := x.(HasUnary); ok { - // (nil, nil) => unhandled - y, err := x.Unary(op) - if y != nil || err != nil { - return y, err - } - } - - return nil, fmt.Errorf("unknown unary op: %s %s", op, x.Type()) -} - -// Binary applies a strict binary operator (not AND or OR) to its operands. -// For equality tests or ordered comparisons, use Compare instead. -func Binary(op syntax.Token, x, y Value) (Value, error) { - switch op { - case syntax.PLUS: - switch x := x.(type) { - case String: - if y, ok := y.(String); ok { - return x + y, nil - } - case Int: - switch y := y.(type) { - case Int: - return x.Add(y), nil - case Float: - xf, err := x.finiteFloat() - if err != nil { - return nil, err - } - return xf + y, nil - } - case Float: - switch y := y.(type) { - case Float: - return x + y, nil - case Int: - yf, err := y.finiteFloat() - if err != nil { - return nil, err - } - return x + yf, nil - } - case *List: - if y, ok := y.(*List); ok { - z := make([]Value, 0, x.Len()+y.Len()) - z = append(z, x.elems...) - z = append(z, y.elems...) - return NewList(z), nil - } - case Tuple: - if y, ok := y.(Tuple); ok { - z := make(Tuple, 0, len(x)+len(y)) - z = append(z, x...) - z = append(z, y...) - return z, nil - } - } - - case syntax.MINUS: - switch x := x.(type) { - case Int: - switch y := y.(type) { - case Int: - return x.Sub(y), nil - case Float: - xf, err := x.finiteFloat() - if err != nil { - return nil, err - } - return xf - y, nil - } - case Float: - switch y := y.(type) { - case Float: - return x - y, nil - case Int: - yf, err := y.finiteFloat() - if err != nil { - return nil, err - } - return x - yf, nil - } - case *Set: // difference - if y, ok := y.(*Set); ok { - iter := y.Iterate() - defer iter.Done() - return x.Difference(iter) - } - } - - case syntax.STAR: - switch x := x.(type) { - case Int: - switch y := y.(type) { - case Int: - return x.Mul(y), nil - case Float: - xf, err := x.finiteFloat() - if err != nil { - return nil, err - } - return xf * y, nil - case String: - return stringRepeat(y, x) - case Bytes: - return bytesRepeat(y, x) - case *List: - elems, err := tupleRepeat(Tuple(y.elems), x) - if err != nil { - return nil, err - } - return NewList(elems), nil - case Tuple: - return tupleRepeat(y, x) - } - case Float: - switch y := y.(type) { - case Float: - return x * y, nil - case Int: - yf, err := y.finiteFloat() - if err != nil { - return nil, err - } - return x * yf, nil - } - case String: - if y, ok := y.(Int); ok { - return stringRepeat(x, y) - } - case Bytes: - if y, ok := y.(Int); ok { - return bytesRepeat(x, y) - } - case *List: - if y, ok := y.(Int); ok { - elems, err := tupleRepeat(Tuple(x.elems), y) - if err != nil { - return nil, err - } - return NewList(elems), nil - } - case Tuple: - if y, ok := y.(Int); ok { - return tupleRepeat(x, y) - } - - } - - case syntax.SLASH: - switch x := x.(type) { - case Int: - xf, err := x.finiteFloat() - if err != nil { - return nil, err - } - switch y := y.(type) { - case Int: - yf, err := y.finiteFloat() - if err != nil { - return nil, err - } - if yf == 0.0 { - return nil, fmt.Errorf("floating-point division by zero") - } - return xf / yf, nil - case Float: - if y == 0.0 { - return nil, fmt.Errorf("floating-point division by zero") - } - return xf / y, nil - } - case Float: - switch y := y.(type) { - case Float: - if y == 0.0 { - return nil, fmt.Errorf("floating-point division by zero") - } - return x / y, nil - case Int: - yf, err := y.finiteFloat() - if err != nil { - return nil, err - } - if yf == 0.0 { - return nil, fmt.Errorf("floating-point division by zero") - } - return x / yf, nil - } - } - - case syntax.SLASHSLASH: - switch x := x.(type) { - case Int: - switch y := y.(type) { - case Int: - if y.Sign() == 0 { - return nil, fmt.Errorf("floored division by zero") - } - return x.Div(y), nil - case Float: - xf, err := x.finiteFloat() - if err != nil { - return nil, err - } - if y == 0.0 { - return nil, fmt.Errorf("floored division by zero") - } - return floor(xf / y), nil - } - case Float: - switch y := y.(type) { - case Float: - if y == 0.0 { - return nil, fmt.Errorf("floored division by zero") - } - return floor(x / y), nil - case Int: - yf, err := y.finiteFloat() - if err != nil { - return nil, err - } - if yf == 0.0 { - return nil, fmt.Errorf("floored division by zero") - } - return floor(x / yf), nil - } - } - - case syntax.PERCENT: - switch x := x.(type) { - case Int: - switch y := y.(type) { - case Int: - if y.Sign() == 0 { - return nil, fmt.Errorf("integer modulo by zero") - } - return x.Mod(y), nil - case Float: - xf, err := x.finiteFloat() - if err != nil { - return nil, err - } - if y == 0 { - return nil, fmt.Errorf("floating-point modulo by zero") - } - return xf.Mod(y), nil - } - case Float: - switch y := y.(type) { - case Float: - if y == 0.0 { - return nil, fmt.Errorf("floating-point modulo by zero") - } - return x.Mod(y), nil - case Int: - if y.Sign() == 0 { - return nil, fmt.Errorf("floating-point modulo by zero") - } - yf, err := y.finiteFloat() - if err != nil { - return nil, err - } - return x.Mod(yf), nil - } - case String: - return interpolate(string(x), y) - } - - case syntax.NOT_IN: - z, err := Binary(syntax.IN, x, y) - if err != nil { - return nil, err - } - return !z.Truth(), nil - - case syntax.IN: - switch y := y.(type) { - case *List: - for _, elem := range y.elems { - if eq, err := Equal(elem, x); err != nil { - return nil, err - } else if eq { - return True, nil - } - } - return False, nil - case Tuple: - for _, elem := range y { - if eq, err := Equal(elem, x); err != nil { - return nil, err - } else if eq { - return True, nil - } - } - return False, nil - case Mapping: // e.g. dict - // Ignore error from Get as we cannot distinguish true - // errors (value cycle, type error) from "key not found". - _, found, _ := y.Get(x) - return Bool(found), nil - case *Set: - ok, err := y.Has(x) - return Bool(ok), err - case String: - needle, ok := x.(String) - if !ok { - return nil, fmt.Errorf("'in ' requires string as left operand, not %s", x.Type()) - } - return Bool(strings.Contains(string(y), string(needle))), nil - case Bytes: - switch needle := x.(type) { - case Bytes: - return Bool(strings.Contains(string(y), string(needle))), nil - case Int: - var b byte - if err := AsInt(needle, &b); err != nil { - return nil, fmt.Errorf("int in bytes: %s", err) - } - return Bool(strings.IndexByte(string(y), b) >= 0), nil - default: - return nil, fmt.Errorf("'in bytes' requires bytes or int as left operand, not %s", x.Type()) - } - case rangeValue: - i, err := NumberToInt(x) - if err != nil { - return nil, fmt.Errorf("'in ' requires integer as left operand, not %s", x.Type()) - } - return Bool(y.contains(i)), nil - } - - case syntax.PIPE: - switch x := x.(type) { - case Int: - if y, ok := y.(Int); ok { - return x.Or(y), nil - } - - case *Dict: // union - if y, ok := y.(*Dict); ok { - return x.Union(y), nil - } - - case *Set: // union - if y, ok := y.(*Set); ok { - iter := Iterate(y) - defer iter.Done() - return x.Union(iter) - } - } - - case syntax.AMP: - switch x := x.(type) { - case Int: - if y, ok := y.(Int); ok { - return x.And(y), nil - } - case *Set: // intersection - if y, ok := y.(*Set); ok { - iter := y.Iterate() - defer iter.Done() - return x.Intersection(iter) - } - } - - case syntax.CIRCUMFLEX: - switch x := x.(type) { - case Int: - if y, ok := y.(Int); ok { - return x.Xor(y), nil - } - case *Set: // symmetric difference - if y, ok := y.(*Set); ok { - iter := y.Iterate() - defer iter.Done() - return x.SymmetricDifference(iter) - } - } - - case syntax.LTLT, syntax.GTGT: - if x, ok := x.(Int); ok { - y, err := AsInt32(y) - if err != nil { - return nil, err - } - if y < 0 { - return nil, fmt.Errorf("negative shift count: %v", y) - } - if op == syntax.LTLT { - if y >= 512 { - return nil, fmt.Errorf("shift count too large: %v", y) - } - return x.Lsh(uint(y)), nil - } else { - return x.Rsh(uint(y)), nil - } - } - - default: - // unknown operator - goto unknown - } - - // user-defined types - // (nil, nil) => unhandled - if x, ok := x.(HasBinary); ok { - z, err := x.Binary(op, y, Left) - if z != nil || err != nil { - return z, err - } - } - if y, ok := y.(HasBinary); ok { - z, err := y.Binary(op, x, Right) - if z != nil || err != nil { - return z, err - } - } - - // unsupported operand types -unknown: - return nil, fmt.Errorf("unknown binary op: %s %s %s", x.Type(), op, y.Type()) -} - -// It's always possible to overeat in small bites but we'll -// try to stop someone swallowing the world in one gulp. -const maxAlloc = 1 << 30 - -func tupleRepeat(elems Tuple, n Int) (Tuple, error) { - if len(elems) == 0 { - return nil, nil - } - i, err := AsInt32(n) - if err != nil { - return nil, fmt.Errorf("repeat count %s too large", n) - } - if i < 1 { - return nil, nil - } - // Inv: i > 0, len > 0 - sz := len(elems) * i - if sz < 0 || sz >= maxAlloc { // sz < 0 => overflow - // Don't print sz. - return nil, fmt.Errorf("excessive repeat (%d * %d elements)", len(elems), i) - } - res := make([]Value, sz) - // copy elems into res, doubling each time - x := copy(res, elems) - for x < len(res) { - copy(res[x:], res[:x]) - x *= 2 - } - return res, nil -} - -func bytesRepeat(b Bytes, n Int) (Bytes, error) { - res, err := stringRepeat(String(b), n) - return Bytes(res), err -} - -func stringRepeat(s String, n Int) (String, error) { - if s == "" { - return "", nil - } - i, err := AsInt32(n) - if err != nil { - return "", fmt.Errorf("repeat count %s too large", n) - } - if i < 1 { - return "", nil - } - // Inv: i > 0, len > 0 - sz := len(s) * i - if sz < 0 || sz >= maxAlloc { // sz < 0 => overflow - // Don't print sz. - return "", fmt.Errorf("excessive repeat (%d * %d elements)", len(s), i) - } - return String(strings.Repeat(string(s), i)), nil -} - -// Call calls the function fn with the specified positional and keyword arguments. -func Call(thread *Thread, fn Value, args Tuple, kwargs []Tuple) (Value, error) { - c, ok := fn.(Callable) - if !ok { - return nil, fmt.Errorf("invalid call of non-function (%s)", fn.Type()) - } - - // Allocate and push a new frame. - var fr *frame - // Optimization: use slack portion of thread.stack - // slice as a freelist of empty frames. - if n := len(thread.stack); n < cap(thread.stack) { - fr = thread.stack[n : n+1][0] - } - if fr == nil { - fr = new(frame) - } - - if thread.stack == nil { - // one-time initialization of thread - if thread.maxSteps == 0 { - thread.maxSteps-- // (MaxUint64) - } - } - - thread.stack = append(thread.stack, fr) // push - - fr.callable = c - - thread.beginProfSpan() - - // Use defer to ensure that panics from built-ins - // pass through the interpreter without leaving - // it in a bad state. - defer func() { - thread.endProfSpan() - - // clear out any references - // TODO(adonovan): opt: zero fr.Locals and - // reuse it if it is large enough. - *fr = frame{} - - thread.stack = thread.stack[:len(thread.stack)-1] // pop - }() - - result, err := c.CallInternal(thread, args, kwargs) - - // Sanity check: nil is not a valid Starlark value. - if result == nil && err == nil { - err = fmt.Errorf("internal error: nil (not None) returned from %s", fn) - } - - // Always return an EvalError with an accurate frame. - if err != nil { - if _, ok := err.(*EvalError); !ok { - err = thread.evalError(err) - } - } - - return result, err -} - -func slice(x, lo, hi, step_ Value) (Value, error) { - sliceable, ok := x.(Sliceable) - if !ok { - return nil, fmt.Errorf("invalid slice operand %s", x.Type()) - } - - n := sliceable.Len() - step := 1 - if step_ != None { - var err error - step, err = AsInt32(step_) - if err != nil { - return nil, fmt.Errorf("invalid slice step: %s", err) - } - if step == 0 { - return nil, fmt.Errorf("zero is not a valid slice step") - } - } - - // TODO(adonovan): opt: preallocate result array. - - var start, end int - if step > 0 { - // positive stride - // default indices are [0:n]. - var err error - start, end, err = indices(lo, hi, n) - if err != nil { - return nil, err - } - - if end < start { - end = start // => empty result - } - } else { - // negative stride - // default indices are effectively [n-1:-1], though to - // get this effect using explicit indices requires - // [n-1:-1-n:-1] because of the treatment of -ve values. - start = n - 1 - if err := asIndex(lo, n, &start); err != nil { - return nil, fmt.Errorf("invalid start index: %s", err) - } - if start >= n { - start = n - 1 - } - - end = -1 - if err := asIndex(hi, n, &end); err != nil { - return nil, fmt.Errorf("invalid end index: %s", err) - } - if end < -1 { - end = -1 - } - - if start < end { - start = end // => empty result - } - } - - return sliceable.Slice(start, end, step), nil -} - -// From Hacker's Delight, section 2.8. -func signum64(x int64) int { return int(uint64(x>>63) | uint64(-x)>>63) } -func signum(x int) int { return signum64(int64(x)) } - -// indices converts start_ and end_ to indices in the range [0:len]. -// The start index defaults to 0 and the end index defaults to len. -// An index -len < i < 0 is treated like i+len. -// All other indices outside the range are clamped to the nearest value in the range. -// Beware: start may be greater than end. -// This function is suitable only for slices with positive strides. -func indices(start_, end_ Value, len int) (start, end int, err error) { - start = 0 - if err := asIndex(start_, len, &start); err != nil { - return 0, 0, fmt.Errorf("invalid start index: %s", err) - } - // Clamp to [0:len]. - if start < 0 { - start = 0 - } else if start > len { - start = len - } - - end = len - if err := asIndex(end_, len, &end); err != nil { - return 0, 0, fmt.Errorf("invalid end index: %s", err) - } - // Clamp to [0:len]. - if end < 0 { - end = 0 - } else if end > len { - end = len - } - - return start, end, nil -} - -// asIndex sets *result to the integer value of v, adding len to it -// if it is negative. If v is nil or None, *result is unchanged. -func asIndex(v Value, len int, result *int) error { - if v != nil && v != None { - var err error - *result, err = AsInt32(v) - if err != nil { - return err - } - if *result < 0 { - *result += len - } - } - return nil -} - -// setArgs sets the values of the formal parameters of function fn in -// based on the actual parameter values in args and kwargs. -func setArgs(locals []Value, fn *Function, args Tuple, kwargs []Tuple) error { - - // This is the general schema of a function: - // - // def f(p1, p2=dp2, p3=dp3, *args, k1, k2=dk2, k3, **kwargs) - // - // The p parameters are non-kwonly, and may be specified positionally. - // The k parameters are kwonly, and must be specified by name. - // The defaults tuple is (dp2, dp3, mandatory, dk2, mandatory). - // - // Arguments are processed as follows: - // - positional arguments are bound to a prefix of [p1, p2, p3]. - // - surplus positional arguments are bound to *args. - // - keyword arguments are bound to any of {p1, p2, p3, k1, k2, k3}; - // duplicate bindings are rejected. - // - surplus keyword arguments are bound to **kwargs. - // - defaults are bound to each parameter from p2 to k3 if no value was set. - // default values come from the tuple above. - // It is an error if the tuple entry for an unset parameter is 'mandatory'. - - // Nullary function? - if fn.NumParams() == 0 { - if nactual := len(args) + len(kwargs); nactual > 0 { - return fmt.Errorf("function %s accepts no arguments (%d given)", fn.Name(), nactual) - } - return nil - } - - cond := func(x bool, y, z interface{}) interface{} { - if x { - return y - } - return z - } - - // nparams is the number of ordinary parameters (sans *args and **kwargs). - nparams := fn.NumParams() - var kwdict *Dict - if fn.HasKwargs() { - nparams-- - kwdict = new(Dict) - locals[nparams] = kwdict - } - if fn.HasVarargs() { - nparams-- - } - - // nonkwonly is the number of non-kwonly parameters. - nonkwonly := nparams - fn.NumKwonlyParams() - - // Too many positional args? - n := len(args) - if len(args) > nonkwonly { - if !fn.HasVarargs() { - return fmt.Errorf("function %s accepts %s%d positional argument%s (%d given)", - fn.Name(), - cond(len(fn.defaults) > fn.NumKwonlyParams(), "at most ", ""), - nonkwonly, - cond(nonkwonly == 1, "", "s"), - len(args)) - } - n = nonkwonly - } - - // Bind positional arguments to non-kwonly parameters. - for i := 0; i < n; i++ { - locals[i] = args[i] - } - - // Bind surplus positional arguments to *args parameter. - if fn.HasVarargs() { - tuple := make(Tuple, len(args)-n) - for i := n; i < len(args); i++ { - tuple[i-n] = args[i] - } - locals[nparams] = tuple - } - - // Bind keyword arguments to parameters. - paramIdents := fn.funcode.Locals[:nparams] - for _, pair := range kwargs { - k, v := pair[0].(String), pair[1] - if i := findParam(paramIdents, string(k)); i >= 0 { - if locals[i] != nil { - return fmt.Errorf("function %s got multiple values for parameter %s", fn.Name(), k) - } - locals[i] = v - continue - } - if kwdict == nil { - return fmt.Errorf("function %s got an unexpected keyword argument %s", fn.Name(), k) - } - oldlen := kwdict.Len() - kwdict.SetKey(k, v) - if kwdict.Len() == oldlen { - return fmt.Errorf("function %s got multiple values for parameter %s", fn.Name(), k) - } - } - - // Are defaults required? - if n < nparams || fn.NumKwonlyParams() > 0 { - m := nparams - len(fn.defaults) // first default - - // Report errors for missing required arguments. - var missing []string - var i int - for i = n; i < m; i++ { - if locals[i] == nil { - missing = append(missing, paramIdents[i].Name) - } - } - - // Bind default values to parameters. - for ; i < nparams; i++ { - if locals[i] == nil { - dflt := fn.defaults[i-m] - if _, ok := dflt.(mandatory); ok { - missing = append(missing, paramIdents[i].Name) - continue - } - locals[i] = dflt - } - } - - if missing != nil { - return fmt.Errorf("function %s missing %d argument%s (%s)", - fn.Name(), len(missing), cond(len(missing) > 1, "s", ""), strings.Join(missing, ", ")) - } - } - return nil -} - -func findParam(params []compile.Binding, name string) int { - for i, param := range params { - if param.Name == name { - return i - } - } - return -1 -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string-interpolation -func interpolate(format string, x Value) (Value, error) { - buf := new(strings.Builder) - index := 0 - nargs := 1 - if tuple, ok := x.(Tuple); ok { - nargs = len(tuple) - } - for { - i := strings.IndexByte(format, '%') - if i < 0 { - buf.WriteString(format) - break - } - buf.WriteString(format[:i]) - format = format[i+1:] - - if format != "" && format[0] == '%' { - buf.WriteByte('%') - format = format[1:] - continue - } - - var arg Value - if format != "" && format[0] == '(' { - // keyword argument: %(name)s. - format = format[1:] - j := strings.IndexByte(format, ')') - if j < 0 { - return nil, fmt.Errorf("incomplete format key") - } - key := format[:j] - if dict, ok := x.(Mapping); !ok { - return nil, fmt.Errorf("format requires a mapping") - } else if v, found, _ := dict.Get(String(key)); found { - arg = v - } else { - return nil, fmt.Errorf("key not found: %s", key) - } - format = format[j+1:] - } else { - // positional argument: %s. - if index >= nargs { - return nil, fmt.Errorf("not enough arguments for format string") - } - if tuple, ok := x.(Tuple); ok { - arg = tuple[index] - } else { - arg = x - } - } - - // NOTE: Starlark does not support any of these optional Python features: - // - optional conversion flags: [#0- +], etc. - // - optional minimum field width (number or *). - // - optional precision (.123 or *) - // - optional length modifier - - // conversion type - if format == "" { - return nil, fmt.Errorf("incomplete format") - } - switch c := format[0]; c { - case 's', 'r': - if str, ok := AsString(arg); ok && c == 's' { - buf.WriteString(str) - } else { - writeValue(buf, arg, nil) - } - case 'd', 'i', 'o', 'x', 'X': - i, err := NumberToInt(arg) - if err != nil { - return nil, fmt.Errorf("%%%c format requires integer: %v", c, err) - } - switch c { - case 'd', 'i': - fmt.Fprintf(buf, "%d", i) - case 'o': - fmt.Fprintf(buf, "%o", i) - case 'x': - fmt.Fprintf(buf, "%x", i) - case 'X': - fmt.Fprintf(buf, "%X", i) - } - case 'e', 'f', 'g', 'E', 'F', 'G': - f, ok := AsFloat(arg) - if !ok { - return nil, fmt.Errorf("%%%c format requires float, not %s", c, arg.Type()) - } - Float(f).format(buf, c) - case 'c': - switch arg := arg.(type) { - case Int: - // chr(int) - r, err := AsInt32(arg) - if err != nil || r < 0 || r > unicode.MaxRune { - return nil, fmt.Errorf("%%c format requires a valid Unicode code point, got %s", arg) - } - buf.WriteRune(rune(r)) - case String: - r, size := utf8.DecodeRuneInString(string(arg)) - if size != len(arg) || len(arg) == 0 { - return nil, fmt.Errorf("%%c format requires a single-character string") - } - buf.WriteRune(r) - default: - return nil, fmt.Errorf("%%c format requires int or single-character string, not %s", arg.Type()) - } - case '%': - buf.WriteByte('%') - default: - return nil, fmt.Errorf("unknown conversion %%%c", c) - } - format = format[1:] - index++ - } - - if index < nargs && !is[Mapping](x) { - return nil, fmt.Errorf("too many arguments for format string") - } - - return String(buf.String()), nil -} - -func is[T any](x any) bool { - _, ok := x.(T) - return ok -} diff --git a/tests/vendor/go.starlark.net/starlark/hashtable.go b/tests/vendor/go.starlark.net/starlark/hashtable.go deleted file mode 100644 index 40f72bb63..000000000 --- a/tests/vendor/go.starlark.net/starlark/hashtable.go +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package starlark - -import ( - "fmt" - "math/big" - _ "unsafe" // for go:linkname hack -) - -// hashtable is used to represent Starlark dict and set values. -// It is a hash table whose key/value entries form a doubly-linked list -// in the order the entries were inserted. -// -// Initialized instances of hashtable must not be copied. -type hashtable struct { - table []bucket // len is zero or a power of two - bucket0 [1]bucket // inline allocation for small maps. - len uint32 - itercount uint32 // number of active iterators (ignored if frozen) - head *entry // insertion order doubly-linked list; may be nil - tailLink **entry // address of nil link at end of list (perhaps &head) - frozen bool - - _ noCopy // triggers vet copylock check on this type. -} - -// noCopy is zero-sized type that triggers vet's copylock check. -// See https://github.com/golang/go/issues/8005#issuecomment-190753527. -type noCopy struct{} - -func (*noCopy) Lock() {} -func (*noCopy) Unlock() {} - -const bucketSize = 8 - -type bucket struct { - entries [bucketSize]entry - next *bucket // linked list of buckets -} - -type entry struct { - hash uint32 // nonzero => in use - key, value Value - next *entry // insertion order doubly-linked list; may be nil - prevLink **entry // address of link to this entry (perhaps &head) -} - -func (ht *hashtable) init(size int) { - if size < 0 { - panic("size < 0") - } - nb := 1 - for overloaded(size, nb) { - nb = nb << 1 - } - if nb < 2 { - ht.table = ht.bucket0[:1] - } else { - ht.table = make([]bucket, nb) - } - ht.tailLink = &ht.head -} - -func (ht *hashtable) freeze() { - if !ht.frozen { - ht.frozen = true - for e := ht.head; e != nil; e = e.next { - e.key.Freeze() - e.value.Freeze() - } - } -} - -func (ht *hashtable) insert(k, v Value) error { - if err := ht.checkMutable("insert into"); err != nil { - return err - } - if ht.table == nil { - ht.init(1) - } - h, err := k.Hash() - if err != nil { - return err - } - if h == 0 { - h = 1 // zero is reserved - } - -retry: - var insert *entry - - // Inspect each bucket in the bucket list. - p := &ht.table[h&(uint32(len(ht.table)-1))] - for { - for i := range p.entries { - e := &p.entries[i] - if e.hash != h { - if e.hash == 0 { - // Found empty entry; make a note. - insert = e - } - continue - } - if eq, err := Equal(k, e.key); err != nil { - return err // e.g. excessively recursive tuple - } else if !eq { - continue - } - // Key already present; update value. - e.value = v - return nil - } - if p.next == nil { - break - } - p = p.next - } - - // Key not found. p points to the last bucket. - - // Does the number of elements exceed the buckets' load factor? - if overloaded(int(ht.len), len(ht.table)) { - ht.grow() - goto retry - } - - if insert == nil { - // No space in existing buckets. Add a new one to the bucket list. - b := new(bucket) - p.next = b - insert = &b.entries[0] - } - - // Insert key/value pair. - insert.hash = h - insert.key = k - insert.value = v - - // Append entry to doubly-linked list. - insert.prevLink = ht.tailLink - *ht.tailLink = insert - ht.tailLink = &insert.next - - ht.len++ - - return nil -} - -func overloaded(elems, buckets int) bool { - const loadFactor = 6.5 // just a guess - return elems >= bucketSize && float64(elems) >= loadFactor*float64(buckets) -} - -func (ht *hashtable) grow() { - // Double the number of buckets and rehash. - // - // Even though this makes reentrant calls to ht.insert, - // calls Equals unnecessarily (since there can't be duplicate keys), - // and recomputes the hash unnecessarily, the gains from - // avoiding these steps were found to be too small to justify - // the extra logic: -2% on hashtable benchmark. - ht.table = make([]bucket, len(ht.table)<<1) - oldhead := ht.head - ht.head = nil - ht.tailLink = &ht.head - ht.len = 0 - for e := oldhead; e != nil; e = e.next { - ht.insert(e.key, e.value) - } - ht.bucket0[0] = bucket{} // clear out unused initial bucket -} - -func (ht *hashtable) lookup(k Value) (v Value, found bool, err error) { - h, err := k.Hash() - if err != nil { - return nil, false, err // unhashable - } - if h == 0 { - h = 1 // zero is reserved - } - if ht.table == nil { - return None, false, nil // empty - } - - // Inspect each bucket in the bucket list. - for p := &ht.table[h&(uint32(len(ht.table)-1))]; p != nil; p = p.next { - for i := range p.entries { - e := &p.entries[i] - if e.hash == h { - if eq, err := Equal(k, e.key); err != nil { - return nil, false, err // e.g. excessively recursive tuple - } else if eq { - return e.value, true, nil // found - } - } - } - } - return None, false, nil // not found -} - -// count returns the number of distinct elements of iter that are elements of ht. -func (ht *hashtable) count(iter Iterator) (int, error) { - if ht.table == nil { - return 0, nil // empty - } - - var k Value - count := 0 - - // Use a bitset per table entry to record seen elements of ht. - // Elements are identified by their bucket number and index within the bucket. - // Each bitset gets one word initially, but may grow. - storage := make([]big.Word, len(ht.table)) - bitsets := make([]big.Int, len(ht.table)) - for i := range bitsets { - bitsets[i].SetBits(storage[i : i+1 : i+1]) - } - for iter.Next(&k) && count != int(ht.len) { - h, err := k.Hash() - if err != nil { - return 0, err // unhashable - } - if h == 0 { - h = 1 // zero is reserved - } - - // Inspect each bucket in the bucket list. - bucketId := h & (uint32(len(ht.table) - 1)) - i := 0 - for p := &ht.table[bucketId]; p != nil; p = p.next { - for j := range p.entries { - e := &p.entries[j] - if e.hash == h { - if eq, err := Equal(k, e.key); err != nil { - return 0, err - } else if eq { - bitIndex := i<<3 + j - if bitsets[bucketId].Bit(bitIndex) == 0 { - bitsets[bucketId].SetBit(&bitsets[bucketId], bitIndex, 1) - count++ - } - } - } - } - i++ - } - } - - return count, nil -} - -// Items returns all the items in the map (as key/value pairs) in insertion order. -func (ht *hashtable) items() []Tuple { - items := make([]Tuple, 0, ht.len) - array := make([]Value, ht.len*2) // allocate a single backing array - for e := ht.head; e != nil; e = e.next { - pair := Tuple(array[:2:2]) - array = array[2:] - pair[0] = e.key - pair[1] = e.value - items = append(items, pair) - } - return items -} - -func (ht *hashtable) first() (Value, bool) { - if ht.head != nil { - return ht.head.key, true - } - return None, false -} - -func (ht *hashtable) keys() []Value { - keys := make([]Value, 0, ht.len) - for e := ht.head; e != nil; e = e.next { - keys = append(keys, e.key) - } - return keys -} - -func (ht *hashtable) delete(k Value) (v Value, found bool, err error) { - if err := ht.checkMutable("delete from"); err != nil { - return nil, false, err - } - if ht.table == nil { - return None, false, nil // empty - } - h, err := k.Hash() - if err != nil { - return nil, false, err // unhashable - } - if h == 0 { - h = 1 // zero is reserved - } - - // Inspect each bucket in the bucket list. - for p := &ht.table[h&(uint32(len(ht.table)-1))]; p != nil; p = p.next { - for i := range p.entries { - e := &p.entries[i] - if e.hash == h { - if eq, err := Equal(k, e.key); err != nil { - return nil, false, err - } else if eq { - // Remove e from doubly-linked list. - *e.prevLink = e.next - if e.next == nil { - ht.tailLink = e.prevLink // deletion of last entry - } else { - e.next.prevLink = e.prevLink - } - - v := e.value - *e = entry{} - ht.len-- - return v, true, nil // found - } - } - } - } - - // TODO(adonovan): opt: remove completely empty bucket from bucket list. - - return None, false, nil // not found -} - -// checkMutable reports an error if the hash table should not be mutated. -// verb+" dict" should describe the operation. -func (ht *hashtable) checkMutable(verb string) error { - if ht.frozen { - return fmt.Errorf("cannot %s frozen hash table", verb) - } - if ht.itercount > 0 { - return fmt.Errorf("cannot %s hash table during iteration", verb) - } - return nil -} - -func (ht *hashtable) clear() error { - if err := ht.checkMutable("clear"); err != nil { - return err - } - if ht.table != nil { - for i := range ht.table { - ht.table[i] = bucket{} - } - } - ht.head = nil - ht.tailLink = &ht.head - ht.len = 0 - return nil -} - -func (ht *hashtable) addAll(other *hashtable) error { - for e := other.head; e != nil; e = e.next { - if err := ht.insert(e.key, e.value); err != nil { - return err - } - } - return nil -} - -// dump is provided as an aid to debugging. -func (ht *hashtable) dump() { - fmt.Printf("hashtable %p len=%d head=%p tailLink=%p", - ht, ht.len, ht.head, ht.tailLink) - if ht.tailLink != nil { - fmt.Printf(" *tailLink=%p", *ht.tailLink) - } - fmt.Println() - for j := range ht.table { - fmt.Printf("bucket chain %d\n", j) - for p := &ht.table[j]; p != nil; p = p.next { - fmt.Printf("bucket %p\n", p) - for i := range p.entries { - e := &p.entries[i] - fmt.Printf("\tentry %d @ %p hash=%d key=%v value=%v\n", - i, e, e.hash, e.key, e.value) - fmt.Printf("\t\tnext=%p &next=%p prev=%p", - e.next, &e.next, e.prevLink) - if e.prevLink != nil { - fmt.Printf(" *prev=%p", *e.prevLink) - } - fmt.Println() - } - } - } -} - -func (ht *hashtable) iterate() *keyIterator { - if !ht.frozen { - ht.itercount++ - } - return &keyIterator{ht: ht, e: ht.head} -} - -type keyIterator struct { - ht *hashtable - e *entry -} - -func (it *keyIterator) Next(k *Value) bool { - if it.e != nil { - *k = it.e.key - it.e = it.e.next - return true - } - return false -} - -func (it *keyIterator) Done() { - if !it.ht.frozen { - it.ht.itercount-- - } -} - -// TODO(adonovan): use go1.19's maphash.String. - -// hashString computes the hash of s. -func hashString(s string) uint32 { - if len(s) >= 12 { - // Call the Go runtime's optimized hash implementation, - // which uses the AESENC instruction on amd64 machines. - return uint32(goStringHash(s, 0)) - } - return softHashString(s) -} - -//go:linkname goStringHash runtime.stringHash -func goStringHash(s string, seed uintptr) uintptr - -// softHashString computes the 32-bit FNV-1a hash of s in software. -func softHashString(s string) uint32 { - var h uint32 = 2166136261 - for i := 0; i < len(s); i++ { - h ^= uint32(s[i]) - h *= 16777619 - } - return h -} diff --git a/tests/vendor/go.starlark.net/starlark/int.go b/tests/vendor/go.starlark.net/starlark/int.go deleted file mode 100644 index 8f2b279c7..000000000 --- a/tests/vendor/go.starlark.net/starlark/int.go +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package starlark - -import ( - "fmt" - "math" - "math/big" - "reflect" - "strconv" - - "go.starlark.net/syntax" -) - -// Int is the type of a Starlark int. -// -// The zero value is not a legal value; use MakeInt(0). -type Int struct{ impl intImpl } - -// --- high-level accessors --- - -// MakeInt returns a Starlark int for the specified signed integer. -func MakeInt(x int) Int { return MakeInt64(int64(x)) } - -// MakeInt64 returns a Starlark int for the specified int64. -func MakeInt64(x int64) Int { - if math.MinInt32 <= x && x <= math.MaxInt32 { - return makeSmallInt(x) - } - return makeBigInt(big.NewInt(x)) -} - -// MakeUint returns a Starlark int for the specified unsigned integer. -func MakeUint(x uint) Int { return MakeUint64(uint64(x)) } - -// MakeUint64 returns a Starlark int for the specified uint64. -func MakeUint64(x uint64) Int { - if x <= math.MaxInt32 { - return makeSmallInt(int64(x)) - } - return makeBigInt(new(big.Int).SetUint64(x)) -} - -// MakeBigInt returns a Starlark int for the specified big.Int. -// The new Int value will contain a copy of x. The caller is safe to modify x. -func MakeBigInt(x *big.Int) Int { - if isSmall(x) { - return makeSmallInt(x.Int64()) - } - z := new(big.Int).Set(x) - return makeBigInt(z) -} - -func isSmall(x *big.Int) bool { - n := x.BitLen() - return n < 32 || n == 32 && x.Int64() == math.MinInt32 -} - -var ( - zero, one = makeSmallInt(0), makeSmallInt(1) - oneBig = big.NewInt(1) - - _ HasUnary = Int{} -) - -// Unary implements the operations +int, -int, and ~int. -func (i Int) Unary(op syntax.Token) (Value, error) { - switch op { - case syntax.MINUS: - return zero.Sub(i), nil - case syntax.PLUS: - return i, nil - case syntax.TILDE: - return i.Not(), nil - } - return nil, nil -} - -// Int64 returns the value as an int64. -// If it is not exactly representable the result is undefined and ok is false. -func (i Int) Int64() (_ int64, ok bool) { - iSmall, iBig := i.get() - if iBig != nil { - x, acc := bigintToInt64(iBig) - if acc != big.Exact { - return // inexact - } - return x, true - } - return iSmall, true -} - -// BigInt returns a new big.Int with the same value as the Int. -func (i Int) BigInt() *big.Int { - iSmall, iBig := i.get() - if iBig != nil { - return new(big.Int).Set(iBig) - } - return big.NewInt(iSmall) -} - -// bigInt returns the value as a big.Int. -// It differs from BigInt in that this method returns the actual -// reference and any modification will change the state of i. -func (i Int) bigInt() *big.Int { - iSmall, iBig := i.get() - if iBig != nil { - return iBig - } - return big.NewInt(iSmall) -} - -// Uint64 returns the value as a uint64. -// If it is not exactly representable the result is undefined and ok is false. -func (i Int) Uint64() (_ uint64, ok bool) { - iSmall, iBig := i.get() - if iBig != nil { - x, acc := bigintToUint64(iBig) - if acc != big.Exact { - return // inexact - } - return x, true - } - if iSmall < 0 { - return // inexact - } - return uint64(iSmall), true -} - -// The math/big API should provide this function. -func bigintToInt64(i *big.Int) (int64, big.Accuracy) { - sign := i.Sign() - if sign > 0 { - if i.Cmp(maxint64) > 0 { - return math.MaxInt64, big.Below - } - } else if sign < 0 { - if i.Cmp(minint64) < 0 { - return math.MinInt64, big.Above - } - } - return i.Int64(), big.Exact -} - -// The math/big API should provide this function. -func bigintToUint64(i *big.Int) (uint64, big.Accuracy) { - sign := i.Sign() - if sign > 0 { - if i.BitLen() > 64 { - return math.MaxUint64, big.Below - } - } else if sign < 0 { - return 0, big.Above - } - return i.Uint64(), big.Exact -} - -var ( - minint64 = new(big.Int).SetInt64(math.MinInt64) - maxint64 = new(big.Int).SetInt64(math.MaxInt64) -) - -func (i Int) Format(s fmt.State, ch rune) { - iSmall, iBig := i.get() - if iBig != nil { - iBig.Format(s, ch) - return - } - big.NewInt(iSmall).Format(s, ch) -} -func (i Int) String() string { - iSmall, iBig := i.get() - if iBig != nil { - return iBig.Text(10) - } - return strconv.FormatInt(iSmall, 10) -} -func (i Int) Type() string { return "int" } -func (i Int) Freeze() {} // immutable -func (i Int) Truth() Bool { return i.Sign() != 0 } -func (i Int) Hash() (uint32, error) { - iSmall, iBig := i.get() - var lo big.Word - if iBig != nil { - lo = iBig.Bits()[0] - } else { - lo = big.Word(iSmall) - } - return 12582917 * uint32(lo+3), nil -} - -// Cmp implements comparison of two Int values. -// Required by the TotallyOrdered interface. -func (i Int) Cmp(v Value, depth int) (int, error) { - j := v.(Int) - iSmall, iBig := i.get() - jSmall, jBig := j.get() - if iBig != nil || jBig != nil { - return i.bigInt().Cmp(j.bigInt()), nil - } - return signum64(iSmall - jSmall), nil // safe: int32 operands -} - -// Float returns the float value nearest i. -func (i Int) Float() Float { - iSmall, iBig := i.get() - if iBig != nil { - // Fast path for hardware int-to-float conversions. - if iBig.IsUint64() { - return Float(iBig.Uint64()) - } else if iBig.IsInt64() { - return Float(iBig.Int64()) - } else { - // Fast path for very big ints. - const maxFiniteLen = 1023 + 1 // max exponent value + implicit mantissa bit - if iBig.BitLen() > maxFiniteLen { - return Float(math.Inf(iBig.Sign())) - } - } - - f, _ := new(big.Float).SetInt(iBig).Float64() - return Float(f) - } - return Float(iSmall) -} - -// finiteFloat returns the finite float value nearest i, -// or an error if the magnitude is too large. -func (i Int) finiteFloat() (Float, error) { - f := i.Float() - if math.IsInf(float64(f), 0) { - return 0, fmt.Errorf("int too large to convert to float") - } - return f, nil -} - -func (x Int) Sign() int { - xSmall, xBig := x.get() - if xBig != nil { - return xBig.Sign() - } - return signum64(xSmall) -} - -func (x Int) Add(y Int) Int { - xSmall, xBig := x.get() - ySmall, yBig := y.get() - if xBig != nil || yBig != nil { - return MakeBigInt(new(big.Int).Add(x.bigInt(), y.bigInt())) - } - return MakeInt64(xSmall + ySmall) -} -func (x Int) Sub(y Int) Int { - xSmall, xBig := x.get() - ySmall, yBig := y.get() - if xBig != nil || yBig != nil { - return MakeBigInt(new(big.Int).Sub(x.bigInt(), y.bigInt())) - } - return MakeInt64(xSmall - ySmall) -} -func (x Int) Mul(y Int) Int { - xSmall, xBig := x.get() - ySmall, yBig := y.get() - if xBig != nil || yBig != nil { - return MakeBigInt(new(big.Int).Mul(x.bigInt(), y.bigInt())) - } - return MakeInt64(xSmall * ySmall) -} -func (x Int) Or(y Int) Int { - xSmall, xBig := x.get() - ySmall, yBig := y.get() - if xBig != nil || yBig != nil { - return MakeBigInt(new(big.Int).Or(x.bigInt(), y.bigInt())) - } - return makeSmallInt(xSmall | ySmall) -} -func (x Int) And(y Int) Int { - xSmall, xBig := x.get() - ySmall, yBig := y.get() - if xBig != nil || yBig != nil { - return MakeBigInt(new(big.Int).And(x.bigInt(), y.bigInt())) - } - return makeSmallInt(xSmall & ySmall) -} -func (x Int) Xor(y Int) Int { - xSmall, xBig := x.get() - ySmall, yBig := y.get() - if xBig != nil || yBig != nil { - return MakeBigInt(new(big.Int).Xor(x.bigInt(), y.bigInt())) - } - return makeSmallInt(xSmall ^ ySmall) -} -func (x Int) Not() Int { - xSmall, xBig := x.get() - if xBig != nil { - return MakeBigInt(new(big.Int).Not(xBig)) - } - return makeSmallInt(^xSmall) -} -func (x Int) Lsh(y uint) Int { return MakeBigInt(new(big.Int).Lsh(x.bigInt(), y)) } -func (x Int) Rsh(y uint) Int { return MakeBigInt(new(big.Int).Rsh(x.bigInt(), y)) } - -// Precondition: y is nonzero. -func (x Int) Div(y Int) Int { - xSmall, xBig := x.get() - ySmall, yBig := y.get() - // http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html - if xBig != nil || yBig != nil { - xb, yb := x.bigInt(), y.bigInt() - - var quo, rem big.Int - quo.QuoRem(xb, yb, &rem) - if (xb.Sign() < 0) != (yb.Sign() < 0) && rem.Sign() != 0 { - quo.Sub(&quo, oneBig) - } - return MakeBigInt(&quo) - } - quo := xSmall / ySmall - rem := xSmall % ySmall - if (xSmall < 0) != (ySmall < 0) && rem != 0 { - quo -= 1 - } - return MakeInt64(quo) -} - -// Precondition: y is nonzero. -func (x Int) Mod(y Int) Int { - xSmall, xBig := x.get() - ySmall, yBig := y.get() - if xBig != nil || yBig != nil { - xb, yb := x.bigInt(), y.bigInt() - - var quo, rem big.Int - quo.QuoRem(xb, yb, &rem) - if (xb.Sign() < 0) != (yb.Sign() < 0) && rem.Sign() != 0 { - rem.Add(&rem, yb) - } - return MakeBigInt(&rem) - } - rem := xSmall % ySmall - if (xSmall < 0) != (ySmall < 0) && rem != 0 { - rem += ySmall - } - return makeSmallInt(rem) -} - -func (i Int) rational() *big.Rat { - iSmall, iBig := i.get() - if iBig != nil { - return new(big.Rat).SetInt(iBig) - } - return new(big.Rat).SetInt64(iSmall) -} - -// AsInt32 returns the value of x if is representable as an int32. -func AsInt32(x Value) (int, error) { - i, ok := x.(Int) - if !ok { - return 0, fmt.Errorf("got %s, want int", x.Type()) - } - iSmall, iBig := i.get() - if iBig != nil { - return 0, fmt.Errorf("%s out of range", i) - } - return int(iSmall), nil -} - -// AsInt sets *ptr to the value of Starlark int x, if it is exactly representable, -// otherwise it returns an error. -// The type of ptr must be one of the pointer types *int, *int8, *int16, *int32, or *int64, -// or one of their unsigned counterparts including *uintptr. -func AsInt(x Value, ptr interface{}) error { - xint, ok := x.(Int) - if !ok { - return fmt.Errorf("got %s, want int", x.Type()) - } - - bits := reflect.TypeOf(ptr).Elem().Size() * 8 - switch ptr.(type) { - case *int, *int8, *int16, *int32, *int64: - i, ok := xint.Int64() - if !ok || bits < 64 && !(-1<<(bits-1) <= i && i < 1<<(bits-1)) { - return fmt.Errorf("%s out of range (want value in signed %d-bit range)", xint, bits) - } - switch ptr := ptr.(type) { - case *int: - *ptr = int(i) - case *int8: - *ptr = int8(i) - case *int16: - *ptr = int16(i) - case *int32: - *ptr = int32(i) - case *int64: - *ptr = int64(i) - } - - case *uint, *uint8, *uint16, *uint32, *uint64, *uintptr: - i, ok := xint.Uint64() - if !ok || bits < 64 && i >= 1< value is not representable as int32 -} - -// --- low-level accessors --- - -// get returns the small and big components of the Int. -// small is defined only if big is nil. -// small is sign-extended to 64 bits for ease of subsequent arithmetic. -func (i Int) get() (small int64, big *big.Int) { - return i.impl.small_, i.impl.big_ -} - -// Precondition: math.MinInt32 <= x && x <= math.MaxInt32 -func makeSmallInt(x int64) Int { - return Int{intImpl{small_: x}} -} - -// Precondition: x cannot be represented as int32. -func makeBigInt(x *big.Int) Int { - return Int{intImpl{big_: x}} -} diff --git a/tests/vendor/go.starlark.net/starlark/int_posix64.go b/tests/vendor/go.starlark.net/starlark/int_posix64.go deleted file mode 100644 index 70c949efc..000000000 --- a/tests/vendor/go.starlark.net/starlark/int_posix64.go +++ /dev/null @@ -1,89 +0,0 @@ -//go:build (linux || darwin || dragonfly || freebsd || netbsd || solaris) && (amd64 || arm64 || mips64x || ppc64 || ppc64le || loong64 || s390x) - -package starlark - -// This file defines an optimized Int implementation for 64-bit machines -// running POSIX. It reserves a 4GB portion of the address space using -// mmap and represents int32 values as addresses within that range. This -// disambiguates int32 values from *big.Int pointers, letting all Int -// values be represented as an unsafe.Pointer, so that Int-to-Value -// interface conversion need not allocate. - -// Although iOS (which, like macOS, appears as darwin/arm64) is -// POSIX-compliant, it limits each process to about 700MB of virtual -// address space, which defeats the optimization. Similarly, -// OpenBSD's default ulimit for virtual memory is a measly GB or so. -// On both those platforms the attempted optimization will fail and -// fall back to the slow implementation. - -// An alternative approach to this optimization would be to embed the -// int32 values in pointers using odd values, which can be distinguished -// from (even) *big.Int pointers. However, the Go runtime does not allow -// user programs to manufacture pointers to arbitrary locations such as -// within the zero page, or non-span, non-mmap, non-stack locations, -// and it may panic if it encounters them; see Issue #382. - -import ( - "log" - "math" - "math/big" - "unsafe" - - "golang.org/x/sys/unix" -) - -// intImpl represents a union of (int32, *big.Int) in a single pointer, -// so that Int-to-Value conversions need not allocate. -// -// The pointer is either a *big.Int, if the value is big, or a pointer into a -// reserved portion of the address space (smallints), if the value is small -// and the address space allocation succeeded. -// -// See int_generic.go for the basic representation concepts. -type intImpl unsafe.Pointer - -// get returns the (small, big) arms of the union. -func (i Int) get() (int64, *big.Int) { - if smallints == 0 { - // optimization disabled - if x := (*big.Int)(i.impl); isSmall(x) { - return x.Int64(), nil - } else { - return 0, x - } - } - - if ptr := uintptr(i.impl); ptr >= smallints && ptr < smallints+1<<32 { - return math.MinInt32 + int64(ptr-smallints), nil - } - return 0, (*big.Int)(i.impl) -} - -// Precondition: math.MinInt32 <= x && x <= math.MaxInt32 -func makeSmallInt(x int64) Int { - if smallints == 0 { - // optimization disabled - return Int{intImpl(big.NewInt(x))} - } - - return Int{intImpl(uintptr(x-math.MinInt32) + smallints)} -} - -// Precondition: x cannot be represented as int32. -func makeBigInt(x *big.Int) Int { return Int{intImpl(x)} } - -// smallints is the base address of a 2^32 byte memory region. -// Pointers to addresses in this region represent int32 values. -// We assume smallints is not at the very top of the address space. -// -// Zero means the optimization is disabled and all Ints allocate a big.Int. -var smallints = reserveAddresses(1 << 32) - -func reserveAddresses(len int) uintptr { - b, err := unix.Mmap(-1, 0, len, unix.PROT_READ, unix.MAP_PRIVATE|unix.MAP_ANON) - if err != nil { - log.Printf("Starlark failed to allocate 4GB address space: %v. Integer performance may suffer.", err) - return 0 // optimization disabled - } - return uintptr(unsafe.Pointer(&b[0])) -} diff --git a/tests/vendor/go.starlark.net/starlark/interp.go b/tests/vendor/go.starlark.net/starlark/interp.go deleted file mode 100644 index d29e52530..000000000 --- a/tests/vendor/go.starlark.net/starlark/interp.go +++ /dev/null @@ -1,704 +0,0 @@ -package starlark - -// This file defines the bytecode interpreter. - -import ( - "fmt" - "os" - "sync/atomic" - "unsafe" - - "go.starlark.net/internal/compile" - "go.starlark.net/internal/spell" - "go.starlark.net/syntax" -) - -const vmdebug = false // TODO(adonovan): use a bitfield of specific kinds of error. - -// TODO(adonovan): -// - optimize position table. -// - opt: record MaxIterStack during compilation and preallocate the stack. - -func (fn *Function) CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) { - // Postcondition: args is not mutated. This is stricter than required by Callable, - // but allows CALL to avoid a copy. - - f := fn.funcode - if !f.Prog.Recursion { - // detect recursion - for _, fr := range thread.stack[:len(thread.stack)-1] { - // We look for the same function code, - // not function value, otherwise the user could - // defeat the check by writing the Y combinator. - if frfn, ok := fr.Callable().(*Function); ok && frfn.funcode == f { - return nil, fmt.Errorf("function %s called recursively", fn.Name()) - } - } - } - - fr := thread.frameAt(0) - - // Allocate space for stack and locals. - // Logically these do not escape from this frame - // (See https://github.com/golang/go/issues/20533.) - // - // This heap allocation looks expensive, but I was unable to get - // more than 1% real time improvement in a large alloc-heavy - // benchmark (in which this alloc was 8% of alloc-bytes) - // by allocating space for 8 Values in each frame, or - // by allocating stack by slicing an array held by the Thread - // that is expanded in chunks of min(k, nspace), for k=256 or 1024. - nlocals := len(f.Locals) - nspace := nlocals + f.MaxStack - space := make([]Value, nspace) - locals := space[:nlocals:nlocals] // local variables, starting with parameters - stack := space[nlocals:] // operand stack - - // Digest arguments and set parameters. - err := setArgs(locals, fn, args, kwargs) - if err != nil { - return nil, thread.evalError(err) - } - - fr.locals = locals - - if vmdebug { - fmt.Printf("Entering %s @ %s\n", f.Name, f.Position(0)) - fmt.Printf("%d stack, %d locals\n", len(stack), len(locals)) - defer fmt.Println("Leaving ", f.Name) - } - - // Spill indicated locals to cells. - // Each cell is a separate alloc to avoid spurious liveness. - for _, index := range f.Cells { - locals[index] = &cell{locals[index]} - } - - // TODO(adonovan): add static check that beneath this point - // - there is exactly one return statement - // - there is no redefinition of 'err'. - - var iterstack []Iterator // stack of active iterators - - // Use defer so that application panics can pass through - // interpreter without leaving thread in a bad state. - defer func() { - // ITERPOP the rest of the iterator stack. - for _, iter := range iterstack { - iter.Done() - } - - fr.locals = nil - }() - - sp := 0 - var pc uint32 - var result Value - code := f.Code -loop: - for { - thread.Steps++ - if thread.Steps >= thread.maxSteps { - if thread.OnMaxSteps != nil { - thread.OnMaxSteps(thread) - } else { - thread.Cancel("too many steps") - } - } - if reason := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&thread.cancelReason))); reason != nil { - err = fmt.Errorf("Starlark computation cancelled: %s", *(*string)(reason)) - break loop - } - - fr.pc = pc - - op := compile.Opcode(code[pc]) - pc++ - var arg uint32 - if op >= compile.OpcodeArgMin { - // TODO(adonovan): opt: profile this. - // Perhaps compiling big endian would be less work to decode? - for s := uint(0); ; s += 7 { - b := code[pc] - pc++ - arg |= uint32(b&0x7f) << s - if b < 0x80 { - break - } - } - } - if vmdebug { - fmt.Fprintln(os.Stderr, stack[:sp]) // very verbose! - compile.PrintOp(f, fr.pc, op, arg) - } - - switch op { - case compile.NOP: - // nop - - case compile.DUP: - stack[sp] = stack[sp-1] - sp++ - - case compile.DUP2: - stack[sp] = stack[sp-2] - stack[sp+1] = stack[sp-1] - sp += 2 - - case compile.POP: - sp-- - - case compile.EXCH: - stack[sp-2], stack[sp-1] = stack[sp-1], stack[sp-2] - - case compile.EQL, compile.NEQ, compile.GT, compile.LT, compile.LE, compile.GE: - op := syntax.Token(op-compile.EQL) + syntax.EQL - y := stack[sp-1] - x := stack[sp-2] - sp -= 2 - ok, err2 := Compare(op, x, y) - if err2 != nil { - err = err2 - break loop - } - stack[sp] = Bool(ok) - sp++ - - case compile.PLUS, - compile.MINUS, - compile.STAR, - compile.SLASH, - compile.SLASHSLASH, - compile.PERCENT, - compile.AMP, - compile.PIPE, - compile.CIRCUMFLEX, - compile.LTLT, - compile.GTGT, - compile.IN: - binop := syntax.Token(op-compile.PLUS) + syntax.PLUS - if op == compile.IN { - binop = syntax.IN // IN token is out of order - } - y := stack[sp-1] - x := stack[sp-2] - sp -= 2 - z, err2 := Binary(binop, x, y) - if err2 != nil { - err = err2 - break loop - } - stack[sp] = z - sp++ - - case compile.UPLUS, compile.UMINUS, compile.TILDE: - var unop syntax.Token - if op == compile.TILDE { - unop = syntax.TILDE - } else { - unop = syntax.Token(op-compile.UPLUS) + syntax.PLUS - } - x := stack[sp-1] - y, err2 := Unary(unop, x) - if err2 != nil { - err = err2 - break loop - } - stack[sp-1] = y - - case compile.INPLACE_ADD: - y := stack[sp-1] - x := stack[sp-2] - sp -= 2 - - // It's possible that y is not Iterable but - // nonetheless defines x+y, in which case we - // should fall back to the general case. - var z Value - if xlist, ok := x.(*List); ok { - if yiter, ok := y.(Iterable); ok { - if err = xlist.checkMutable("apply += to"); err != nil { - break loop - } - listExtend(xlist, yiter) - z = xlist - } - } - if z == nil { - z, err = Binary(syntax.PLUS, x, y) - if err != nil { - break loop - } - } - - stack[sp] = z - sp++ - - case compile.INPLACE_PIPE: - y := stack[sp-1] - x := stack[sp-2] - sp -= 2 - - // It's possible that y is not Dict but - // nonetheless defines x|y, in which case we - // should fall back to the general case. - var z Value - if xdict, ok := x.(*Dict); ok { - if ydict, ok := y.(*Dict); ok { - if err = xdict.ht.checkMutable("apply |= to"); err != nil { - break loop - } - xdict.ht.addAll(&ydict.ht) // can't fail - z = xdict - } - } - if z == nil { - z, err = Binary(syntax.PIPE, x, y) - if err != nil { - break loop - } - } - - stack[sp] = z - sp++ - - case compile.NONE: - stack[sp] = None - sp++ - - case compile.TRUE: - stack[sp] = True - sp++ - - case compile.FALSE: - stack[sp] = False - sp++ - - case compile.MANDATORY: - stack[sp] = mandatory{} - sp++ - - case compile.JMP: - pc = arg - - case compile.CALL, compile.CALL_VAR, compile.CALL_KW, compile.CALL_VAR_KW: - var kwargs Value - if op == compile.CALL_KW || op == compile.CALL_VAR_KW { - kwargs = stack[sp-1] - sp-- - } - - var args Value - if op == compile.CALL_VAR || op == compile.CALL_VAR_KW { - args = stack[sp-1] - sp-- - } - - // named args (pairs) - var kvpairs []Tuple - if nkvpairs := int(arg & 0xff); nkvpairs > 0 { - kvpairs = make([]Tuple, 0, nkvpairs) - kvpairsAlloc := make(Tuple, 2*nkvpairs) // allocate a single backing array - sp -= 2 * nkvpairs - for i := 0; i < nkvpairs; i++ { - pair := kvpairsAlloc[:2:2] - kvpairsAlloc = kvpairsAlloc[2:] - pair[0] = stack[sp+2*i] // name - pair[1] = stack[sp+2*i+1] // value - kvpairs = append(kvpairs, pair) - } - } - if kwargs != nil { - // Add key/value items from **kwargs dictionary. - dict, ok := kwargs.(IterableMapping) - if !ok { - err = fmt.Errorf("argument after ** must be a mapping, not %s", kwargs.Type()) - break loop - } - items := dict.Items() - for _, item := range items { - if _, ok := item[0].(String); !ok { - err = fmt.Errorf("keywords must be strings, not %s", item[0].Type()) - break loop - } - } - if len(kvpairs) == 0 { - kvpairs = items - } else { - kvpairs = append(kvpairs, items...) - } - } - - // positional args - var positional Tuple - if npos := int(arg >> 8); npos > 0 { - positional = stack[sp-npos : sp] - sp -= npos - - // Copy positional arguments into a new array, - // unless the callee is another Starlark function, - // in which case it can be trusted not to mutate them. - if _, ok := stack[sp-1].(*Function); !ok || args != nil { - positional = append(Tuple(nil), positional...) - } - } - if args != nil { - // Add elements from *args sequence. - iter := Iterate(args) - if iter == nil { - err = fmt.Errorf("argument after * must be iterable, not %s", args.Type()) - break loop - } - var elem Value - for iter.Next(&elem) { - positional = append(positional, elem) - } - iter.Done() - } - - function := stack[sp-1] - - if vmdebug { - fmt.Printf("VM call %s args=%s kwargs=%s @%s\n", - function, positional, kvpairs, f.Position(fr.pc)) - } - - thread.endProfSpan() - z, err2 := Call(thread, function, positional, kvpairs) - thread.beginProfSpan() - if err2 != nil { - err = err2 - break loop - } - if vmdebug { - fmt.Printf("Resuming %s @ %s\n", f.Name, f.Position(0)) - } - stack[sp-1] = z - - case compile.ITERPUSH: - x := stack[sp-1] - sp-- - iter := Iterate(x) - if iter == nil { - err = fmt.Errorf("%s value is not iterable", x.Type()) - break loop - } - iterstack = append(iterstack, iter) - - case compile.ITERJMP: - iter := iterstack[len(iterstack)-1] - if iter.Next(&stack[sp]) { - sp++ - } else { - pc = arg - } - - case compile.ITERPOP: - n := len(iterstack) - 1 - iterstack[n].Done() - iterstack = iterstack[:n] - - case compile.NOT: - stack[sp-1] = !stack[sp-1].Truth() - - case compile.RETURN: - result = stack[sp-1] - break loop - - case compile.SETINDEX: - z := stack[sp-1] - y := stack[sp-2] - x := stack[sp-3] - sp -= 3 - err = setIndex(x, y, z) - if err != nil { - break loop - } - - case compile.INDEX: - y := stack[sp-1] - x := stack[sp-2] - sp -= 2 - z, err2 := getIndex(x, y) - if err2 != nil { - err = err2 - break loop - } - stack[sp] = z - sp++ - - case compile.ATTR: - x := stack[sp-1] - name := f.Prog.Names[arg] - y, err2 := getAttr(x, name) - if err2 != nil { - err = err2 - break loop - } - stack[sp-1] = y - - case compile.SETFIELD: - y := stack[sp-1] - x := stack[sp-2] - sp -= 2 - name := f.Prog.Names[arg] - if err2 := setField(x, name, y); err2 != nil { - err = err2 - break loop - } - - case compile.MAKEDICT: - stack[sp] = new(Dict) - sp++ - - case compile.SETDICT, compile.SETDICTUNIQ: - dict := stack[sp-3].(*Dict) - k := stack[sp-2] - v := stack[sp-1] - sp -= 3 - oldlen := dict.Len() - if err2 := dict.SetKey(k, v); err2 != nil { - err = err2 - break loop - } - if op == compile.SETDICTUNIQ && dict.Len() == oldlen { - err = fmt.Errorf("duplicate key: %v", k) - break loop - } - - case compile.APPEND: - elem := stack[sp-1] - list := stack[sp-2].(*List) - sp -= 2 - list.elems = append(list.elems, elem) - - case compile.SLICE: - x := stack[sp-4] - lo := stack[sp-3] - hi := stack[sp-2] - step := stack[sp-1] - sp -= 4 - res, err2 := slice(x, lo, hi, step) - if err2 != nil { - err = err2 - break loop - } - stack[sp] = res - sp++ - - case compile.UNPACK: - n := int(arg) - iterable := stack[sp-1] - sp-- - iter := Iterate(iterable) - if iter == nil { - err = fmt.Errorf("got %s in sequence assignment", iterable.Type()) - break loop - } - i := 0 - sp += n - for i < n && iter.Next(&stack[sp-1-i]) { - i++ - } - var dummy Value - if iter.Next(&dummy) { - // NB: Len may return -1 here in obscure cases. - err = fmt.Errorf("too many values to unpack (got %d, want %d)", Len(iterable), n) - break loop - } - iter.Done() - if i < n { - err = fmt.Errorf("too few values to unpack (got %d, want %d)", i, n) - break loop - } - - case compile.CJMP: - if stack[sp-1].Truth() { - pc = arg - } - sp-- - - case compile.CONSTANT: - stack[sp] = fn.module.constants[arg] - sp++ - - case compile.MAKETUPLE: - n := int(arg) - tuple := make(Tuple, n) - sp -= n - copy(tuple, stack[sp:]) - stack[sp] = tuple - sp++ - - case compile.MAKELIST: - n := int(arg) - elems := make([]Value, n) - sp -= n - copy(elems, stack[sp:]) - stack[sp] = NewList(elems) - sp++ - - case compile.MAKEFUNC: - funcode := f.Prog.Functions[arg] - tuple := stack[sp-1].(Tuple) - n := len(tuple) - len(funcode.Freevars) - defaults := tuple[:n:n] - freevars := tuple[n:] - stack[sp-1] = &Function{ - funcode: funcode, - module: fn.module, - defaults: defaults, - freevars: freevars, - } - - case compile.LOAD: - n := int(arg) - module := string(stack[sp-1].(String)) - sp-- - - if thread.Load == nil { - err = fmt.Errorf("load not implemented by this application") - break loop - } - - thread.endProfSpan() - dict, err2 := thread.Load(thread, module) - thread.beginProfSpan() - if err2 != nil { - err = wrappedError{ - msg: fmt.Sprintf("cannot load %s: %v", module, err2), - cause: err2, - } - break loop - } - - for i := 0; i < n; i++ { - from := string(stack[sp-1-i].(String)) - v, ok := dict[from] - if !ok { - err = fmt.Errorf("load: name %s not found in module %s", from, module) - if n := spell.Nearest(from, dict.Keys()); n != "" { - err = fmt.Errorf("%s (did you mean %s?)", err, n) - } - break loop - } - stack[sp-1-i] = v - } - - case compile.SETLOCAL: - locals[arg] = stack[sp-1] - sp-- - - case compile.SETLOCALCELL: - locals[arg].(*cell).v = stack[sp-1] - sp-- - - case compile.SETGLOBAL: - fn.module.globals[arg] = stack[sp-1] - sp-- - - case compile.LOCAL: - x := locals[arg] - if x == nil { - err = fmt.Errorf("local variable %s referenced before assignment", f.Locals[arg].Name) - break loop - } - stack[sp] = x - sp++ - - case compile.FREE: - stack[sp] = fn.freevars[arg] - sp++ - - case compile.LOCALCELL: - v := locals[arg].(*cell).v - if v == nil { - err = fmt.Errorf("local variable %s referenced before assignment", f.Locals[arg].Name) - break loop - } - stack[sp] = v - sp++ - - case compile.FREECELL: - v := fn.freevars[arg].(*cell).v - if v == nil { - err = fmt.Errorf("local variable %s referenced before assignment", f.Freevars[arg].Name) - break loop - } - stack[sp] = v - sp++ - - case compile.GLOBAL: - x := fn.module.globals[arg] - if x == nil { - err = fmt.Errorf("global variable %s referenced before assignment", f.Prog.Globals[arg].Name) - break loop - } - stack[sp] = x - sp++ - - case compile.PREDECLARED: - name := f.Prog.Names[arg] - x := fn.module.predeclared[name] - if x == nil { - err = fmt.Errorf("internal error: predeclared variable %s is uninitialized", name) - break loop - } - stack[sp] = x - sp++ - - case compile.UNIVERSAL: - stack[sp] = Universe[f.Prog.Names[arg]] - sp++ - - default: - err = fmt.Errorf("unimplemented: %s", op) - break loop - } - } - // (deferred cleanup runs here) - return result, err -} - -type wrappedError struct { - msg string - cause error -} - -func (e wrappedError) Error() string { - return e.msg -} - -// Implements the xerrors.Wrapper interface -// https://godoc.org/golang.org/x/xerrors#Wrapper -func (e wrappedError) Unwrap() error { - return e.cause -} - -// mandatory is a sentinel value used in a function's defaults tuple -// to indicate that a (keyword-only) parameter is mandatory. -type mandatory struct{} - -func (mandatory) String() string { return "mandatory" } -func (mandatory) Type() string { return "mandatory" } -func (mandatory) Freeze() {} // immutable -func (mandatory) Truth() Bool { return False } -func (mandatory) Hash() (uint32, error) { return 0, nil } - -// A cell is a box containing a Value. -// Local variables marked as cells hold their value indirectly -// so that they may be shared by outer and inner nested functions. -// Cells are always accessed using indirect {FREE,LOCAL,SETLOCAL}CELL instructions. -// The FreeVars tuple contains only cells. -// The FREE instruction always yields a cell. -type cell struct{ v Value } - -func (c *cell) String() string { return "cell" } -func (c *cell) Type() string { return "cell" } -func (c *cell) Freeze() { - if c.v != nil { - c.v.Freeze() - } -} -func (c *cell) Truth() Bool { panic("unreachable") } -func (c *cell) Hash() (uint32, error) { panic("unreachable") } diff --git a/tests/vendor/go.starlark.net/starlark/library.go b/tests/vendor/go.starlark.net/starlark/library.go deleted file mode 100644 index 4e73a40ba..000000000 --- a/tests/vendor/go.starlark.net/starlark/library.go +++ /dev/null @@ -1,2455 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package starlark - -// This file defines the library of built-ins. -// -// Built-ins must explicitly check the "frozen" flag before updating -// mutable types such as lists and dicts. - -import ( - "errors" - "fmt" - "math" - "math/big" - "os" - "sort" - "strconv" - "strings" - "unicode" - "unicode/utf16" - "unicode/utf8" - - "go.starlark.net/syntax" -) - -// Universe defines the set of universal built-ins, such as None, True, and len. -// -// The Go application may add or remove items from the -// universe dictionary before Starlark evaluation begins. -// All values in the dictionary must be immutable. -// Starlark programs cannot modify the dictionary. -var Universe StringDict - -func init() { - // https://github.com/google/starlark-go/blob/master/doc/spec.md#built-in-constants-and-functions - Universe = StringDict{ - "None": None, - "True": True, - "False": False, - "abs": NewBuiltin("abs", abs), - "any": NewBuiltin("any", any_), - "all": NewBuiltin("all", all), - "bool": NewBuiltin("bool", bool_), - "bytes": NewBuiltin("bytes", bytes_), - "chr": NewBuiltin("chr", chr), - "dict": NewBuiltin("dict", dict), - "dir": NewBuiltin("dir", dir), - "enumerate": NewBuiltin("enumerate", enumerate), - "fail": NewBuiltin("fail", fail), - "float": NewBuiltin("float", float), - "getattr": NewBuiltin("getattr", getattr), - "hasattr": NewBuiltin("hasattr", hasattr), - "hash": NewBuiltin("hash", hash), - "int": NewBuiltin("int", int_), - "len": NewBuiltin("len", len_), - "list": NewBuiltin("list", list), - "max": NewBuiltin("max", minmax), - "min": NewBuiltin("min", minmax), - "ord": NewBuiltin("ord", ord), - "print": NewBuiltin("print", print), - "range": NewBuiltin("range", range_), - "repr": NewBuiltin("repr", repr), - "reversed": NewBuiltin("reversed", reversed), - "set": NewBuiltin("set", set), // requires resolve.AllowSet - "sorted": NewBuiltin("sorted", sorted), - "str": NewBuiltin("str", str), - "tuple": NewBuiltin("tuple", tuple), - "type": NewBuiltin("type", type_), - "zip": NewBuiltin("zip", zip), - } -} - -// methods of built-in types -// https://github.com/google/starlark-go/blob/master/doc/spec.md#built-in-methods -var ( - bytesMethods = map[string]*Builtin{ - "elems": NewBuiltin("elems", bytes_elems), - } - - dictMethods = map[string]*Builtin{ - "clear": NewBuiltin("clear", dict_clear), - "get": NewBuiltin("get", dict_get), - "items": NewBuiltin("items", dict_items), - "keys": NewBuiltin("keys", dict_keys), - "pop": NewBuiltin("pop", dict_pop), - "popitem": NewBuiltin("popitem", dict_popitem), - "setdefault": NewBuiltin("setdefault", dict_setdefault), - "update": NewBuiltin("update", dict_update), - "values": NewBuiltin("values", dict_values), - } - - listMethods = map[string]*Builtin{ - "append": NewBuiltin("append", list_append), - "clear": NewBuiltin("clear", list_clear), - "extend": NewBuiltin("extend", list_extend), - "index": NewBuiltin("index", list_index), - "insert": NewBuiltin("insert", list_insert), - "pop": NewBuiltin("pop", list_pop), - "remove": NewBuiltin("remove", list_remove), - } - - stringMethods = map[string]*Builtin{ - "capitalize": NewBuiltin("capitalize", string_capitalize), - "codepoint_ords": NewBuiltin("codepoint_ords", string_iterable), - "codepoints": NewBuiltin("codepoints", string_iterable), // sic - "count": NewBuiltin("count", string_count), - "elem_ords": NewBuiltin("elem_ords", string_iterable), - "elems": NewBuiltin("elems", string_iterable), // sic - "endswith": NewBuiltin("endswith", string_startswith), // sic - "find": NewBuiltin("find", string_find), - "format": NewBuiltin("format", string_format), - "index": NewBuiltin("index", string_index), - "isalnum": NewBuiltin("isalnum", string_isalnum), - "isalpha": NewBuiltin("isalpha", string_isalpha), - "isdigit": NewBuiltin("isdigit", string_isdigit), - "islower": NewBuiltin("islower", string_islower), - "isspace": NewBuiltin("isspace", string_isspace), - "istitle": NewBuiltin("istitle", string_istitle), - "isupper": NewBuiltin("isupper", string_isupper), - "join": NewBuiltin("join", string_join), - "lower": NewBuiltin("lower", string_lower), - "lstrip": NewBuiltin("lstrip", string_strip), // sic - "partition": NewBuiltin("partition", string_partition), - "removeprefix": NewBuiltin("removeprefix", string_removefix), - "removesuffix": NewBuiltin("removesuffix", string_removefix), - "replace": NewBuiltin("replace", string_replace), - "rfind": NewBuiltin("rfind", string_rfind), - "rindex": NewBuiltin("rindex", string_rindex), - "rpartition": NewBuiltin("rpartition", string_partition), // sic - "rsplit": NewBuiltin("rsplit", string_split), // sic - "rstrip": NewBuiltin("rstrip", string_strip), // sic - "split": NewBuiltin("split", string_split), - "splitlines": NewBuiltin("splitlines", string_splitlines), - "startswith": NewBuiltin("startswith", string_startswith), - "strip": NewBuiltin("strip", string_strip), - "title": NewBuiltin("title", string_title), - "upper": NewBuiltin("upper", string_upper), - } - - setMethods = map[string]*Builtin{ - "add": NewBuiltin("add", set_add), - "clear": NewBuiltin("clear", set_clear), - "difference": NewBuiltin("difference", set_difference), - "discard": NewBuiltin("discard", set_discard), - "intersection": NewBuiltin("intersection", set_intersection), - "issubset": NewBuiltin("issubset", set_issubset), - "issuperset": NewBuiltin("issuperset", set_issuperset), - "pop": NewBuiltin("pop", set_pop), - "remove": NewBuiltin("remove", set_remove), - "symmetric_difference": NewBuiltin("symmetric_difference", set_symmetric_difference), - "union": NewBuiltin("union", set_union), - } -) - -func builtinAttr(recv Value, name string, methods map[string]*Builtin) (Value, error) { - b := methods[name] - if b == nil { - return nil, nil // no such method - } - return b.BindReceiver(recv), nil -} - -func builtinAttrNames(methods map[string]*Builtin) []string { - names := make([]string, 0, len(methods)) - for name := range methods { - names = append(names, name) - } - sort.Strings(names) - return names -} - -// ---- built-in functions ---- - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#abs -func abs(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var x Value - if err := UnpackPositionalArgs("abs", args, kwargs, 1, &x); err != nil { - return nil, err - } - switch x := x.(type) { - case Float: - return Float(math.Abs(float64(x))), nil - case Int: - if x.Sign() >= 0 { - return x, nil - } - return zero.Sub(x), nil - default: - return nil, fmt.Errorf("got %s, want int or float", x.Type()) - } -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#all -func all(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var iterable Iterable - if err := UnpackPositionalArgs("all", args, kwargs, 1, &iterable); err != nil { - return nil, err - } - iter := iterable.Iterate() - defer iter.Done() - var x Value - for iter.Next(&x) { - if !x.Truth() { - return False, nil - } - } - return True, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#any -func any_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var iterable Iterable - if err := UnpackPositionalArgs("any", args, kwargs, 1, &iterable); err != nil { - return nil, err - } - iter := iterable.Iterate() - defer iter.Done() - var x Value - for iter.Next(&x) { - if x.Truth() { - return True, nil - } - } - return False, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#bool -func bool_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var x Value = False - if err := UnpackPositionalArgs("bool", args, kwargs, 0, &x); err != nil { - return nil, err - } - return x.Truth(), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#bytes -func bytes_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(kwargs) > 0 { - return nil, fmt.Errorf("bytes does not accept keyword arguments") - } - if len(args) != 1 { - return nil, fmt.Errorf("bytes: got %d arguments, want exactly 1", len(args)) - } - switch x := args[0].(type) { - case Bytes: - return x, nil - case String: - // Invalid encodings are replaced by that of U+FFFD. - return Bytes(utf8Transcode(string(x))), nil - case Iterable: - // iterable of numeric byte values - var buf strings.Builder - if n := Len(x); n >= 0 { - // common case: known length - buf.Grow(n) - } - iter := x.Iterate() - defer iter.Done() - var elem Value - var b byte - for i := 0; iter.Next(&elem); i++ { - if err := AsInt(elem, &b); err != nil { - return nil, fmt.Errorf("bytes: at index %d, %s", i, err) - } - buf.WriteByte(b) - } - return Bytes(buf.String()), nil - - default: - // Unlike string(foo), which stringifies it, bytes(foo) is an error. - return nil, fmt.Errorf("bytes: got %s, want string, bytes, or iterable of ints", x.Type()) - } -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#chr -func chr(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(kwargs) > 0 { - return nil, fmt.Errorf("chr does not accept keyword arguments") - } - if len(args) != 1 { - return nil, fmt.Errorf("chr: got %d arguments, want 1", len(args)) - } - i, err := AsInt32(args[0]) - if err != nil { - return nil, fmt.Errorf("chr: %s", err) - } - if i < 0 { - return nil, fmt.Errorf("chr: Unicode code point %d out of range (<0)", i) - } - if i > unicode.MaxRune { - return nil, fmt.Errorf("chr: Unicode code point U+%X out of range (>0x10FFFF)", i) - } - return String(string(rune(i))), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict -func dict(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(args) > 1 { - return nil, fmt.Errorf("dict: got %d arguments, want at most 1", len(args)) - } - dict := new(Dict) - if err := updateDict(dict, args, kwargs); err != nil { - return nil, fmt.Errorf("dict: %v", err) - } - return dict, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dir -func dir(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(kwargs) > 0 { - return nil, fmt.Errorf("dir does not accept keyword arguments") - } - if len(args) != 1 { - return nil, fmt.Errorf("dir: got %d arguments, want 1", len(args)) - } - - var names []string - if x, ok := args[0].(HasAttrs); ok { - names = x.AttrNames() - } - sort.Strings(names) - elems := make([]Value, len(names)) - for i, name := range names { - elems[i] = String(name) - } - return NewList(elems), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#enumerate -func enumerate(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var iterable Iterable - var start int - if err := UnpackPositionalArgs("enumerate", args, kwargs, 1, &iterable, &start); err != nil { - return nil, err - } - - iter := iterable.Iterate() - defer iter.Done() - - var pairs []Value - var x Value - - if n := Len(iterable); n >= 0 { - // common case: known length - pairs = make([]Value, 0, n) - array := make(Tuple, 2*n) // allocate a single backing array - for i := 0; iter.Next(&x); i++ { - pair := array[:2:2] - array = array[2:] - pair[0] = MakeInt(start + i) - pair[1] = x - pairs = append(pairs, pair) - } - } else { - // non-sequence (unknown length) - for i := 0; iter.Next(&x); i++ { - pair := Tuple{MakeInt(start + i), x} - pairs = append(pairs, pair) - } - } - - return NewList(pairs), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#fail -func fail(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - sep := " " - if err := UnpackArgs("fail", nil, kwargs, "sep?", &sep); err != nil { - return nil, err - } - buf := new(strings.Builder) - buf.WriteString("fail: ") - for i, v := range args { - if i > 0 { - buf.WriteString(sep) - } - if s, ok := AsString(v); ok { - buf.WriteString(s) - } else { - writeValue(buf, v, nil) - } - } - - return nil, errors.New(buf.String()) -} - -func float(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(kwargs) > 0 { - return nil, fmt.Errorf("float does not accept keyword arguments") - } - if len(args) == 0 { - return Float(0.0), nil - } - if len(args) != 1 { - return nil, fmt.Errorf("float got %d arguments, wants 1", len(args)) - } - switch x := args[0].(type) { - case Bool: - if x { - return Float(1.0), nil - } else { - return Float(0.0), nil - } - case Int: - return x.finiteFloat() - case Float: - return x, nil - case String: - if x == "" { - return nil, fmt.Errorf("float: empty string") - } - // +/- NaN or Inf or Infinity (case insensitive)? - s := string(x) - switch x[len(x)-1] { - case 'y', 'Y': - if strings.EqualFold(s, "infinity") || strings.EqualFold(s, "+infinity") { - return inf, nil - } else if strings.EqualFold(s, "-infinity") { - return neginf, nil - } - case 'f', 'F': - if strings.EqualFold(s, "inf") || strings.EqualFold(s, "+inf") { - return inf, nil - } else if strings.EqualFold(s, "-inf") { - return neginf, nil - } - case 'n', 'N': - if strings.EqualFold(s, "nan") || strings.EqualFold(s, "+nan") || strings.EqualFold(s, "-nan") { - return nan, nil - } - } - f, err := strconv.ParseFloat(s, 64) - if math.IsInf(f, 0) { - return nil, fmt.Errorf("floating-point number too large") - } - if err != nil { - return nil, fmt.Errorf("invalid float literal: %s", s) - } - return Float(f), nil - default: - return nil, fmt.Errorf("float got %s, want number or string", x.Type()) - } -} - -var ( - inf = Float(math.Inf(+1)) - neginf = Float(math.Inf(-1)) - nan = Float(math.NaN()) -) - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#getattr -func getattr(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var object, dflt Value - var name string - if err := UnpackPositionalArgs("getattr", args, kwargs, 2, &object, &name, &dflt); err != nil { - return nil, err - } - if object, ok := object.(HasAttrs); ok { - v, err := object.Attr(name) - if err != nil { - // An error could mean the field doesn't exist, - // or it exists but could not be computed. - if dflt != nil { - return dflt, nil - } - return nil, nameErr(b, err) - } - if v != nil { - return v, nil - } - // (nil, nil) => no such field - } - if dflt != nil { - return dflt, nil - } - return nil, fmt.Errorf("getattr: %s has no .%s field or method", object.Type(), name) -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#hasattr -func hasattr(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var object Value - var name string - if err := UnpackPositionalArgs("hasattr", args, kwargs, 2, &object, &name); err != nil { - return nil, err - } - if object, ok := object.(HasAttrs); ok { - v, err := object.Attr(name) - if err == nil { - return Bool(v != nil), nil - } - - // An error does not conclusively indicate presence or - // absence of a field: it could occur while computing - // the value of a present attribute, or it could be a - // "no such attribute" error with details. - for _, x := range object.AttrNames() { - if x == name { - return True, nil - } - } - } - return False, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#hash -func hash(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var x Value - if err := UnpackPositionalArgs("hash", args, kwargs, 1, &x); err != nil { - return nil, err - } - - var h int64 - switch x := x.(type) { - case String: - // The Starlark spec requires that the hash function be - // deterministic across all runs, motivated by the need - // for reproducibility of builds. Thus we cannot call - // String.Hash, which uses the fastest implementation - // available, because as varies across process restarts, - // and may evolve with the implementation. - h = int64(javaStringHash(string(x))) - case Bytes: - h = int64(softHashString(string(x))) // FNV32 - default: - return nil, fmt.Errorf("hash: got %s, want string or bytes", x.Type()) - } - return MakeInt64(h), nil -} - -// javaStringHash returns the same hash as would be produced by -// java.lang.String.hashCode. This requires transcoding the string to -// UTF-16; transcoding may introduce Unicode replacement characters -// U+FFFD if s does not contain valid UTF-8. -func javaStringHash(s string) (h int32) { - for _, r := range s { - if utf16.IsSurrogate(r) { - c1, c2 := utf16.EncodeRune(r) - h = 31*h + c1 - h = 31*h + c2 - } else { - h = 31*h + r // r may be U+FFFD - } - } - return h -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#int -func int_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var x Value = zero - var base Value - if err := UnpackArgs("int", args, kwargs, "x", &x, "base?", &base); err != nil { - return nil, err - } - - if s, ok := AsString(x); ok { - b := 10 - if base != nil { - var err error - b, err = AsInt32(base) - if err != nil { - return nil, fmt.Errorf("int: for base, got %s, want int", base.Type()) - } - if b != 0 && (b < 2 || b > 36) { - return nil, fmt.Errorf("int: base must be an integer >= 2 && <= 36") - } - } - res := parseInt(s, b) - if res == nil { - return nil, fmt.Errorf("int: invalid literal with base %d: %s", b, s) - } - return res, nil - } - - if base != nil { - return nil, fmt.Errorf("int: can't convert non-string with explicit base") - } - - if b, ok := x.(Bool); ok { - if b { - return one, nil - } else { - return zero, nil - } - } - - i, err := NumberToInt(x) - if err != nil { - return nil, fmt.Errorf("int: %s", err) - } - return i, nil -} - -// parseInt defines the behavior of int(string, base=int). It returns nil on error. -func parseInt(s string, base int) Value { - // remove sign - var neg bool - if s != "" { - if s[0] == '+' { - s = s[1:] - } else if s[0] == '-' { - neg = true - s = s[1:] - } - } - - // remove optional base prefix - baseprefix := 0 - if len(s) > 1 && s[0] == '0' { - if len(s) > 2 { - switch s[1] { - case 'o', 'O': - baseprefix = 8 - case 'x', 'X': - baseprefix = 16 - case 'b', 'B': - baseprefix = 2 - } - } - if baseprefix != 0 { - // Remove the base prefix if it matches - // the explicit base, or if base=0. - if base == 0 || baseprefix == base { - base = baseprefix - s = s[2:] - } - } else { - // For automatic base detection, - // a string starting with zero - // must be all zeros. - // Thus we reject int("0755", 0). - if base == 0 { - for i := 1; i < len(s); i++ { - if s[i] != '0' { - return nil - } - } - return zero - } - } - } - if base == 0 { - base = 10 - } - - // we explicitly handled sign above. - // if a sign remains, it is invalid. - if s != "" && (s[0] == '-' || s[0] == '+') { - return nil - } - - // s has no sign or base prefix. - if i, ok := new(big.Int).SetString(s, base); ok { - res := MakeBigInt(i) - if neg { - res = zero.Sub(res) - } - return res - } - - return nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#len -func len_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var x Value - if err := UnpackPositionalArgs("len", args, kwargs, 1, &x); err != nil { - return nil, err - } - len := Len(x) - if len < 0 { - return nil, fmt.Errorf("len: value of type %s has no len", x.Type()) - } - return MakeInt(len), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#list -func list(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var iterable Iterable - if err := UnpackPositionalArgs("list", args, kwargs, 0, &iterable); err != nil { - return nil, err - } - var elems []Value - if iterable != nil { - iter := iterable.Iterate() - defer iter.Done() - if n := Len(iterable); n > 0 { - elems = make([]Value, 0, n) // preallocate if length known - } - var x Value - for iter.Next(&x) { - elems = append(elems, x) - } - } - return NewList(elems), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#min -func minmax(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(args) == 0 { - return nil, fmt.Errorf("%s requires at least one positional argument", b.Name()) - } - var keyFunc Callable - if err := UnpackArgs(b.Name(), nil, kwargs, "key?", &keyFunc); err != nil { - return nil, err - } - var op syntax.Token - if b.Name() == "max" { - op = syntax.GT - } else { - op = syntax.LT - } - var iterable Value - if len(args) == 1 { - iterable = args[0] - } else { - iterable = args - } - iter := Iterate(iterable) - if iter == nil { - return nil, fmt.Errorf("%s: %s value is not iterable", b.Name(), iterable.Type()) - } - defer iter.Done() - var extremum Value - if !iter.Next(&extremum) { - return nil, nameErr(b, "argument is an empty sequence") - } - - var extremeKey Value - var keyargs Tuple - if keyFunc == nil { - extremeKey = extremum - } else { - keyargs = Tuple{extremum} - res, err := Call(thread, keyFunc, keyargs, nil) - if err != nil { - return nil, err // to preserve backtrace, don't modify error - } - extremeKey = res - } - - var x Value - for iter.Next(&x) { - var key Value - if keyFunc == nil { - key = x - } else { - keyargs[0] = x - res, err := Call(thread, keyFunc, keyargs, nil) - if err != nil { - return nil, err // to preserve backtrace, don't modify error - } - key = res - } - - if ok, err := Compare(op, key, extremeKey); err != nil { - return nil, nameErr(b, err) - } else if ok { - extremum = x - extremeKey = key - } - } - return extremum, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#ord -func ord(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(kwargs) > 0 { - return nil, fmt.Errorf("ord does not accept keyword arguments") - } - if len(args) != 1 { - return nil, fmt.Errorf("ord: got %d arguments, want 1", len(args)) - } - switch x := args[0].(type) { - case String: - // ord(string) returns int value of sole rune. - s := string(x) - r, sz := utf8.DecodeRuneInString(s) - if sz == 0 || sz != len(s) { - n := utf8.RuneCountInString(s) - return nil, fmt.Errorf("ord: string encodes %d Unicode code points, want 1", n) - } - return MakeInt(int(r)), nil - - case Bytes: - // ord(bytes) returns int value of sole byte. - if len(x) != 1 { - return nil, fmt.Errorf("ord: bytes has length %d, want 1", len(x)) - } - return MakeInt(int(x[0])), nil - default: - return nil, fmt.Errorf("ord: got %s, want string or bytes", x.Type()) - } -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#print -func print(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - sep := " " - if err := UnpackArgs("print", nil, kwargs, "sep?", &sep); err != nil { - return nil, err - } - buf := new(strings.Builder) - for i, v := range args { - if i > 0 { - buf.WriteString(sep) - } - if s, ok := AsString(v); ok { - buf.WriteString(s) - } else if b, ok := v.(Bytes); ok { - buf.WriteString(string(b)) - } else { - writeValue(buf, v, nil) - } - } - - s := buf.String() - if thread.Print != nil { - thread.Print(thread, s) - } else { - fmt.Fprintln(os.Stderr, s) - } - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#range -func range_(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var start, stop, step int - step = 1 - if err := UnpackPositionalArgs("range", args, kwargs, 1, &start, &stop, &step); err != nil { - return nil, err - } - - if len(args) == 1 { - // range(stop) - start, stop = 0, start - } - if step == 0 { - // we were given range(start, stop, 0) - return nil, nameErr(b, "step argument must not be zero") - } - - return rangeValue{start: start, stop: stop, step: step, len: rangeLen(start, stop, step)}, nil -} - -// A rangeValue is a comparable, immutable, indexable sequence of integers -// defined by the three parameters to a range(...) call. -// Invariant: step != 0. -type rangeValue struct{ start, stop, step, len int } - -var ( - _ Indexable = rangeValue{} - _ Sequence = rangeValue{} - _ Comparable = rangeValue{} - _ Sliceable = rangeValue{} -) - -func (r rangeValue) Len() int { return r.len } -func (r rangeValue) Index(i int) Value { return MakeInt(r.start + i*r.step) } -func (r rangeValue) Iterate() Iterator { return &rangeIterator{r, 0} } - -// rangeLen calculates the length of a range with the provided start, stop, and step. -// caller must ensure that step is non-zero. -func rangeLen(start, stop, step int) int { - switch { - case step > 0: - if stop > start { - return (stop-1-start)/step + 1 - } - case step < 0: - if start > stop { - return (start-1-stop)/-step + 1 - } - default: - panic("rangeLen: zero step") - } - return 0 -} - -func (r rangeValue) Slice(start, end, step int) Value { - newStart := r.start + r.step*start - newStop := r.start + r.step*end - newStep := r.step * step - return rangeValue{ - start: newStart, - stop: newStop, - step: newStep, - len: rangeLen(newStart, newStop, newStep), - } -} - -func (r rangeValue) Freeze() {} // immutable -func (r rangeValue) String() string { - if r.step != 1 { - return fmt.Sprintf("range(%d, %d, %d)", r.start, r.stop, r.step) - } else if r.start != 0 { - return fmt.Sprintf("range(%d, %d)", r.start, r.stop) - } else { - return fmt.Sprintf("range(%d)", r.stop) - } -} -func (r rangeValue) Type() string { return "range" } -func (r rangeValue) Truth() Bool { return r.len > 0 } -func (r rangeValue) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: range") } - -func (x rangeValue) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { - y := y_.(rangeValue) - switch op { - case syntax.EQL: - return rangeEqual(x, y), nil - case syntax.NEQ: - return !rangeEqual(x, y), nil - default: - return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) - } -} - -func rangeEqual(x, y rangeValue) bool { - // Two ranges compare equal if they denote the same sequence. - if x.len != y.len { - return false // sequences differ in length - } - if x.len == 0 { - return true // both sequences are empty - } - if x.start != y.start { - return false // first element differs - } - return x.len == 1 || x.step == y.step -} - -func (r rangeValue) contains(x Int) bool { - x32, err := AsInt32(x) - if err != nil { - return false // out of range - } - delta := x32 - r.start - quo, rem := delta/r.step, delta%r.step - return rem == 0 && 0 <= quo && quo < r.len -} - -type rangeIterator struct { - r rangeValue - i int -} - -func (it *rangeIterator) Next(p *Value) bool { - if it.i < it.r.len { - *p = it.r.Index(it.i) - it.i++ - return true - } - return false -} -func (*rangeIterator) Done() {} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#repr -func repr(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var x Value - if err := UnpackPositionalArgs("repr", args, kwargs, 1, &x); err != nil { - return nil, err - } - return String(x.String()), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#reversed -func reversed(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var iterable Iterable - if err := UnpackPositionalArgs("reversed", args, kwargs, 1, &iterable); err != nil { - return nil, err - } - iter := iterable.Iterate() - defer iter.Done() - var elems []Value - if n := Len(args[0]); n >= 0 { - elems = make([]Value, 0, n) // preallocate if length known - } - var x Value - for iter.Next(&x) { - elems = append(elems, x) - } - n := len(elems) - for i := 0; i < n>>1; i++ { - elems[i], elems[n-1-i] = elems[n-1-i], elems[i] - } - return NewList(elems), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set -func set(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var iterable Iterable - if err := UnpackPositionalArgs("set", args, kwargs, 0, &iterable); err != nil { - return nil, err - } - set := new(Set) - if iterable != nil { - iter := iterable.Iterate() - defer iter.Done() - var x Value - for iter.Next(&x) { - if err := set.Insert(x); err != nil { - return nil, nameErr(b, err) - } - } - } - return set, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#sorted -func sorted(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - // Oddly, Python's sorted permits all arguments to be positional, thus so do we. - var iterable Iterable - var key Callable - var reverse bool - if err := UnpackArgs("sorted", args, kwargs, - "iterable", &iterable, - "key?", &key, - "reverse?", &reverse, - ); err != nil { - return nil, err - } - - iter := iterable.Iterate() - defer iter.Done() - var values []Value - if n := Len(iterable); n > 0 { - values = make(Tuple, 0, n) // preallocate if length is known - } - var x Value - for iter.Next(&x) { - values = append(values, x) - } - - // Derive keys from values by applying key function. - var keys []Value - if key != nil { - keys = make([]Value, len(values)) - for i, v := range values { - k, err := Call(thread, key, Tuple{v}, nil) - if err != nil { - return nil, err // to preserve backtrace, don't modify error - } - keys[i] = k - } - } - - slice := &sortSlice{keys: keys, values: values} - if reverse { - sort.Stable(sort.Reverse(slice)) - } else { - sort.Stable(slice) - } - return NewList(slice.values), slice.err -} - -type sortSlice struct { - keys []Value // nil => values[i] is key - values []Value - err error -} - -func (s *sortSlice) Len() int { return len(s.values) } -func (s *sortSlice) Less(i, j int) bool { - keys := s.keys - if s.keys == nil { - keys = s.values - } - ok, err := Compare(syntax.LT, keys[i], keys[j]) - if err != nil { - s.err = err - } - return ok -} -func (s *sortSlice) Swap(i, j int) { - if s.keys != nil { - s.keys[i], s.keys[j] = s.keys[j], s.keys[i] - } - s.values[i], s.values[j] = s.values[j], s.values[i] -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#str -func str(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(kwargs) > 0 { - return nil, fmt.Errorf("str does not accept keyword arguments") - } - if len(args) != 1 { - return nil, fmt.Errorf("str: got %d arguments, want exactly 1", len(args)) - } - switch x := args[0].(type) { - case String: - return x, nil - case Bytes: - // Invalid encodings are replaced by that of U+FFFD. - return String(utf8Transcode(string(x))), nil - default: - return String(x.String()), nil - } -} - -// utf8Transcode returns the UTF-8-to-UTF-8 transcoding of s. -// The effect is that each code unit that is part of an -// invalid sequence is replaced by U+FFFD. -func utf8Transcode(s string) string { - if utf8.ValidString(s) { - return s - } - var out strings.Builder - for _, r := range s { - out.WriteRune(r) - } - return out.String() -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#tuple -func tuple(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var iterable Iterable - if err := UnpackPositionalArgs("tuple", args, kwargs, 0, &iterable); err != nil { - return nil, err - } - if len(args) == 0 { - return Tuple(nil), nil - } - iter := iterable.Iterate() - defer iter.Done() - var elems Tuple - if n := Len(iterable); n > 0 { - elems = make(Tuple, 0, n) // preallocate if length is known - } - var x Value - for iter.Next(&x) { - elems = append(elems, x) - } - return elems, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#type -func type_(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(kwargs) > 0 { - return nil, fmt.Errorf("type does not accept keyword arguments") - } - if len(args) != 1 { - return nil, fmt.Errorf("type: got %d arguments, want exactly 1", len(args)) - } - return String(args[0].Type()), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#zip -func zip(thread *Thread, _ *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(kwargs) > 0 { - return nil, fmt.Errorf("zip does not accept keyword arguments") - } - rows, cols := 0, len(args) - iters := make([]Iterator, cols) - defer func() { - for _, iter := range iters { - if iter != nil { - iter.Done() - } - } - }() - for i, seq := range args { - it := Iterate(seq) - if it == nil { - return nil, fmt.Errorf("zip: argument #%d is not iterable: %s", i+1, seq.Type()) - } - iters[i] = it - n := Len(seq) - if i == 0 || n < rows { - rows = n // possibly -1 - } - } - var result []Value - if rows >= 0 { - // length known - result = make([]Value, rows) - array := make(Tuple, cols*rows) // allocate a single backing array - for i := 0; i < rows; i++ { - tuple := array[:cols:cols] - array = array[cols:] - for j, iter := range iters { - iter.Next(&tuple[j]) - } - result[i] = tuple - } - } else { - // length not known - outer: - for { - tuple := make(Tuple, cols) - for i, iter := range iters { - if !iter.Next(&tuple[i]) { - break outer - } - } - result = append(result, tuple) - } - } - return NewList(result), nil -} - -// ---- methods of built-in types --- - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·get -func dict_get(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var key, dflt Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &key, &dflt); err != nil { - return nil, err - } - if v, ok, err := b.Receiver().(*Dict).Get(key); err != nil { - return nil, nameErr(b, err) - } else if ok { - return v, nil - } else if dflt != nil { - return dflt, nil - } - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·clear -func dict_clear(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - return None, b.Receiver().(*Dict).Clear() -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·items -func dict_items(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - items := b.Receiver().(*Dict).Items() - res := make([]Value, len(items)) - for i, item := range items { - res[i] = item // convert [2]Value to Value - } - return NewList(res), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·keys -func dict_keys(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - return NewList(b.Receiver().(*Dict).Keys()), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·pop -func dict_pop(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var k, d Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &k, &d); err != nil { - return nil, err - } - if v, found, err := b.Receiver().(*Dict).Delete(k); err != nil { - return nil, nameErr(b, err) // dict is frozen or key is unhashable - } else if found { - return v, nil - } else if d != nil { - return d, nil - } - return nil, nameErr(b, "missing key") -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·popitem -func dict_popitem(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - recv := b.Receiver().(*Dict) - k, ok := recv.ht.first() - if !ok { - return nil, nameErr(b, "empty dict") - } - v, _, err := recv.Delete(k) - if err != nil { - return nil, nameErr(b, err) // dict is frozen - } - return Tuple{k, v}, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·setdefault -func dict_setdefault(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var key, dflt Value = nil, None - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &key, &dflt); err != nil { - return nil, err - } - dict := b.Receiver().(*Dict) - if v, ok, err := dict.Get(key); err != nil { - return nil, nameErr(b, err) - } else if ok { - return v, nil - } else if err := dict.SetKey(key, dflt); err != nil { - return nil, nameErr(b, err) - } else { - return dflt, nil - } -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·update -func dict_update(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if len(args) > 1 { - return nil, fmt.Errorf("update: got %d arguments, want at most 1", len(args)) - } - if err := updateDict(b.Receiver().(*Dict), args, kwargs); err != nil { - return nil, fmt.Errorf("update: %v", err) - } - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#dict·update -func dict_values(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - items := b.Receiver().(*Dict).Items() - res := make([]Value, len(items)) - for i, item := range items { - res[i] = item[1] - } - return NewList(res), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#list·append -func list_append(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var object Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &object); err != nil { - return nil, err - } - recv := b.Receiver().(*List) - if err := recv.checkMutable("append to"); err != nil { - return nil, nameErr(b, err) - } - recv.elems = append(recv.elems, object) - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#list·clear -func list_clear(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - if err := b.Receiver().(*List).Clear(); err != nil { - return nil, nameErr(b, err) - } - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#list·extend -func list_extend(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - recv := b.Receiver().(*List) - var iterable Iterable - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &iterable); err != nil { - return nil, err - } - if err := recv.checkMutable("extend"); err != nil { - return nil, nameErr(b, err) - } - listExtend(recv, iterable) - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#list·index -func list_index(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var value, start_, end_ Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &value, &start_, &end_); err != nil { - return nil, err - } - - recv := b.Receiver().(*List) - start, end, err := indices(start_, end_, recv.Len()) - if err != nil { - return nil, nameErr(b, err) - } - - for i := start; i < end; i++ { - if eq, err := Equal(recv.elems[i], value); err != nil { - return nil, nameErr(b, err) - } else if eq { - return MakeInt(i), nil - } - } - return nil, nameErr(b, "value not in list") -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#list·insert -func list_insert(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - recv := b.Receiver().(*List) - var index int - var object Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 2, &index, &object); err != nil { - return nil, err - } - if err := recv.checkMutable("insert into"); err != nil { - return nil, nameErr(b, err) - } - - if index < 0 { - index += recv.Len() - } - - if index >= recv.Len() { - // end - recv.elems = append(recv.elems, object) - } else { - if index < 0 { - index = 0 // start - } - recv.elems = append(recv.elems, nil) - copy(recv.elems[index+1:], recv.elems[index:]) // slide up one - recv.elems[index] = object - } - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#list·remove -func list_remove(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - recv := b.Receiver().(*List) - var value Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &value); err != nil { - return nil, err - } - if err := recv.checkMutable("remove from"); err != nil { - return nil, nameErr(b, err) - } - for i, elem := range recv.elems { - if eq, err := Equal(elem, value); err != nil { - return nil, fmt.Errorf("remove: %v", err) - } else if eq { - recv.elems = append(recv.elems[:i], recv.elems[i+1:]...) - return None, nil - } - } - return nil, fmt.Errorf("remove: element not found") -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#list·pop -func list_pop(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - recv := b.Receiver() - list := recv.(*List) - n := list.Len() - i := n - 1 - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &i); err != nil { - return nil, err - } - origI := i - if i < 0 { - i += n - } - if i < 0 || i >= n { - return nil, nameErr(b, outOfRange(origI, n, list)) - } - if err := list.checkMutable("pop from"); err != nil { - return nil, nameErr(b, err) - } - res := list.elems[i] - list.elems = append(list.elems[:i], list.elems[i+1:]...) - return res, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·capitalize -func string_capitalize(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - s := string(b.Receiver().(String)) - res := new(strings.Builder) - res.Grow(len(s)) - for i, r := range s { - if i == 0 { - r = unicode.ToTitle(r) - } else { - r = unicode.ToLower(r) - } - res.WriteRune(r) - } - return String(res.String()), nil -} - -// string_iterable returns an unspecified iterable value whose iterator yields: -// - elems: successive 1-byte substrings -// - codepoints: successive substrings that encode a single Unicode code point. -// - elem_ords: numeric values of successive bytes -// - codepoint_ords: numeric values of successive Unicode code points -func string_iterable(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - s := b.Receiver().(String) - ords := b.Name()[len(b.Name())-2] == 'd' - codepoints := b.Name()[0] == 'c' - if codepoints { - return stringCodepoints{s, ords}, nil - } else { - return stringElems{s, ords}, nil - } -} - -// bytes_elems returns an unspecified iterable value whose -// iterator yields the int values of successive elements. -func bytes_elems(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - return bytesIterable{b.Receiver().(Bytes)}, nil -} - -// A bytesIterable is an iterable returned by bytes.elems(), -// whose iterator yields a sequence of numeric bytes values. -type bytesIterable struct{ bytes Bytes } - -var _ Iterable = (*bytesIterable)(nil) - -func (bi bytesIterable) String() string { return bi.bytes.String() + ".elems()" } -func (bi bytesIterable) Type() string { return "bytes.elems" } -func (bi bytesIterable) Freeze() {} // immutable -func (bi bytesIterable) Truth() Bool { return True } -func (bi bytesIterable) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", bi.Type()) } -func (bi bytesIterable) Iterate() Iterator { return &bytesIterator{bi.bytes} } - -type bytesIterator struct{ bytes Bytes } - -func (it *bytesIterator) Next(p *Value) bool { - if it.bytes == "" { - return false - } - *p = MakeInt(int(it.bytes[0])) - it.bytes = it.bytes[1:] - return true -} - -func (*bytesIterator) Done() {} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·count -func string_count(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var sub string - var start_, end_ Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &sub, &start_, &end_); err != nil { - return nil, err - } - - recv := string(b.Receiver().(String)) - start, end, err := indices(start_, end_, len(recv)) - if err != nil { - return nil, nameErr(b, err) - } - - var slice string - if start < end { - slice = recv[start:end] - } - return MakeInt(strings.Count(slice, sub)), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·isalnum -func string_isalnum(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - recv := string(b.Receiver().(String)) - for _, r := range recv { - if !unicode.IsLetter(r) && !unicode.IsDigit(r) { - return False, nil - } - } - return Bool(recv != ""), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·isalpha -func string_isalpha(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - recv := string(b.Receiver().(String)) - for _, r := range recv { - if !unicode.IsLetter(r) { - return False, nil - } - } - return Bool(recv != ""), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·isdigit -func string_isdigit(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - recv := string(b.Receiver().(String)) - for _, r := range recv { - if !unicode.IsDigit(r) { - return False, nil - } - } - return Bool(recv != ""), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·islower -func string_islower(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - recv := string(b.Receiver().(String)) - return Bool(isCasedString(recv) && recv == strings.ToLower(recv)), nil -} - -// isCasedString reports whether its argument contains any cased code points. -func isCasedString(s string) bool { - for _, r := range s { - if isCasedRune(r) { - return true - } - } - return false -} - -func isCasedRune(r rune) bool { - // It's unclear what the correct behavior is for a rune such as 'ffi', - // a lowercase letter with no upper or title case and no SimpleFold. - return 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || unicode.SimpleFold(r) != r -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·isspace -func string_isspace(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - recv := string(b.Receiver().(String)) - for _, r := range recv { - if !unicode.IsSpace(r) { - return False, nil - } - } - return Bool(recv != ""), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·istitle -func string_istitle(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - recv := string(b.Receiver().(String)) - - // Python semantics differ from x==strings.{To,}Title(x) in Go: - // "uppercase characters may only follow uncased characters and - // lowercase characters only cased ones." - var cased, prevCased bool - for _, r := range recv { - if 'A' <= r && r <= 'Z' || unicode.IsTitle(r) { // e.g. "Dž" - if prevCased { - return False, nil - } - prevCased = true - cased = true - } else if unicode.IsLower(r) { - if !prevCased { - return False, nil - } - prevCased = true - cased = true - } else if unicode.IsUpper(r) { - return False, nil - } else { - prevCased = false - } - } - return Bool(cased), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·isupper -func string_isupper(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - recv := string(b.Receiver().(String)) - return Bool(isCasedString(recv) && recv == strings.ToUpper(recv)), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·find -func string_find(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - return string_find_impl(b, args, kwargs, true, false) -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·format -func string_format(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - format := string(b.Receiver().(String)) - var auto, manual bool // kinds of positional indexing used - buf := new(strings.Builder) - index := 0 - for { - literal := format - i := strings.IndexByte(format, '{') - if i >= 0 { - literal = format[:i] - } - - // Replace "}}" with "}" in non-field portion, rejecting a lone '}'. - for { - j := strings.IndexByte(literal, '}') - if j < 0 { - buf.WriteString(literal) - break - } - if len(literal) == j+1 || literal[j+1] != '}' { - return nil, fmt.Errorf("format: single '}' in format") - } - buf.WriteString(literal[:j+1]) - literal = literal[j+2:] - } - - if i < 0 { - break // end of format string - } - - if i+1 < len(format) && format[i+1] == '{' { - // "{{" means a literal '{' - buf.WriteByte('{') - format = format[i+2:] - continue - } - - format = format[i+1:] - i = strings.IndexByte(format, '}') - if i < 0 { - return nil, fmt.Errorf("format: unmatched '{' in format") - } - - var arg Value - conv := "s" - var spec string - - field := format[:i] - format = format[i+1:] - - var name string - if i := strings.IndexByte(field, '!'); i < 0 { - // "name" or "name:spec" - if i := strings.IndexByte(field, ':'); i < 0 { - name = field - } else { - name = field[:i] - spec = field[i+1:] - } - } else { - // "name!conv" or "name!conv:spec" - name = field[:i] - field = field[i+1:] - // "conv" or "conv:spec" - if i := strings.IndexByte(field, ':'); i < 0 { - conv = field - } else { - conv = field[:i] - spec = field[i+1:] - } - } - - if name == "" { - // "{}": automatic indexing - if manual { - return nil, fmt.Errorf("format: cannot switch from manual field specification to automatic field numbering") - } - auto = true - if index >= len(args) { - return nil, fmt.Errorf("format: tuple index out of range") - } - arg = args[index] - index++ - } else if num, ok := decimal(name); ok { - // positional argument - if auto { - return nil, fmt.Errorf("format: cannot switch from automatic field numbering to manual field specification") - } - manual = true - if num >= len(args) { - return nil, fmt.Errorf("format: tuple index out of range") - } else { - arg = args[num] - } - } else { - // keyword argument - for _, kv := range kwargs { - if string(kv[0].(String)) == name { - arg = kv[1] - break - } - } - if arg == nil { - // Starlark does not support Python's x.y or a[i] syntaxes, - // or nested use of {...}. - if strings.Contains(name, ".") { - return nil, fmt.Errorf("format: attribute syntax x.y is not supported in replacement fields: %s", name) - } - if strings.Contains(name, "[") { - return nil, fmt.Errorf("format: element syntax a[i] is not supported in replacement fields: %s", name) - } - if strings.Contains(name, "{") { - return nil, fmt.Errorf("format: nested replacement fields not supported") - } - return nil, fmt.Errorf("format: keyword %s not found", name) - } - } - - if spec != "" { - // Starlark does not support Python's format_spec features. - return nil, fmt.Errorf("format spec features not supported in replacement fields: %s", spec) - } - - switch conv { - case "s": - if str, ok := AsString(arg); ok { - buf.WriteString(str) - } else { - writeValue(buf, arg, nil) - } - case "r": - writeValue(buf, arg, nil) - default: - return nil, fmt.Errorf("format: unknown conversion %q", conv) - } - } - return String(buf.String()), nil -} - -// decimal interprets s as a sequence of decimal digits. -func decimal(s string) (x int, ok bool) { - n := len(s) - for i := 0; i < n; i++ { - digit := s[i] - '0' - if digit > 9 { - return 0, false - } - x = x*10 + int(digit) - if x < 0 { - return 0, false // underflow - } - } - return x, true -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·index -func string_index(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - return string_find_impl(b, args, kwargs, false, false) -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·join -func string_join(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - recv := string(b.Receiver().(String)) - var iterable Iterable - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &iterable); err != nil { - return nil, err - } - iter := iterable.Iterate() - defer iter.Done() - buf := new(strings.Builder) - var x Value - for i := 0; iter.Next(&x); i++ { - if i > 0 { - buf.WriteString(recv) - } - s, ok := AsString(x) - if !ok { - return nil, fmt.Errorf("join: in list, want string, got %s", x.Type()) - } - buf.WriteString(s) - } - return String(buf.String()), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·lower -func string_lower(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - return String(strings.ToLower(string(b.Receiver().(String)))), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·partition -func string_partition(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - recv := string(b.Receiver().(String)) - var sep string - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &sep); err != nil { - return nil, err - } - if sep == "" { - return nil, nameErr(b, "empty separator") - } - var i int - if b.Name()[0] == 'p' { - i = strings.Index(recv, sep) // partition - } else { - i = strings.LastIndex(recv, sep) // rpartition - } - tuple := make(Tuple, 0, 3) - if i < 0 { - if b.Name()[0] == 'p' { - tuple = append(tuple, String(recv), String(""), String("")) - } else { - tuple = append(tuple, String(""), String(""), String(recv)) - } - } else { - tuple = append(tuple, String(recv[:i]), String(sep), String(recv[i+len(sep):])) - } - return tuple, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·removeprefix -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·removesuffix -func string_removefix(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - recv := string(b.Receiver().(String)) - var fix string - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &fix); err != nil { - return nil, err - } - if b.name[len("remove")] == 'p' { - recv = strings.TrimPrefix(recv, fix) - } else { - recv = strings.TrimSuffix(recv, fix) - } - return String(recv), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·replace -func string_replace(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - recv := string(b.Receiver().(String)) - var old, new string - count := -1 - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 2, &old, &new, &count); err != nil { - return nil, err - } - return String(strings.Replace(recv, old, new, count)), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·rfind -func string_rfind(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - return string_find_impl(b, args, kwargs, true, true) -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·rindex -func string_rindex(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - return string_find_impl(b, args, kwargs, false, true) -} - -// https://github.com/google/starlark-go/starlark/blob/master/doc/spec.md#string·startswith -// https://github.com/google/starlark-go/starlark/blob/master/doc/spec.md#string·endswith -func string_startswith(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var x Value - var start, end Value = None, None - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &x, &start, &end); err != nil { - return nil, err - } - - // compute effective substring. - s := string(b.Receiver().(String)) - if start, end, err := indices(start, end, len(s)); err != nil { - return nil, nameErr(b, err) - } else { - if end < start { - end = start // => empty result - } - s = s[start:end] - } - - f := strings.HasPrefix - if b.Name()[0] == 'e' { // endswith - f = strings.HasSuffix - } - - switch x := x.(type) { - case Tuple: - for i, x := range x { - prefix, ok := AsString(x) - if !ok { - return nil, fmt.Errorf("%s: want string, got %s, for element %d", - b.Name(), x.Type(), i) - } - if f(s, prefix) { - return True, nil - } - } - return False, nil - case String: - return Bool(f(s, string(x))), nil - } - return nil, fmt.Errorf("%s: got %s, want string or tuple of string", b.Name(), x.Type()) -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·strip -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·lstrip -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·rstrip -func string_strip(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var chars string - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &chars); err != nil { - return nil, err - } - recv := string(b.Receiver().(String)) - var s string - switch b.Name()[0] { - case 's': // strip - if chars != "" { - s = strings.Trim(recv, chars) - } else { - s = strings.TrimSpace(recv) - } - case 'l': // lstrip - if chars != "" { - s = strings.TrimLeft(recv, chars) - } else { - s = strings.TrimLeftFunc(recv, unicode.IsSpace) - } - case 'r': // rstrip - if chars != "" { - s = strings.TrimRight(recv, chars) - } else { - s = strings.TrimRightFunc(recv, unicode.IsSpace) - } - } - return String(s), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·title -func string_title(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - - s := string(b.Receiver().(String)) - - // Python semantics differ from x==strings.{To,}Title(x) in Go: - // "uppercase characters may only follow uncased characters and - // lowercase characters only cased ones." - buf := new(strings.Builder) - buf.Grow(len(s)) - var prevCased bool - for _, r := range s { - if prevCased { - r = unicode.ToLower(r) - } else { - r = unicode.ToTitle(r) - } - prevCased = isCasedRune(r) - buf.WriteRune(r) - } - return String(buf.String()), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·upper -func string_upper(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - return String(strings.ToUpper(string(b.Receiver().(String)))), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·split -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·rsplit -func string_split(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - recv := string(b.Receiver().(String)) - var sep_ Value - maxsplit := -1 - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &sep_, &maxsplit); err != nil { - return nil, err - } - - var res []string - - if sep_ == nil || sep_ == None { - // special case: split on whitespace - if maxsplit < 0 { - res = strings.Fields(recv) - } else if b.Name() == "split" { - res = splitspace(recv, maxsplit) - } else { // rsplit - res = rsplitspace(recv, maxsplit) - } - - } else if sep, ok := AsString(sep_); ok { - if sep == "" { - return nil, fmt.Errorf("split: empty separator") - } - // usual case: split on non-empty separator - if maxsplit < 0 { - res = strings.Split(recv, sep) - } else if b.Name() == "split" { - res = strings.SplitN(recv, sep, maxsplit+1) - } else { // rsplit - res = strings.Split(recv, sep) - if excess := len(res) - maxsplit; excess > 0 { - res[0] = strings.Join(res[:excess], sep) - res = append(res[:1], res[excess:]...) - } - } - - } else { - return nil, fmt.Errorf("split: got %s for separator, want string", sep_.Type()) - } - - list := make([]Value, len(res)) - for i, x := range res { - list[i] = String(x) - } - return NewList(list), nil -} - -// Precondition: max >= 0. -func rsplitspace(s string, max int) []string { - res := make([]string, 0, max+1) - end := -1 // index of field end, or -1 in a region of spaces. - for i := len(s); i > 0; { - r, sz := utf8.DecodeLastRuneInString(s[:i]) - if unicode.IsSpace(r) { - if end >= 0 { - if len(res) == max { - break // let this field run to the start - } - res = append(res, s[i:end]) - end = -1 - } - } else if end < 0 { - end = i - } - i -= sz - } - if end >= 0 { - res = append(res, s[:end]) - } - - resLen := len(res) - for i := 0; i < resLen/2; i++ { - res[i], res[resLen-1-i] = res[resLen-1-i], res[i] - } - - return res -} - -// Precondition: max >= 0. -func splitspace(s string, max int) []string { - var res []string - start := -1 // index of field start, or -1 in a region of spaces - for i, r := range s { - if unicode.IsSpace(r) { - if start >= 0 { - if len(res) == max { - break // let this field run to the end - } - res = append(res, s[start:i]) - start = -1 - } - } else if start == -1 { - start = i - } - } - if start >= 0 { - res = append(res, s[start:]) - } - return res -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·splitlines -func string_splitlines(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var keepends bool - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &keepends); err != nil { - return nil, err - } - var lines []string - if s := string(b.Receiver().(String)); s != "" { - // TODO(adonovan): handle CRLF correctly. - if keepends { - lines = strings.SplitAfter(s, "\n") - } else { - lines = strings.Split(s, "\n") - } - if strings.HasSuffix(s, "\n") { - lines = lines[:len(lines)-1] - } - } - list := make([]Value, len(lines)) - for i, x := range lines { - list[i] = String(x) - } - return NewList(list), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·add. -func set_add(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var elem Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &elem); err != nil { - return nil, err - } - if found, err := b.Receiver().(*Set).Has(elem); err != nil { - return nil, nameErr(b, err) - } else if found { - return None, nil - } - err := b.Receiver().(*Set).Insert(elem) - if err != nil { - return nil, nameErr(b, err) - } - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·clear. -func set_clear(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - if b.Receiver().(*Set).Len() > 0 { - if err := b.Receiver().(*Set).Clear(); err != nil { - return nil, nameErr(b, err) - } - } - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·difference. -func set_difference(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - // TODO: support multiple others: s.difference(*others) - var other Iterable - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil { - return nil, err - } - iter := other.Iterate() - defer iter.Done() - diff, err := b.Receiver().(*Set).Difference(iter) - if err != nil { - return nil, nameErr(b, err) - } - return diff, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set_intersection. -func set_intersection(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - // TODO: support multiple others: s.difference(*others) - var other Iterable - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil { - return nil, err - } - iter := other.Iterate() - defer iter.Done() - diff, err := b.Receiver().(*Set).Intersection(iter) - if err != nil { - return nil, nameErr(b, err) - } - return diff, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set_issubset. -func set_issubset(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var other Iterable - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil { - return nil, err - } - iter := other.Iterate() - defer iter.Done() - diff, err := b.Receiver().(*Set).IsSubset(iter) - if err != nil { - return nil, nameErr(b, err) - } - return Bool(diff), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set_issuperset. -func set_issuperset(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var other Iterable - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil { - return nil, err - } - iter := other.Iterate() - defer iter.Done() - diff, err := b.Receiver().(*Set).IsSuperset(iter) - if err != nil { - return nil, nameErr(b, err) - } - return Bool(diff), nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·discard. -func set_discard(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var k Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &k); err != nil { - return nil, err - } - if found, err := b.Receiver().(*Set).Has(k); err != nil { - return nil, nameErr(b, err) - } else if !found { - return None, nil - } - if _, err := b.Receiver().(*Set).Delete(k); err != nil { - return nil, nameErr(b, err) // set is frozen - } - return None, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·pop. -func set_pop(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil { - return nil, err - } - recv := b.Receiver().(*Set) - k, ok := recv.ht.first() - if !ok { - return nil, nameErr(b, "empty set") - } - _, err := recv.Delete(k) - if err != nil { - return nil, nameErr(b, err) // set is frozen - } - return k, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·remove. -func set_remove(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var k Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &k); err != nil { - return nil, err - } - if found, err := b.Receiver().(*Set).Delete(k); err != nil { - return nil, nameErr(b, err) // dict is frozen or key is unhashable - } else if found { - return None, nil - } - return nil, nameErr(b, "missing key") -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·symmetric_difference. -func set_symmetric_difference(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var other Iterable - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil { - return nil, err - } - iter := other.Iterate() - defer iter.Done() - diff, err := b.Receiver().(*Set).SymmetricDifference(iter) - if err != nil { - return nil, nameErr(b, err) - } - return diff, nil -} - -// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·union. -func set_union(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) { - var iterable Iterable - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &iterable); err != nil { - return nil, err - } - iter := iterable.Iterate() - defer iter.Done() - union, err := b.Receiver().(*Set).Union(iter) - if err != nil { - return nil, nameErr(b, err) - } - return union, nil -} - -// Common implementation of string_{r}{find,index}. -func string_find_impl(b *Builtin, args Tuple, kwargs []Tuple, allowError, last bool) (Value, error) { - var sub string - var start_, end_ Value - if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &sub, &start_, &end_); err != nil { - return nil, err - } - - s := string(b.Receiver().(String)) - start, end, err := indices(start_, end_, len(s)) - if err != nil { - return nil, nameErr(b, err) - } - var slice string - if start < end { - slice = s[start:end] - } - - var i int - if last { - i = strings.LastIndex(slice, sub) - } else { - i = strings.Index(slice, sub) - } - if i < 0 { - if !allowError { - return nil, nameErr(b, "substring not found") - } - return MakeInt(-1), nil - } - return MakeInt(i + start), nil -} - -// Common implementation of builtin dict function and dict.update method. -// Precondition: len(updates) == 0 or 1. -func updateDict(dict *Dict, updates Tuple, kwargs []Tuple) error { - if len(updates) == 1 { - switch updates := updates[0].(type) { - case IterableMapping: - // Iterate over dict's key/value pairs, not just keys. - for _, item := range updates.Items() { - if err := dict.SetKey(item[0], item[1]); err != nil { - return err // dict is frozen - } - } - default: - // all other sequences - iter := Iterate(updates) - if iter == nil { - return fmt.Errorf("got %s, want iterable", updates.Type()) - } - defer iter.Done() - var pair Value - for i := 0; iter.Next(&pair); i++ { - iter2 := Iterate(pair) - if iter2 == nil { - return fmt.Errorf("dictionary update sequence element #%d is not iterable (%s)", i, pair.Type()) - - } - defer iter2.Done() - len := Len(pair) - if len < 0 { - return fmt.Errorf("dictionary update sequence element #%d has unknown length (%s)", i, pair.Type()) - } else if len != 2 { - return fmt.Errorf("dictionary update sequence element #%d has length %d, want 2", i, len) - } - var k, v Value - iter2.Next(&k) - iter2.Next(&v) - if err := dict.SetKey(k, v); err != nil { - return err - } - } - } - } - - // Then add the kwargs. - before := dict.Len() - for _, pair := range kwargs { - if err := dict.SetKey(pair[0], pair[1]); err != nil { - return err // dict is frozen - } - } - // In the common case, each kwarg will add another dict entry. - // If that's not so, check whether it is because there was a duplicate kwarg. - if dict.Len() < before+len(kwargs) { - keys := make(map[String]bool, len(kwargs)) - for _, kv := range kwargs { - k := kv[0].(String) - if keys[k] { - return fmt.Errorf("duplicate keyword arg: %v", k) - } - keys[k] = true - } - } - - return nil -} - -// nameErr returns an error message of the form "name: msg" -// where name is b.Name() and msg is a string or error. -func nameErr(b *Builtin, msg interface{}) error { - return fmt.Errorf("%s: %v", b.Name(), msg) -} diff --git a/tests/vendor/go.starlark.net/starlark/profile.go b/tests/vendor/go.starlark.net/starlark/profile.go deleted file mode 100644 index 590a4e2bb..000000000 --- a/tests/vendor/go.starlark.net/starlark/profile.go +++ /dev/null @@ -1,449 +0,0 @@ -// Copyright 2019 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package starlark - -// This file defines a simple execution-time profiler for Starlark. -// It measures the wall time spent executing Starlark code, and emits a -// gzipped protocol message in pprof format (github.com/google/pprof). -// -// When profiling is enabled, the interpreter calls the profiler to -// indicate the start and end of each "span" or time interval. A leaf -// function (whether Go or Starlark) has a single span. A function that -// calls another function has spans for each interval in which it is the -// top of the stack. (A LOAD instruction also ends a span.) -// -// At the start of a span, the interpreter records the current time in -// the thread's topmost frame. At the end of the span, it obtains the -// time again and subtracts the span start time. The difference is added -// to an accumulator variable in the thread. If the accumulator exceeds -// some fixed quantum (10ms, say), the profiler records the current call -// stack and sends it to the profiler goroutine, along with the number -// of quanta, which are subtracted. For example, if the accumulator -// holds 3ms and then a completed span adds 25ms to it, its value is 28ms, -// which exceeeds 10ms. The profiler records a stack with the value 20ms -// (2 quanta), and the accumulator is left with 8ms. -// -// The profiler goroutine converts the stacks into the pprof format and -// emits a gzip-compressed protocol message to the designated output -// file. We use a hand-written streaming proto encoder to avoid -// dependencies on pprof and proto, and to avoid the need to -// materialize the profile data structure in memory. -// -// A limitation of this profiler is that it measures wall time, which -// does not necessarily correspond to CPU time. A CPU profiler requires -// that only running (not runnable) threads are sampled; this is -// commonly achieved by having the kernel deliver a (PROF) signal to an -// arbitrary running thread, through setitimer(2). The CPU profiler in the -// Go runtime uses this mechanism, but it is not possible for a Go -// application to register a SIGPROF handler, nor is it possible for a -// Go handler for some other signal to read the stack pointer of -// the interrupted thread. -// -// Two caveats: -// (1) it is tempting to send the leaf Frame directly to the profiler -// goroutine instead of making a copy of the stack, since a Frame is a -// spaghetti stack--a linked list. However, as soon as execution -// resumes, the stack's Frame.pc values may be mutated, so Frames are -// not safe to share with the asynchronous profiler goroutine. -// (2) it is tempting to use Callables as keys in a map when tabulating -// the pprof protocols's Function entities. However, we cannot assume -// that Callables are valid map keys, and furthermore we must not -// pin function values in memory indefinitely as this may cause lambda -// values to keep their free variables live much longer than necessary. - -// TODO(adonovan): -// - make Start/Stop fully thread-safe. -// - fix the pc hack. -// - experiment with other values of quantum. - -import ( - "bufio" - "bytes" - "compress/gzip" - "encoding/binary" - "fmt" - "io" - "log" - "reflect" - "sync/atomic" - "time" - "unsafe" - - "go.starlark.net/syntax" -) - -// StartProfile enables time profiling of all Starlark threads, -// and writes a profile in pprof format to w. -// It must be followed by a call to StopProfiler to stop -// the profiler and finalize the profile. -// -// StartProfile returns an error if profiling was already enabled. -// -// StartProfile must not be called concurrently with Starlark execution. -func StartProfile(w io.Writer) error { - if !atomic.CompareAndSwapUint32(&profiler.on, 0, 1) { - return fmt.Errorf("profiler already running") - } - - // TODO(adonovan): make the API fully concurrency-safe. - // The main challenge is racy reads/writes of profiler.events, - // and of send/close races on the channel it refers to. - // It's easy to solve them with a mutex but harder to do - // it efficiently. - - profiler.events = make(chan *profEvent, 1) - profiler.done = make(chan error) - - go profile(w) - - return nil -} - -// StopProfile stops the profiler started by a prior call to -// StartProfile and finalizes the profile. It returns an error if the -// profile could not be completed. -// -// StopProfile must not be called concurrently with Starlark execution. -func StopProfile() error { - // Terminate the profiler goroutine and get its result. - close(profiler.events) - err := <-profiler.done - - profiler.done = nil - profiler.events = nil - atomic.StoreUint32(&profiler.on, 0) - - return err -} - -// globals -var profiler struct { - on uint32 // nonzero => profiler running - events chan *profEvent // profile events from interpreter threads - done chan error // indicates profiler goroutine is ready -} - -func (thread *Thread) beginProfSpan() { - if profiler.events == nil { - return // profiling not enabled - } - - thread.frameAt(0).spanStart = nanotime() -} - -// TODO(adonovan): experiment with smaller values, -// which trade space and time for greater precision. -const quantum = 10 * time.Millisecond - -func (thread *Thread) endProfSpan() { - if profiler.events == nil { - return // profiling not enabled - } - - // Add the span to the thread's accumulator. - thread.proftime += time.Duration(nanotime() - thread.frameAt(0).spanStart) - if thread.proftime < quantum { - return - } - - // Only record complete quanta. - n := thread.proftime / quantum - thread.proftime -= n * quantum - - // Copy the stack. - // (We can't save thread.frame because its pc will change.) - ev := &profEvent{ - thread: thread, - time: n * quantum, - } - ev.stack = ev.stackSpace[:0] - for i := range thread.stack { - fr := thread.frameAt(i) - ev.stack = append(ev.stack, profFrame{ - pos: fr.Position(), - fn: fr.Callable(), - pc: fr.pc, - }) - } - - profiler.events <- ev -} - -type profEvent struct { - thread *Thread // currently unused - time time.Duration - stack []profFrame - stackSpace [8]profFrame // initial space for stack -} - -type profFrame struct { - fn Callable // don't hold this live for too long (prevents GC of lambdas) - pc uint32 // program counter (Starlark frames only) - pos syntax.Position // position of pc within this frame -} - -// profile is the profiler goroutine. -// It runs until StopProfiler is called. -func profile(w io.Writer) { - // Field numbers from pprof protocol. - // See https://github.com/google/pprof/blob/master/proto/profile.proto - const ( - Profile_sample_type = 1 // repeated ValueType - Profile_sample = 2 // repeated Sample - Profile_mapping = 3 // repeated Mapping - Profile_location = 4 // repeated Location - Profile_function = 5 // repeated Function - Profile_string_table = 6 // repeated string - Profile_time_nanos = 9 // int64 - Profile_duration_nanos = 10 // int64 - Profile_period_type = 11 // ValueType - Profile_period = 12 // int64 - - ValueType_type = 1 // int64 - ValueType_unit = 2 // int64 - - Sample_location_id = 1 // repeated uint64 - Sample_value = 2 // repeated int64 - Sample_label = 3 // repeated Label - - Label_key = 1 // int64 - Label_str = 2 // int64 - Label_num = 3 // int64 - Label_num_unit = 4 // int64 - - Location_id = 1 // uint64 - Location_mapping_id = 2 // uint64 - Location_address = 3 // uint64 - Location_line = 4 // repeated Line - - Line_function_id = 1 // uint64 - Line_line = 2 // int64 - - Function_id = 1 // uint64 - Function_name = 2 // int64 - Function_system_name = 3 // int64 - Function_filename = 4 // int64 - Function_start_line = 5 // int64 - ) - - bufw := bufio.NewWriter(w) // write file in 4KB (not 240B flate-sized) chunks - gz := gzip.NewWriter(bufw) - enc := protoEncoder{w: gz} - - // strings - stringIndex := make(map[string]int64) - str := func(s string) int64 { - i, ok := stringIndex[s] - if !ok { - i = int64(len(stringIndex)) - enc.string(Profile_string_table, s) - stringIndex[s] = i - } - return i - } - str("") // entry 0 - - // functions - // - // function returns the ID of a Callable for use in Line.FunctionId. - // The ID is the same as the function's logical address, - // which is supplied by the caller to avoid the need to recompute it. - functionId := make(map[uintptr]uint64) - function := func(fn Callable, addr uintptr) uint64 { - id, ok := functionId[addr] - if !ok { - id = uint64(addr) - - var pos syntax.Position - if fn, ok := fn.(callableWithPosition); ok { - pos = fn.Position() - } - - name := fn.Name() - if name == "" { - name = pos.Filename() - } - - nameIndex := str(name) - - fun := new(bytes.Buffer) - funenc := protoEncoder{w: fun} - funenc.uint(Function_id, id) - funenc.int(Function_name, nameIndex) - funenc.int(Function_system_name, nameIndex) - funenc.int(Function_filename, str(pos.Filename())) - funenc.int(Function_start_line, int64(pos.Line)) - enc.bytes(Profile_function, fun.Bytes()) - - functionId[addr] = id - } - return id - } - - // locations - // - // location returns the ID of the location denoted by fr. - // For Starlark frames, this is the Frame pc. - locationId := make(map[uintptr]uint64) - location := func(fr profFrame) uint64 { - fnAddr := profFuncAddr(fr.fn) - - // For Starlark functions, the frame position - // represents the current PC value. - // Mix it into the low bits of the address. - // This is super hacky and may result in collisions - // in large functions or if functions are numerous. - // TODO(adonovan): fix: try making this cleaner by treating - // each bytecode segment as a Profile.Mapping. - pcAddr := fnAddr - if _, ok := fr.fn.(*Function); ok { - pcAddr = (pcAddr << 16) ^ uintptr(fr.pc) - } - - id, ok := locationId[pcAddr] - if !ok { - id = uint64(pcAddr) - - line := new(bytes.Buffer) - lineenc := protoEncoder{w: line} - lineenc.uint(Line_function_id, function(fr.fn, fnAddr)) - lineenc.int(Line_line, int64(fr.pos.Line)) - loc := new(bytes.Buffer) - locenc := protoEncoder{w: loc} - locenc.uint(Location_id, id) - locenc.uint(Location_address, uint64(pcAddr)) - locenc.bytes(Location_line, line.Bytes()) - enc.bytes(Profile_location, loc.Bytes()) - - locationId[pcAddr] = id - } - return id - } - - wallNanos := new(bytes.Buffer) - wnenc := protoEncoder{w: wallNanos} - wnenc.int(ValueType_type, str("wall")) - wnenc.int(ValueType_unit, str("nanoseconds")) - - // informational fields of Profile - enc.bytes(Profile_sample_type, wallNanos.Bytes()) - enc.int(Profile_period, quantum.Nanoseconds()) // magnitude of sampling period - enc.bytes(Profile_period_type, wallNanos.Bytes()) // dimension and unit of period - enc.int(Profile_time_nanos, time.Now().UnixNano()) // start (real) time of profile - - startNano := nanotime() - - // Read profile events from the channel - // until it is closed by StopProfiler. - for e := range profiler.events { - sample := new(bytes.Buffer) - sampleenc := protoEncoder{w: sample} - sampleenc.int(Sample_value, e.time.Nanoseconds()) // wall nanoseconds - for _, fr := range e.stack { - sampleenc.uint(Sample_location_id, location(fr)) - } - enc.bytes(Profile_sample, sample.Bytes()) - } - - endNano := nanotime() - enc.int(Profile_duration_nanos, endNano-startNano) - - err := gz.Close() // Close reports any prior write error - if flushErr := bufw.Flush(); err == nil { - err = flushErr - } - profiler.done <- err -} - -// nanotime returns the time in nanoseconds since epoch. -// It is implemented by runtime.nanotime using the linkname hack; -// runtime.nanotime is defined for all OSs/ARCHS and uses the -// monotonic system clock, which there is no portable way to access. -// Should that function ever go away, these alternatives exist: -// -// // POSIX only. REALTIME not MONOTONIC. 17ns. -// var tv syscall.Timeval -// syscall.Gettimeofday(&tv) // can't fail -// return tv.Nano() -// -// // Portable. REALTIME not MONOTONIC. 46ns. -// return time.Now().Nanoseconds() -// -// // POSIX only. Adds a dependency. -// import "golang.org/x/sys/unix" -// var ts unix.Timespec -// unix.ClockGettime(CLOCK_MONOTONIC, &ts) // can't fail -// return unix.TimespecToNsec(ts) -// -//go:linkname nanotime runtime.nanotime -func nanotime() int64 - -// profFuncAddr returns the canonical "address" -// of a Callable for use by the profiler. -func profFuncAddr(fn Callable) uintptr { - switch fn := fn.(type) { - case *Builtin: - return reflect.ValueOf(fn.fn).Pointer() - case *Function: - return uintptr(unsafe.Pointer(fn.funcode)) - } - - // User-defined callable types are typically of - // of kind pointer-to-struct. Handle them specially. - if v := reflect.ValueOf(fn); v.Type().Kind() == reflect.Ptr { - return v.Pointer() - } - - // Address zero is reserved by the protocol. - // Use 1 for callables we don't recognize. - log.Printf("Starlark profiler: no address for Callable %T", fn) - return 1 -} - -// We encode the protocol message by hand to avoid making -// the interpreter depend on both github.com/google/pprof -// and github.com/golang/protobuf. -// -// This also avoids the need to materialize a protocol message object -// tree of unbounded size and serialize it all at the end. -// The pprof format appears to have been designed to -// permit streaming implementations such as this one. -// -// See https://developers.google.com/protocol-buffers/docs/encoding. -type protoEncoder struct { - w io.Writer // *bytes.Buffer or *gzip.Writer - tmp [binary.MaxVarintLen64]byte -} - -func (e *protoEncoder) uvarint(x uint64) { - n := binary.PutUvarint(e.tmp[:], x) - e.w.Write(e.tmp[:n]) -} - -func (e *protoEncoder) tag(field, wire uint) { - e.uvarint(uint64(field<<3 | wire)) -} - -func (e *protoEncoder) string(field uint, s string) { - e.tag(field, 2) // length-delimited - e.uvarint(uint64(len(s))) - io.WriteString(e.w, s) -} - -func (e *protoEncoder) bytes(field uint, b []byte) { - e.tag(field, 2) // length-delimited - e.uvarint(uint64(len(b))) - e.w.Write(b) -} - -func (e *protoEncoder) uint(field uint, x uint64) { - e.tag(field, 0) // varint - e.uvarint(x) -} - -func (e *protoEncoder) int(field uint, x int64) { - e.tag(field, 0) // varint - e.uvarint(uint64(x)) -} diff --git a/tests/vendor/go.starlark.net/starlark/unpack.go b/tests/vendor/go.starlark.net/starlark/unpack.go deleted file mode 100644 index 316858992..000000000 --- a/tests/vendor/go.starlark.net/starlark/unpack.go +++ /dev/null @@ -1,355 +0,0 @@ -package starlark - -// This file defines the Unpack helper functions used by -// built-in functions to interpret their call arguments. - -import ( - "fmt" - "log" - "reflect" - "strings" - - "go.starlark.net/internal/spell" -) - -// An Unpacker defines custom argument unpacking behavior. -// See UnpackArgs. -type Unpacker interface { - Unpack(v Value) error -} - -// UnpackArgs unpacks the positional and keyword arguments into the -// supplied parameter variables. pairs is an alternating list of names -// and pointers to variables. -// -// If the variable is a bool, integer, string, *List, *Dict, Callable, -// Iterable, or user-defined implementation of Value, -// UnpackArgs performs the appropriate type check. -// Predeclared Go integer types uses the AsInt check. -// -// If the parameter name ends with "?", it is optional. -// -// If the parameter name ends with "??", it is optional and treats the None value -// as if the argument was absent. -// -// If a parameter is marked optional, then all following parameters are -// implicitly optional where or not they are marked. -// -// If the variable implements Unpacker, its Unpack argument -// is called with the argument value, allowing an application -// to define its own argument validation and conversion. -// -// If the variable implements Value, UnpackArgs may call -// its Type() method while constructing the error message. -// -// Examples: -// -// var ( -// a Value -// b = MakeInt(42) -// c Value = starlark.None -// ) -// -// // 1. mixed parameters, like def f(a, b=42, c=None). -// err := UnpackArgs("f", args, kwargs, "a", &a, "b?", &b, "c?", &c) -// -// // 2. keyword parameters only, like def f(*, a, b, c=None). -// if len(args) > 0 { -// return fmt.Errorf("f: unexpected positional arguments") -// } -// err := UnpackArgs("f", args, kwargs, "a", &a, "b?", &b, "c?", &c) -// -// // 3. positional parameters only, like def f(a, b=42, c=None, /) in Python 3.8. -// err := UnpackPositionalArgs("f", args, kwargs, 1, &a, &b, &c) -// -// More complex forms such as def f(a, b=42, *args, c, d=123, **kwargs) -// require additional logic, but their need in built-ins is exceedingly rare. -// -// In the examples above, the declaration of b with type Int causes UnpackArgs -// to require that b's argument value, if provided, is also an int. -// To allow arguments of any type, while retaining the default value of 42, -// declare b as a Value: -// -// var b Value = MakeInt(42) -// -// The zero value of a variable of type Value, such as 'a' in the -// examples above, is not a valid Starlark value, so if the parameter is -// optional, the caller must explicitly handle the default case by -// interpreting nil as None or some computed default. The same is true -// for the zero values of variables of type *List, *Dict, Callable, or -// Iterable. For example: -// -// // def myfunc(d=None, e=[], f={}) -// var ( -// d Value -// e *List -// f *Dict -// ) -// err := UnpackArgs("myfunc", args, kwargs, "d?", &d, "e?", &e, "f?", &f) -// if d == nil { d = None; } -// if e == nil { e = new(List); } -// if f == nil { f = new(Dict); } -// -func UnpackArgs(fnname string, args Tuple, kwargs []Tuple, pairs ...interface{}) error { - nparams := len(pairs) / 2 - var defined intset - defined.init(nparams) - - paramName := func(x interface{}) (name string, skipNone bool) { // (no free variables) - name = x.(string) - if strings.HasSuffix(name, "??") { - name = strings.TrimSuffix(name, "??") - skipNone = true - } else if name[len(name)-1] == '?' { - name = name[:len(name)-1] - } - - return name, skipNone - } - - // positional arguments - if len(args) > nparams { - return fmt.Errorf("%s: got %d arguments, want at most %d", - fnname, len(args), nparams) - } - for i, arg := range args { - defined.set(i) - name, skipNone := paramName(pairs[2*i]) - if skipNone { - if _, isNone := arg.(NoneType); isNone { - continue - } - } - if err := unpackOneArg(arg, pairs[2*i+1]); err != nil { - return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err) - } - } - - // keyword arguments -kwloop: - for _, item := range kwargs { - name, arg := item[0].(String), item[1] - for i := 0; i < nparams; i++ { - pName, skipNone := paramName(pairs[2*i]) - if pName == string(name) { - // found it - if defined.set(i) { - return fmt.Errorf("%s: got multiple values for keyword argument %s", - fnname, name) - } - - if skipNone { - if _, isNone := arg.(NoneType); isNone { - continue kwloop - } - } - - ptr := pairs[2*i+1] - if err := unpackOneArg(arg, ptr); err != nil { - return fmt.Errorf("%s: for parameter %s: %s", fnname, name, err) - } - continue kwloop - } - } - err := fmt.Errorf("%s: unexpected keyword argument %s", fnname, name) - names := make([]string, 0, nparams) - for i := 0; i < nparams; i += 2 { - param, _ := paramName(pairs[i]) - names = append(names, param) - } - if n := spell.Nearest(string(name), names); n != "" { - err = fmt.Errorf("%s (did you mean %s?)", err.Error(), n) - } - return err - } - - // Check that all non-optional parameters are defined. - // (We needn't check the first len(args).) - for i := len(args); i < nparams; i++ { - name := pairs[2*i].(string) - if strings.HasSuffix(name, "?") { - break // optional - } - if !defined.get(i) { - return fmt.Errorf("%s: missing argument for %s", fnname, name) - } - } - - return nil -} - -// UnpackPositionalArgs unpacks the positional arguments into -// corresponding variables. Each element of vars is a pointer; see -// UnpackArgs for allowed types and conversions. -// -// UnpackPositionalArgs reports an error if the number of arguments is -// less than min or greater than len(vars), if kwargs is nonempty, or if -// any conversion fails. -// -// See UnpackArgs for general comments. -func UnpackPositionalArgs(fnname string, args Tuple, kwargs []Tuple, min int, vars ...interface{}) error { - if len(kwargs) > 0 { - return fmt.Errorf("%s: unexpected keyword arguments", fnname) - } - max := len(vars) - if len(args) < min { - var atleast string - if min < max { - atleast = "at least " - } - return fmt.Errorf("%s: got %d arguments, want %s%d", fnname, len(args), atleast, min) - } - if len(args) > max { - var atmost string - if max > min { - atmost = "at most " - } - return fmt.Errorf("%s: got %d arguments, want %s%d", fnname, len(args), atmost, max) - } - for i, arg := range args { - if err := unpackOneArg(arg, vars[i]); err != nil { - return fmt.Errorf("%s: for parameter %d: %s", fnname, i+1, err) - } - } - return nil -} - -func unpackOneArg(v Value, ptr interface{}) error { - // On failure, don't clobber *ptr. - switch ptr := ptr.(type) { - case Unpacker: - return ptr.Unpack(v) - case *Value: - *ptr = v - case *string: - s, ok := AsString(v) - if !ok { - return fmt.Errorf("got %s, want string", v.Type()) - } - *ptr = s - case *bool: - b, ok := v.(Bool) - if !ok { - return fmt.Errorf("got %s, want bool", v.Type()) - } - *ptr = bool(b) - case *int, *int8, *int16, *int32, *int64, - *uint, *uint8, *uint16, *uint32, *uint64, *uintptr: - return AsInt(v, ptr) - case *float64: - f, ok := v.(Float) - if !ok { - return fmt.Errorf("got %s, want float", v.Type()) - } - *ptr = float64(f) - case **List: - list, ok := v.(*List) - if !ok { - return fmt.Errorf("got %s, want list", v.Type()) - } - *ptr = list - case **Dict: - dict, ok := v.(*Dict) - if !ok { - return fmt.Errorf("got %s, want dict", v.Type()) - } - *ptr = dict - case *Callable: - f, ok := v.(Callable) - if !ok { - return fmt.Errorf("got %s, want callable", v.Type()) - } - *ptr = f - case *Iterable: - it, ok := v.(Iterable) - if !ok { - return fmt.Errorf("got %s, want iterable", v.Type()) - } - *ptr = it - default: - // v must have type *V, where V is some subtype of starlark.Value. - ptrv := reflect.ValueOf(ptr) - if ptrv.Kind() != reflect.Ptr { - log.Panicf("internal error: not a pointer: %T", ptr) - } - paramVar := ptrv.Elem() - if !reflect.TypeOf(v).AssignableTo(paramVar.Type()) { - // The value is not assignable to the variable. - - // Detect a possible bug in the Go program that called Unpack: - // If the variable *ptr is not a subtype of Value, - // no value of v can possibly work. - if !paramVar.Type().AssignableTo(reflect.TypeOf(new(Value)).Elem()) { - log.Panicf("pointer element type does not implement Value: %T", ptr) - } - - // Report Starlark dynamic type error. - // - // We prefer the Starlark Value.Type name over - // its Go reflect.Type name, but calling the - // Value.Type method on the variable is not safe - // in general. If the variable is an interface, - // the call will fail. Even if the variable has - // a concrete type, it might not be safe to call - // Type() on a zero instance. Thus we must use - // recover. - - // Default to Go reflect.Type name - paramType := paramVar.Type().String() - - // Attempt to call Value.Type method. - func() { - defer func() { recover() }() - if typer, _ := paramVar.Interface().(interface{ Type() string }); typer != nil { - paramType = typer.Type() - } - }() - return fmt.Errorf("got %s, want %s", v.Type(), paramType) - } - paramVar.Set(reflect.ValueOf(v)) - } - return nil -} - -type intset struct { - small uint64 // bitset, used if n < 64 - large map[int]bool // set, used if n >= 64 -} - -func (is *intset) init(n int) { - if n >= 64 { - is.large = make(map[int]bool) - } -} - -func (is *intset) set(i int) (prev bool) { - if is.large == nil { - prev = is.small&(1< Hash(x) == Hash(y). - // Hash may fail if the value's type is not hashable, or if the value - // contains a non-hashable value. The hash is used only by dictionaries and - // is not exposed to the Starlark program. - Hash() (uint32, error) -} - -// A Comparable is a value that defines its own equivalence relation and -// perhaps ordered comparisons. -type Comparable interface { - Value - // CompareSameType compares one value to another of the same Type(). - // The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE. - // CompareSameType returns an error if an ordered comparison was - // requested for a type that does not support it. - // - // Implementations that recursively compare subcomponents of - // the value should use the CompareDepth function, not Compare, to - // avoid infinite recursion on cyclic structures. - // - // The depth parameter is used to bound comparisons of cyclic - // data structures. Implementations should decrement depth - // before calling CompareDepth and should return an error if depth - // < 1. - // - // Client code should not call this method. Instead, use the - // standalone Compare or Equals functions, which are defined for - // all pairs of operands. - CompareSameType(op syntax.Token, y Value, depth int) (bool, error) -} - -// A TotallyOrdered is a type whose values form a total order: -// if x and y are of the same TotallyOrdered type, then x must be less than y, -// greater than y, or equal to y. -// -// It is simpler than Comparable and should be preferred in new code, -// but if a type implements both interfaces, Comparable takes precedence. -type TotallyOrdered interface { - Value - // Cmp compares two values x and y of the same totally ordered type. - // It returns negative if x < y, positive if x > y, and zero if the values are equal. - // - // Implementations that recursively compare subcomponents of - // the value should use the CompareDepth function, not Cmp, to - // avoid infinite recursion on cyclic structures. - // - // The depth parameter is used to bound comparisons of cyclic - // data structures. Implementations should decrement depth - // before calling CompareDepth and should return an error if depth - // < 1. - // - // Client code should not call this method. Instead, use the - // standalone Compare or Equals functions, which are defined for - // all pairs of operands. - Cmp(y Value, depth int) (int, error) -} - -var ( - _ TotallyOrdered = Int{} - _ TotallyOrdered = Float(0) - _ Comparable = False - _ Comparable = String("") - _ Comparable = (*Dict)(nil) - _ Comparable = (*List)(nil) - _ Comparable = Tuple(nil) - _ Comparable = (*Set)(nil) -) - -// A Callable value f may be the operand of a function call, f(x). -// -// Clients should use the Call function, never the CallInternal method. -type Callable interface { - Value - Name() string - CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) -} - -type callableWithPosition interface { - Callable - Position() syntax.Position -} - -var ( - _ Callable = (*Builtin)(nil) - _ Callable = (*Function)(nil) - _ callableWithPosition = (*Function)(nil) -) - -// An Iterable abstracts a sequence of values. -// An iterable value may be iterated over by a 'for' loop or used where -// any other Starlark iterable is allowed. Unlike a Sequence, the length -// of an Iterable is not necessarily known in advance of iteration. -type Iterable interface { - Value - Iterate() Iterator // must be followed by call to Iterator.Done -} - -// A Sequence is a sequence of values of known length. -type Sequence interface { - Iterable - Len() int -} - -var ( - _ Sequence = (*Dict)(nil) - _ Sequence = (*Set)(nil) -) - -// An Indexable is a sequence of known length that supports efficient random access. -// It is not necessarily iterable. -type Indexable interface { - Value - Index(i int) Value // requires 0 <= i < Len() - Len() int -} - -// A Sliceable is a sequence that can be cut into pieces with the slice operator (x[i:j:step]). -// -// All native indexable objects are sliceable. -// This is a separate interface for backwards-compatibility. -type Sliceable interface { - Indexable - // For positive strides (step > 0), 0 <= start <= end <= n. - // For negative strides (step < 0), -1 <= end <= start < n. - // The caller must ensure that the start and end indices are valid - // and that step is non-zero. - Slice(start, end, step int) Value -} - -// A HasSetIndex is an Indexable value whose elements may be assigned (x[i] = y). -// -// The implementation should not add Len to a negative index as the -// evaluator does this before the call. -type HasSetIndex interface { - Indexable - SetIndex(index int, v Value) error -} - -var ( - _ HasSetIndex = (*List)(nil) - _ Indexable = Tuple(nil) - _ Indexable = String("") - _ Sliceable = Tuple(nil) - _ Sliceable = String("") - _ Sliceable = (*List)(nil) -) - -// An Iterator provides a sequence of values to the caller. -// -// The caller must call Done when the iterator is no longer needed. -// Operations that modify a sequence will fail if it has active iterators. -// -// Example usage: -// -// iter := iterable.Iterator() -// defer iter.Done() -// var x Value -// for iter.Next(&x) { -// ... -// } -type Iterator interface { - // If the iterator is exhausted, Next returns false. - // Otherwise it sets *p to the current element of the sequence, - // advances the iterator, and returns true. - Next(p *Value) bool - Done() -} - -// A Mapping is a mapping from keys to values, such as a dictionary. -// -// If a type satisfies both Mapping and Iterable, the iterator yields -// the keys of the mapping. -type Mapping interface { - Value - // Get returns the value corresponding to the specified key, - // or !found if the mapping does not contain the key. - // - // Get also defines the behavior of "v in mapping". - // The 'in' operator reports the 'found' component, ignoring errors. - Get(Value) (v Value, found bool, err error) -} - -// An IterableMapping is a mapping that supports key enumeration. -type IterableMapping interface { - Mapping - Iterate() Iterator // see Iterable interface - Items() []Tuple // a new slice containing all key/value pairs -} - -var _ IterableMapping = (*Dict)(nil) - -// A HasSetKey supports map update using x[k]=v syntax, like a dictionary. -type HasSetKey interface { - Mapping - SetKey(k, v Value) error -} - -var _ HasSetKey = (*Dict)(nil) - -// A HasBinary value may be used as either operand of these binary operators: -// + - * / // % in not in | & ^ << >> -// -// The Side argument indicates whether the receiver is the left or right operand. -// -// An implementation may decline to handle an operation by returning (nil, nil). -// For this reason, clients should always call the standalone Binary(op, x, y) -// function rather than calling the method directly. -type HasBinary interface { - Value - Binary(op syntax.Token, y Value, side Side) (Value, error) -} - -type Side bool - -const ( - Left Side = false - Right Side = true -) - -// A HasUnary value may be used as the operand of these unary operators: -// + - ~ -// -// An implementation may decline to handle an operation by returning (nil, nil). -// For this reason, clients should always call the standalone Unary(op, x) -// function rather than calling the method directly. -type HasUnary interface { - Value - Unary(op syntax.Token) (Value, error) -} - -// A HasAttrs value has fields or methods that may be read by a dot expression (y = x.f). -// Attribute names may be listed using the built-in 'dir' function. -// -// For implementation convenience, a result of (nil, nil) from Attr is -// interpreted as a "no such field or method" error. Implementations are -// free to return a more precise error. -type HasAttrs interface { - Value - Attr(name string) (Value, error) // returns (nil, nil) if attribute not present - AttrNames() []string // callers must not modify the result. -} - -var ( - _ HasAttrs = String("") - _ HasAttrs = new(List) - _ HasAttrs = new(Dict) - _ HasAttrs = new(Set) -) - -// A HasSetField value has fields that may be written by a dot expression (x.f = y). -// -// An implementation of SetField may return a NoSuchAttrError, -// in which case the runtime may augment the error message to -// warn of possible misspelling. -type HasSetField interface { - HasAttrs - SetField(name string, val Value) error -} - -// A NoSuchAttrError may be returned by an implementation of -// HasAttrs.Attr or HasSetField.SetField to indicate that no such field -// exists. In that case the runtime may augment the error message to -// warn of possible misspelling. -type NoSuchAttrError string - -func (e NoSuchAttrError) Error() string { return string(e) } - -// NoneType is the type of None. Its only legal value is None. -// (We represent it as a number, not struct{}, so that None may be constant.) -type NoneType byte - -const None = NoneType(0) - -func (NoneType) String() string { return "None" } -func (NoneType) Type() string { return "NoneType" } -func (NoneType) Freeze() {} // immutable -func (NoneType) Truth() Bool { return False } -func (NoneType) Hash() (uint32, error) { return 0, nil } - -// Bool is the type of a Starlark bool. -type Bool bool - -const ( - False Bool = false - True Bool = true -) - -func (b Bool) String() string { - if b { - return "True" - } else { - return "False" - } -} -func (b Bool) Type() string { return "bool" } -func (b Bool) Freeze() {} // immutable -func (b Bool) Truth() Bool { return b } -func (b Bool) Hash() (uint32, error) { return uint32(b2i(bool(b))), nil } -func (x Bool) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { - y := y_.(Bool) - return threeway(op, b2i(bool(x))-b2i(bool(y))), nil -} - -// Float is the type of a Starlark float. -type Float float64 - -func (f Float) String() string { - var buf strings.Builder - f.format(&buf, 'g') - return buf.String() -} - -func (f Float) format(buf *strings.Builder, conv byte) { - ff := float64(f) - if !isFinite(ff) { - if math.IsInf(ff, +1) { - buf.WriteString("+inf") - } else if math.IsInf(ff, -1) { - buf.WriteString("-inf") - } else { - buf.WriteString("nan") - } - return - } - - // %g is the default format used by str. - // It uses the minimum precision to avoid ambiguity, - // and always includes a '.' or an 'e' so that the value - // is self-evidently a float, not an int. - if conv == 'g' || conv == 'G' { - s := strconv.FormatFloat(ff, conv, -1, 64) - buf.WriteString(s) - // Ensure result always has a decimal point if no exponent. - // "123" -> "123.0" - if strings.IndexByte(s, conv-'g'+'e') < 0 && strings.IndexByte(s, '.') < 0 { - buf.WriteString(".0") - } - return - } - - // %[eEfF] use 6-digit precision - buf.WriteString(strconv.FormatFloat(ff, conv, 6, 64)) -} - -func (f Float) Type() string { return "float" } -func (f Float) Freeze() {} // immutable -func (f Float) Truth() Bool { return f != 0.0 } -func (f Float) Hash() (uint32, error) { - // Equal float and int values must yield the same hash. - // TODO(adonovan): opt: if f is non-integral, and thus not equal - // to any Int, we can avoid the Int conversion and use a cheaper hash. - if isFinite(float64(f)) { - return finiteFloatToInt(f).Hash() - } - return 1618033, nil // NaN, +/-Inf -} - -func floor(f Float) Float { return Float(math.Floor(float64(f))) } - -// isFinite reports whether f represents a finite rational value. -// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0). -func isFinite(f float64) bool { - return math.Abs(f) <= math.MaxFloat64 -} - -// Cmp implements comparison of two Float values. -// Required by the TotallyOrdered interface. -func (f Float) Cmp(v Value, depth int) (int, error) { - g := v.(Float) - return floatCmp(f, g), nil -} - -// floatCmp performs a three-valued comparison on floats, -// which are totally ordered with NaN > +Inf. -func floatCmp(x, y Float) int { - if x > y { - return +1 - } else if x < y { - return -1 - } else if x == y { - return 0 - } - - // At least one operand is NaN. - if x == x { - return -1 // y is NaN - } else if y == y { - return +1 // x is NaN - } - return 0 // both NaN -} - -func (f Float) rational() *big.Rat { return new(big.Rat).SetFloat64(float64(f)) } - -// AsFloat returns the float64 value closest to x. -// The f result is undefined if x is not a float or Int. -// The result may be infinite if x is a very large Int. -func AsFloat(x Value) (f float64, ok bool) { - switch x := x.(type) { - case Float: - return float64(x), true - case Int: - return float64(x.Float()), true - } - return 0, false -} - -func (x Float) Mod(y Float) Float { - z := Float(math.Mod(float64(x), float64(y))) - if (x < 0) != (y < 0) && z != 0 { - z += y - } - return z -} - -// Unary implements the operations +float and -float. -func (f Float) Unary(op syntax.Token) (Value, error) { - switch op { - case syntax.MINUS: - return -f, nil - case syntax.PLUS: - return +f, nil - } - return nil, nil -} - -// String is the type of a Starlark text string. -// -// A String encapsulates an an immutable sequence of bytes, -// but strings are not directly iterable. Instead, iterate -// over the result of calling one of these four methods: -// codepoints, codepoint_ords, elems, elem_ords. -// -// Strings typically contain text; use Bytes for binary strings. -// The Starlark spec defines text strings as sequences of UTF-k -// codes that encode Unicode code points. In this Go implementation, -// k=8, whereas in a Java implementation, k=16. For portability, -// operations on strings should aim to avoid assumptions about -// the value of k. -// -// Warning: the contract of the Value interface's String method is that -// it returns the value printed in Starlark notation, -// so s.String() or fmt.Sprintf("%s", s) returns a quoted string. -// Use string(s) or s.GoString() or fmt.Sprintf("%#v", s) to obtain the raw contents -// of a Starlark string as a Go string. -type String string - -func (s String) String() string { return syntax.Quote(string(s), false) } -func (s String) GoString() string { return string(s) } -func (s String) Type() string { return "string" } -func (s String) Freeze() {} // immutable -func (s String) Truth() Bool { return len(s) > 0 } -func (s String) Hash() (uint32, error) { return hashString(string(s)), nil } -func (s String) Len() int { return len(s) } // bytes -func (s String) Index(i int) Value { return s[i : i+1] } - -func (s String) Slice(start, end, step int) Value { - if step == 1 { - return s[start:end] - } - - sign := signum(step) - var str []byte - for i := start; signum(end-i) == sign; i += step { - str = append(str, s[i]) - } - return String(str) -} - -func (s String) Attr(name string) (Value, error) { return builtinAttr(s, name, stringMethods) } -func (s String) AttrNames() []string { return builtinAttrNames(stringMethods) } - -func (x String) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { - y := y_.(String) - return threeway(op, strings.Compare(string(x), string(y))), nil -} - -func AsString(x Value) (string, bool) { v, ok := x.(String); return string(v), ok } - -// A stringElems is an iterable whose iterator yields a sequence of -// elements (bytes), either numerically or as successive substrings. -// It is an indexable sequence. -type stringElems struct { - s String - ords bool -} - -var ( - _ Iterable = (*stringElems)(nil) - _ Indexable = (*stringElems)(nil) -) - -func (si stringElems) String() string { - if si.ords { - return si.s.String() + ".elem_ords()" - } else { - return si.s.String() + ".elems()" - } -} -func (si stringElems) Type() string { return "string.elems" } -func (si stringElems) Freeze() {} // immutable -func (si stringElems) Truth() Bool { return True } -func (si stringElems) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", si.Type()) } -func (si stringElems) Iterate() Iterator { return &stringElemsIterator{si, 0} } -func (si stringElems) Len() int { return len(si.s) } -func (si stringElems) Index(i int) Value { - if si.ords { - return MakeInt(int(si.s[i])) - } else { - // TODO(adonovan): opt: preallocate canonical 1-byte strings - // to avoid interface allocation. - return si.s[i : i+1] - } -} - -type stringElemsIterator struct { - si stringElems - i int -} - -func (it *stringElemsIterator) Next(p *Value) bool { - if it.i == len(it.si.s) { - return false - } - *p = it.si.Index(it.i) - it.i++ - return true -} - -func (*stringElemsIterator) Done() {} - -// A stringCodepoints is an iterable whose iterator yields a sequence of -// Unicode code points, either numerically or as successive substrings. -// It is not indexable. -type stringCodepoints struct { - s String - ords bool -} - -var _ Iterable = (*stringCodepoints)(nil) - -func (si stringCodepoints) String() string { - if si.ords { - return si.s.String() + ".codepoint_ords()" - } else { - return si.s.String() + ".codepoints()" - } -} -func (si stringCodepoints) Type() string { return "string.codepoints" } -func (si stringCodepoints) Freeze() {} // immutable -func (si stringCodepoints) Truth() Bool { return True } -func (si stringCodepoints) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", si.Type()) } -func (si stringCodepoints) Iterate() Iterator { return &stringCodepointsIterator{si, 0} } - -type stringCodepointsIterator struct { - si stringCodepoints - i int -} - -func (it *stringCodepointsIterator) Next(p *Value) bool { - s := it.si.s[it.i:] - if s == "" { - return false - } - r, sz := utf8.DecodeRuneInString(string(s)) - if !it.si.ords { - if r == utf8.RuneError { - *p = String(r) - } else { - *p = s[:sz] - } - } else { - *p = MakeInt(int(r)) - } - it.i += sz - return true -} - -func (*stringCodepointsIterator) Done() {} - -// A Function is a function defined by a Starlark def statement or lambda expression. -// The initialization behavior of a Starlark module is also represented by a Function. -type Function struct { - funcode *compile.Funcode - module *module - defaults Tuple - freevars Tuple -} - -// A module is the dynamic counterpart to a Program. -// All functions in the same program share a module. -type module struct { - program *compile.Program - predeclared StringDict - globals []Value - constants []Value -} - -// makeGlobalDict returns a new, unfrozen StringDict containing all global -// variables so far defined in the module. -func (m *module) makeGlobalDict() StringDict { - r := make(StringDict, len(m.program.Globals)) - for i, id := range m.program.Globals { - if v := m.globals[i]; v != nil { - r[id.Name] = v - } - } - return r -} - -func (fn *Function) Name() string { return fn.funcode.Name } // "lambda" for anonymous functions -func (fn *Function) Doc() string { return fn.funcode.Doc } -func (fn *Function) Hash() (uint32, error) { return hashString(fn.funcode.Name), nil } -func (fn *Function) Freeze() { fn.defaults.Freeze(); fn.freevars.Freeze() } -func (fn *Function) String() string { return toString(fn) } -func (fn *Function) Type() string { return "function" } -func (fn *Function) Truth() Bool { return true } - -// Globals returns a new, unfrozen StringDict containing all global -// variables so far defined in the function's module. -func (fn *Function) Globals() StringDict { return fn.module.makeGlobalDict() } - -func (fn *Function) Position() syntax.Position { return fn.funcode.Pos } -func (fn *Function) NumParams() int { return fn.funcode.NumParams } -func (fn *Function) NumKwonlyParams() int { return fn.funcode.NumKwonlyParams } - -// Param returns the name and position of the ith parameter, -// where 0 <= i < NumParams(). -// The *args and **kwargs parameters are at the end -// even if there were optional parameters after *args. -func (fn *Function) Param(i int) (string, syntax.Position) { - if i >= fn.NumParams() { - panic(i) - } - id := fn.funcode.Locals[i] - return id.Name, id.Pos -} - -// ParamDefault returns the default value of the specified parameter -// (0 <= i < NumParams()), or nil if the parameter is not optional. -func (fn *Function) ParamDefault(i int) Value { - if i < 0 || i >= fn.NumParams() { - panic(i) - } - - // fn.defaults omits all required params up to the first optional param. It - // also does not include *args or **kwargs at the end. - firstOptIdx := fn.NumParams() - len(fn.defaults) - if fn.HasVarargs() { - firstOptIdx-- - } - if fn.HasKwargs() { - firstOptIdx-- - } - if i < firstOptIdx || i >= firstOptIdx+len(fn.defaults) { - return nil - } - - dflt := fn.defaults[i-firstOptIdx] - if _, ok := dflt.(mandatory); ok { - return nil - } - return dflt -} - -func (fn *Function) HasVarargs() bool { return fn.funcode.HasVarargs } -func (fn *Function) HasKwargs() bool { return fn.funcode.HasKwargs } - -// A Builtin is a function implemented in Go. -type Builtin struct { - name string - fn func(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error) - recv Value // for bound methods (e.g. "".startswith) -} - -func (b *Builtin) Name() string { return b.name } -func (b *Builtin) Freeze() { - if b.recv != nil { - b.recv.Freeze() - } -} -func (b *Builtin) Hash() (uint32, error) { - h := hashString(b.name) - if b.recv != nil { - h ^= 5521 - } - return h, nil -} -func (b *Builtin) Receiver() Value { return b.recv } -func (b *Builtin) String() string { return toString(b) } -func (b *Builtin) Type() string { return "builtin_function_or_method" } -func (b *Builtin) CallInternal(thread *Thread, args Tuple, kwargs []Tuple) (Value, error) { - return b.fn(thread, b, args, kwargs) -} -func (b *Builtin) Truth() Bool { return true } - -// NewBuiltin returns a new 'builtin_function_or_method' value with the specified name -// and implementation. It compares unequal with all other values. -func NewBuiltin(name string, fn func(thread *Thread, fn *Builtin, args Tuple, kwargs []Tuple) (Value, error)) *Builtin { - return &Builtin{name: name, fn: fn} -} - -// BindReceiver returns a new Builtin value representing a method -// closure, that is, a built-in function bound to a receiver value. -// -// In the example below, the value of f is the string.index -// built-in method bound to the receiver value "abc": -// -// f = "abc".index; f("a"); f("b") -// -// In the common case, the receiver is bound only during the call, -// but this still results in the creation of a temporary method closure: -// -// "abc".index("a") -func (b *Builtin) BindReceiver(recv Value) *Builtin { - return &Builtin{name: b.name, fn: b.fn, recv: recv} -} - -// A *Dict represents a Starlark dictionary. -// The zero value of Dict is a valid empty dictionary. -// If you know the exact final number of entries, -// it is more efficient to call NewDict. -type Dict struct { - ht hashtable -} - -// NewDict returns a set with initial space for -// at least size insertions before rehashing. -func NewDict(size int) *Dict { - dict := new(Dict) - dict.ht.init(size) - return dict -} - -func (d *Dict) Clear() error { return d.ht.clear() } -func (d *Dict) Delete(k Value) (v Value, found bool, err error) { return d.ht.delete(k) } -func (d *Dict) Get(k Value) (v Value, found bool, err error) { return d.ht.lookup(k) } -func (d *Dict) Items() []Tuple { return d.ht.items() } -func (d *Dict) Keys() []Value { return d.ht.keys() } -func (d *Dict) Len() int { return int(d.ht.len) } -func (d *Dict) Iterate() Iterator { return d.ht.iterate() } -func (d *Dict) SetKey(k, v Value) error { return d.ht.insert(k, v) } -func (d *Dict) String() string { return toString(d) } -func (d *Dict) Type() string { return "dict" } -func (d *Dict) Freeze() { d.ht.freeze() } -func (d *Dict) Truth() Bool { return d.Len() > 0 } -func (d *Dict) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: dict") } - -func (x *Dict) Union(y *Dict) *Dict { - z := new(Dict) - z.ht.init(x.Len()) // a lower bound - z.ht.addAll(&x.ht) // can't fail - z.ht.addAll(&y.ht) // can't fail - return z -} - -func (d *Dict) Attr(name string) (Value, error) { return builtinAttr(d, name, dictMethods) } -func (d *Dict) AttrNames() []string { return builtinAttrNames(dictMethods) } - -func (x *Dict) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { - y := y_.(*Dict) - switch op { - case syntax.EQL: - ok, err := dictsEqual(x, y, depth) - return ok, err - case syntax.NEQ: - ok, err := dictsEqual(x, y, depth) - return !ok, err - default: - return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) - } -} - -func dictsEqual(x, y *Dict, depth int) (bool, error) { - if x.Len() != y.Len() { - return false, nil - } - for e := x.ht.head; e != nil; e = e.next { - key, xval := e.key, e.value - - if yval, found, _ := y.Get(key); !found { - return false, nil - } else if eq, err := EqualDepth(xval, yval, depth-1); err != nil { - return false, err - } else if !eq { - return false, nil - } - } - return true, nil -} - -// A *List represents a Starlark list value. -type List struct { - elems []Value - frozen bool - itercount uint32 // number of active iterators (ignored if frozen) -} - -// NewList returns a list containing the specified elements. -// Callers should not subsequently modify elems. -func NewList(elems []Value) *List { return &List{elems: elems} } - -func (l *List) Freeze() { - if !l.frozen { - l.frozen = true - for _, elem := range l.elems { - elem.Freeze() - } - } -} - -// checkMutable reports an error if the list should not be mutated. -// verb+" list" should describe the operation. -func (l *List) checkMutable(verb string) error { - if l.frozen { - return fmt.Errorf("cannot %s frozen list", verb) - } - if l.itercount > 0 { - return fmt.Errorf("cannot %s list during iteration", verb) - } - return nil -} - -func (l *List) String() string { return toString(l) } -func (l *List) Type() string { return "list" } -func (l *List) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: list") } -func (l *List) Truth() Bool { return l.Len() > 0 } -func (l *List) Len() int { return len(l.elems) } -func (l *List) Index(i int) Value { return l.elems[i] } - -func (l *List) Slice(start, end, step int) Value { - if step == 1 { - elems := append([]Value{}, l.elems[start:end]...) - return NewList(elems) - } - - sign := signum(step) - var list []Value - for i := start; signum(end-i) == sign; i += step { - list = append(list, l.elems[i]) - } - return NewList(list) -} - -func (l *List) Attr(name string) (Value, error) { return builtinAttr(l, name, listMethods) } -func (l *List) AttrNames() []string { return builtinAttrNames(listMethods) } - -func (l *List) Iterate() Iterator { - if !l.frozen { - l.itercount++ - } - return &listIterator{l: l} -} - -func (x *List) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { - y := y_.(*List) - // It's tempting to check x == y as an optimization here, - // but wrong because a list containing NaN is not equal to itself. - return sliceCompare(op, x.elems, y.elems, depth) -} - -func sliceCompare(op syntax.Token, x, y []Value, depth int) (bool, error) { - // Fast path: check length. - if len(x) != len(y) && (op == syntax.EQL || op == syntax.NEQ) { - return op == syntax.NEQ, nil - } - - // Find first element that is not equal in both lists. - for i := 0; i < len(x) && i < len(y); i++ { - if eq, err := EqualDepth(x[i], y[i], depth-1); err != nil { - return false, err - } else if !eq { - switch op { - case syntax.EQL: - return false, nil - case syntax.NEQ: - return true, nil - default: - return CompareDepth(op, x[i], y[i], depth-1) - } - } - } - - return threeway(op, len(x)-len(y)), nil -} - -type listIterator struct { - l *List - i int -} - -func (it *listIterator) Next(p *Value) bool { - if it.i < it.l.Len() { - *p = it.l.elems[it.i] - it.i++ - return true - } - return false -} - -func (it *listIterator) Done() { - if !it.l.frozen { - it.l.itercount-- - } -} - -func (l *List) SetIndex(i int, v Value) error { - if err := l.checkMutable("assign to element of"); err != nil { - return err - } - l.elems[i] = v - return nil -} - -func (l *List) Append(v Value) error { - if err := l.checkMutable("append to"); err != nil { - return err - } - l.elems = append(l.elems, v) - return nil -} - -func (l *List) Clear() error { - if err := l.checkMutable("clear"); err != nil { - return err - } - for i := range l.elems { - l.elems[i] = nil // aid GC - } - l.elems = l.elems[:0] - return nil -} - -// A Tuple represents a Starlark tuple value. -type Tuple []Value - -func (t Tuple) Len() int { return len(t) } -func (t Tuple) Index(i int) Value { return t[i] } - -func (t Tuple) Slice(start, end, step int) Value { - if step == 1 { - return t[start:end] - } - - sign := signum(step) - var tuple Tuple - for i := start; signum(end-i) == sign; i += step { - tuple = append(tuple, t[i]) - } - return tuple -} - -func (t Tuple) Iterate() Iterator { return &tupleIterator{elems: t} } -func (t Tuple) Freeze() { - for _, elem := range t { - elem.Freeze() - } -} -func (t Tuple) String() string { return toString(t) } -func (t Tuple) Type() string { return "tuple" } -func (t Tuple) Truth() Bool { return len(t) > 0 } - -func (x Tuple) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { - y := y_.(Tuple) - return sliceCompare(op, x, y, depth) -} - -func (t Tuple) Hash() (uint32, error) { - // Use same algorithm as Python. - var x, mult uint32 = 0x345678, 1000003 - for _, elem := range t { - y, err := elem.Hash() - if err != nil { - return 0, err - } - x = x ^ y*mult - mult += 82520 + uint32(len(t)+len(t)) - } - return x, nil -} - -type tupleIterator struct{ elems Tuple } - -func (it *tupleIterator) Next(p *Value) bool { - if len(it.elems) > 0 { - *p = it.elems[0] - it.elems = it.elems[1:] - return true - } - return false -} - -func (it *tupleIterator) Done() {} - -// A Set represents a Starlark set value. -// The zero value of Set is a valid empty set. -// If you know the exact final number of elements, -// it is more efficient to call NewSet. -type Set struct { - ht hashtable // values are all None -} - -// NewSet returns a dictionary with initial space for -// at least size insertions before rehashing. -func NewSet(size int) *Set { - set := new(Set) - set.ht.init(size) - return set -} - -func (s *Set) Delete(k Value) (found bool, err error) { _, found, err = s.ht.delete(k); return } -func (s *Set) Clear() error { return s.ht.clear() } -func (s *Set) Has(k Value) (found bool, err error) { _, found, err = s.ht.lookup(k); return } -func (s *Set) Insert(k Value) error { return s.ht.insert(k, None) } -func (s *Set) Len() int { return int(s.ht.len) } -func (s *Set) Iterate() Iterator { return s.ht.iterate() } -func (s *Set) String() string { return toString(s) } -func (s *Set) Type() string { return "set" } -func (s *Set) Freeze() { s.ht.freeze() } -func (s *Set) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable type: set") } -func (s *Set) Truth() Bool { return s.Len() > 0 } - -func (s *Set) Attr(name string) (Value, error) { return builtinAttr(s, name, setMethods) } -func (s *Set) AttrNames() []string { return builtinAttrNames(setMethods) } - -func (x *Set) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { - y := y_.(*Set) - switch op { - case syntax.EQL: - ok, err := setsEqual(x, y, depth) - return ok, err - case syntax.NEQ: - ok, err := setsEqual(x, y, depth) - return !ok, err - case syntax.GE: // superset - if x.Len() < y.Len() { - return false, nil - } - iter := y.Iterate() - defer iter.Done() - return x.IsSuperset(iter) - case syntax.LE: // subset - if x.Len() > y.Len() { - return false, nil - } - iter := y.Iterate() - defer iter.Done() - return x.IsSubset(iter) - case syntax.GT: // proper superset - if x.Len() <= y.Len() { - return false, nil - } - iter := y.Iterate() - defer iter.Done() - return x.IsSuperset(iter) - case syntax.LT: // proper subset - if x.Len() >= y.Len() { - return false, nil - } - iter := y.Iterate() - defer iter.Done() - return x.IsSubset(iter) - default: - return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) - } -} - -func setsEqual(x, y *Set, depth int) (bool, error) { - if x.Len() != y.Len() { - return false, nil - } - for e := x.ht.head; e != nil; e = e.next { - if found, _ := y.Has(e.key); !found { - return false, nil - } - } - return true, nil -} - -func setFromIterator(iter Iterator) (*Set, error) { - var x Value - set := new(Set) - for iter.Next(&x) { - err := set.Insert(x) - if err != nil { - return set, err - } - } - return set, nil -} - -func (s *Set) clone() *Set { - set := new(Set) - for e := s.ht.head; e != nil; e = e.next { - set.Insert(e.key) // can't fail - } - return set -} - -func (s *Set) Union(iter Iterator) (Value, error) { - set := s.clone() - var x Value - for iter.Next(&x) { - if err := set.Insert(x); err != nil { - return nil, err - } - } - return set, nil -} - -func (s *Set) Difference(other Iterator) (Value, error) { - diff := s.clone() - var x Value - for other.Next(&x) { - if _, err := diff.Delete(x); err != nil { - return nil, err - } - } - return diff, nil -} - -func (s *Set) IsSuperset(other Iterator) (bool, error) { - var x Value - for other.Next(&x) { - found, err := s.Has(x) - if err != nil { - return false, err - } - if !found { - return false, nil - } - } - return true, nil -} - -func (s *Set) IsSubset(other Iterator) (bool, error) { - if count, err := s.ht.count(other); err != nil { - return false, err - } else { - return count == s.Len(), nil - } -} - -func (s *Set) Intersection(other Iterator) (Value, error) { - intersect := new(Set) - var x Value - for other.Next(&x) { - found, err := s.Has(x) - if err != nil { - return nil, err - } - if found { - err = intersect.Insert(x) - if err != nil { - return nil, err - } - } - } - return intersect, nil -} - -func (s *Set) SymmetricDifference(other Iterator) (Value, error) { - diff := s.clone() - var x Value - for other.Next(&x) { - found, err := diff.Delete(x) - if err != nil { - return nil, err - } - if !found { - diff.Insert(x) - } - } - return diff, nil -} - -// toString returns the string form of value v. -// It may be more efficient than v.String() for larger values. -func toString(v Value) string { - buf := new(strings.Builder) - writeValue(buf, v, nil) - return buf.String() -} - -// writeValue writes x to out. -// -// path is used to detect cycles. -// It contains the list of *List and *Dict values we're currently printing. -// (These are the only potentially cyclic structures.) -// Callers should generally pass nil for path. -// It is safe to re-use the same path slice for multiple calls. -func writeValue(out *strings.Builder, x Value, path []Value) { - switch x := x.(type) { - case nil: - out.WriteString("") // indicates a bug - - // These four cases are duplicates of T.String(), for efficiency. - case NoneType: - out.WriteString("None") - - case Int: - out.WriteString(x.String()) - - case Bool: - if x { - out.WriteString("True") - } else { - out.WriteString("False") - } - - case String: - out.WriteString(syntax.Quote(string(x), false)) - - case *List: - out.WriteByte('[') - if pathContains(path, x) { - out.WriteString("...") // list contains itself - } else { - for i, elem := range x.elems { - if i > 0 { - out.WriteString(", ") - } - writeValue(out, elem, append(path, x)) - } - } - out.WriteByte(']') - - case Tuple: - out.WriteByte('(') - for i, elem := range x { - if i > 0 { - out.WriteString(", ") - } - writeValue(out, elem, path) - } - if len(x) == 1 { - out.WriteByte(',') - } - out.WriteByte(')') - - case *Function: - fmt.Fprintf(out, "", x.Name()) - - case *Builtin: - if x.recv != nil { - fmt.Fprintf(out, "", x.Name(), x.recv.Type()) - } else { - fmt.Fprintf(out, "", x.Name()) - } - - case *Dict: - out.WriteByte('{') - if pathContains(path, x) { - out.WriteString("...") // dict contains itself - } else { - sep := "" - for e := x.ht.head; e != nil; e = e.next { - k, v := e.key, e.value - out.WriteString(sep) - writeValue(out, k, path) - out.WriteString(": ") - writeValue(out, v, append(path, x)) // cycle check - sep = ", " - } - } - out.WriteByte('}') - - case *Set: - out.WriteString("set([") - for e := x.ht.head; e != nil; e = e.next { - if e != x.ht.head { - out.WriteString(", ") - } - writeValue(out, e.key, path) - } - out.WriteString("])") - - default: - out.WriteString(x.String()) - } -} - -func pathContains(path []Value, x Value) bool { - for _, y := range path { - if x == y { - return true - } - } - return false -} - -// CompareLimit is the depth limit on recursive comparison operations such as == and <. -// Comparison of data structures deeper than this limit may fail. -var CompareLimit = 10 - -// Equal reports whether two Starlark values are equal. -func Equal(x, y Value) (bool, error) { - if x, ok := x.(String); ok { - return x == y, nil // fast path for an important special case - } - return EqualDepth(x, y, CompareLimit) -} - -// EqualDepth reports whether two Starlark values are equal. -// -// Recursive comparisons by implementations of Value.CompareSameType -// should use EqualDepth to prevent infinite recursion. -func EqualDepth(x, y Value, depth int) (bool, error) { - return CompareDepth(syntax.EQL, x, y, depth) -} - -// Compare compares two Starlark values. -// The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE. -// Compare returns an error if an ordered comparison was -// requested for a type that does not support it. -// -// Recursive comparisons by implementations of Value.CompareSameType -// should use CompareDepth to prevent infinite recursion. -func Compare(op syntax.Token, x, y Value) (bool, error) { - return CompareDepth(op, x, y, CompareLimit) -} - -// CompareDepth compares two Starlark values. -// The comparison operation must be one of EQL, NEQ, LT, LE, GT, or GE. -// CompareDepth returns an error if an ordered comparison was -// requested for a pair of values that do not support it. -// -// The depth parameter limits the maximum depth of recursion -// in cyclic data structures. -func CompareDepth(op syntax.Token, x, y Value, depth int) (bool, error) { - if depth < 1 { - return false, fmt.Errorf("comparison exceeded maximum recursion depth") - } - if sameType(x, y) { - if xcomp, ok := x.(Comparable); ok { - return xcomp.CompareSameType(op, y, depth) - } - - if xcomp, ok := x.(TotallyOrdered); ok { - t, err := xcomp.Cmp(y, depth) - if err != nil { - return false, err - } - return threeway(op, t), nil - } - - // use identity comparison - switch op { - case syntax.EQL: - return x == y, nil - case syntax.NEQ: - return x != y, nil - } - return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) - } - - // different types - - // int/float ordered comparisons - switch x := x.(type) { - case Int: - if y, ok := y.(Float); ok { - var cmp int - if y != y { - cmp = -1 // y is NaN - } else if !math.IsInf(float64(y), 0) { - cmp = x.rational().Cmp(y.rational()) // y is finite - } else if y > 0 { - cmp = -1 // y is +Inf - } else { - cmp = +1 // y is -Inf - } - return threeway(op, cmp), nil - } - case Float: - if y, ok := y.(Int); ok { - var cmp int - if x != x { - cmp = +1 // x is NaN - } else if !math.IsInf(float64(x), 0) { - cmp = x.rational().Cmp(y.rational()) // x is finite - } else if x > 0 { - cmp = +1 // x is +Inf - } else { - cmp = -1 // x is -Inf - } - return threeway(op, cmp), nil - } - } - - // All other values of different types compare unequal. - switch op { - case syntax.EQL: - return false, nil - case syntax.NEQ: - return true, nil - } - return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) -} - -func sameType(x, y Value) bool { - return reflect.TypeOf(x) == reflect.TypeOf(y) || x.Type() == y.Type() -} - -// threeway interprets a three-way comparison value cmp (-1, 0, +1) -// as a boolean comparison (e.g. x < y). -func threeway(op syntax.Token, cmp int) bool { - switch op { - case syntax.EQL: - return cmp == 0 - case syntax.NEQ: - return cmp != 0 - case syntax.LE: - return cmp <= 0 - case syntax.LT: - return cmp < 0 - case syntax.GE: - return cmp >= 0 - case syntax.GT: - return cmp > 0 - } - panic(op) -} - -func b2i(b bool) int { - if b { - return 1 - } else { - return 0 - } -} - -// Len returns the length of a string or sequence value, -// and -1 for all others. -// -// Warning: Len(x) >= 0 does not imply Iterate(x) != nil. -// A string has a known length but is not directly iterable. -func Len(x Value) int { - switch x := x.(type) { - case String: - return x.Len() - case Indexable: - return x.Len() - case Sequence: - return x.Len() - } - return -1 -} - -// Iterate return a new iterator for the value if iterable, nil otherwise. -// If the result is non-nil, the caller must call Done when finished with it. -// -// Warning: Iterate(x) != nil does not imply Len(x) >= 0. -// Some iterables may have unknown length. -func Iterate(x Value) Iterator { - if x, ok := x.(Iterable); ok { - return x.Iterate() - } - return nil -} - -// Bytes is the type of a Starlark binary string. -// -// A Bytes encapsulates an immutable sequence of bytes. -// It is comparable, indexable, and sliceable, but not directly iterable; -// use bytes.elems() for an iterable view. -// -// In this Go implementation, the elements of 'string' and 'bytes' are -// both bytes, but in other implementations, notably Java, the elements -// of a 'string' are UTF-16 codes (Java chars). The spec abstracts text -// strings as sequences of UTF-k codes that encode Unicode code points, -// and operations that convert from text to binary incur UTF-k-to-UTF-8 -// transcoding; conversely, conversion from binary to text incurs -// UTF-8-to-UTF-k transcoding. Because k=8 for Go, these operations -// are the identity function, at least for valid encodings of text. -type Bytes string - -var ( - _ Comparable = Bytes("") - _ Sliceable = Bytes("") - _ Indexable = Bytes("") -) - -func (b Bytes) String() string { return syntax.Quote(string(b), true) } -func (b Bytes) Type() string { return "bytes" } -func (b Bytes) Freeze() {} // immutable -func (b Bytes) Truth() Bool { return len(b) > 0 } -func (b Bytes) Hash() (uint32, error) { return String(b).Hash() } -func (b Bytes) Len() int { return len(b) } -func (b Bytes) Index(i int) Value { return b[i : i+1] } - -func (b Bytes) Attr(name string) (Value, error) { return builtinAttr(b, name, bytesMethods) } -func (b Bytes) AttrNames() []string { return builtinAttrNames(bytesMethods) } - -func (b Bytes) Slice(start, end, step int) Value { - if step == 1 { - return b[start:end] - } - - sign := signum(step) - var str []byte - for i := start; signum(end-i) == sign; i += step { - str = append(str, b[i]) - } - return Bytes(str) -} - -func (x Bytes) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) { - y := y_.(Bytes) - return threeway(op, strings.Compare(string(x), string(y))), nil -} diff --git a/tests/vendor/go.starlark.net/starlarkstruct/module.go b/tests/vendor/go.starlark.net/starlarkstruct/module.go deleted file mode 100644 index 735c98ae3..000000000 --- a/tests/vendor/go.starlark.net/starlarkstruct/module.go +++ /dev/null @@ -1,43 +0,0 @@ -package starlarkstruct - -import ( - "fmt" - - "go.starlark.net/starlark" -) - -// A Module is a named collection of values, -// typically a suite of functions imported by a load statement. -// -// It differs from Struct primarily in that its string representation -// does not enumerate its fields. -type Module struct { - Name string - Members starlark.StringDict -} - -var _ starlark.HasAttrs = (*Module)(nil) - -func (m *Module) Attr(name string) (starlark.Value, error) { return m.Members[name], nil } -func (m *Module) AttrNames() []string { return m.Members.Keys() } -func (m *Module) Freeze() { m.Members.Freeze() } -func (m *Module) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", m.Type()) } -func (m *Module) String() string { return fmt.Sprintf("", m.Name) } -func (m *Module) Truth() starlark.Bool { return true } -func (m *Module) Type() string { return "module" } - -// MakeModule may be used as the implementation of a Starlark built-in -// function, module(name, **kwargs). It returns a new module with the -// specified name and members. -func MakeModule(thread *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { - var name string - if err := starlark.UnpackPositionalArgs(b.Name(), args, nil, 1, &name); err != nil { - return nil, err - } - members := make(starlark.StringDict, len(kwargs)) - for _, kwarg := range kwargs { - k := string(kwarg[0].(starlark.String)) - members[k] = kwarg[1] - } - return &Module{name, members}, nil -} diff --git a/tests/vendor/go.starlark.net/starlarkstruct/struct.go b/tests/vendor/go.starlark.net/starlarkstruct/struct.go deleted file mode 100644 index ea2b1f639..000000000 --- a/tests/vendor/go.starlark.net/starlarkstruct/struct.go +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package starlarkstruct defines the Starlark types 'struct' and -// 'module', both optional language extensions. -// -package starlarkstruct // import "go.starlark.net/starlarkstruct" - -// It is tempting to introduce a variant of Struct that is a wrapper -// around a Go struct value, for stronger typing guarantees and more -// efficient and convenient field lookup. However: -// 1) all fields of Starlark structs are optional, so we cannot represent -// them using more specific types such as String, Int, *Depset, and -// *File, as such types give no way to represent missing fields. -// 2) the efficiency gain of direct struct field access is rather -// marginal: finding the index of a field by binary searching on the -// sorted list of field names is quite fast compared to the other -// overheads. -// 3) the gains in compactness and spatial locality are also rather -// marginal: the array behind the []entry slice is (due to field name -// strings) only a factor of 2 larger than the corresponding Go struct -// would be, and, like the Go struct, requires only a single allocation. - -import ( - "fmt" - "sort" - "strings" - - "go.starlark.net/starlark" - "go.starlark.net/syntax" -) - -// Make is the implementation of a built-in function that instantiates -// an immutable struct from the specified keyword arguments. -// -// An application can add 'struct' to the Starlark environment like so: -// -// globals := starlark.StringDict{ -// "struct": starlark.NewBuiltin("struct", starlarkstruct.Make), -// } -// -func Make(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { - if len(args) > 0 { - return nil, fmt.Errorf("struct: unexpected positional arguments") - } - return FromKeywords(Default, kwargs), nil -} - -// FromKeywords returns a new struct instance whose fields are specified by the -// key/value pairs in kwargs. (Each kwargs[i][0] must be a starlark.String.) -func FromKeywords(constructor starlark.Value, kwargs []starlark.Tuple) *Struct { - if constructor == nil { - panic("nil constructor") - } - s := &Struct{ - constructor: constructor, - entries: make(entries, 0, len(kwargs)), - } - for _, kwarg := range kwargs { - k := string(kwarg[0].(starlark.String)) - v := kwarg[1] - s.entries = append(s.entries, entry{k, v}) - } - sort.Sort(s.entries) - return s -} - -// FromStringDict returns a new struct instance whose elements are those of d. -// The constructor parameter specifies the constructor; use Default for an ordinary struct. -func FromStringDict(constructor starlark.Value, d starlark.StringDict) *Struct { - if constructor == nil { - panic("nil constructor") - } - s := &Struct{ - constructor: constructor, - entries: make(entries, 0, len(d)), - } - for k, v := range d { - s.entries = append(s.entries, entry{k, v}) - } - sort.Sort(s.entries) - return s -} - -// Struct is an immutable Starlark type that maps field names to values. -// It is not iterable and does not support len. -// -// A struct has a constructor, a distinct value that identifies a class -// of structs, and which appears in the struct's string representation. -// -// Operations such as x+y fail if the constructors of the two operands -// are not equal. -// -// The default constructor, Default, is the string "struct", but -// clients may wish to 'brand' structs for their own purposes. -// The constructor value appears in the printed form of the value, -// and is accessible using the Constructor method. -// -// Use Attr to access its fields and AttrNames to enumerate them. -type Struct struct { - constructor starlark.Value - entries entries // sorted by name -} - -// Default is the default constructor for structs. -// It is merely the string "struct". -const Default = starlark.String("struct") - -type entries []entry - -func (a entries) Len() int { return len(a) } -func (a entries) Less(i, j int) bool { return a[i].name < a[j].name } -func (a entries) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -type entry struct { - name string - value starlark.Value -} - -var ( - _ starlark.HasAttrs = (*Struct)(nil) - _ starlark.HasBinary = (*Struct)(nil) -) - -// ToStringDict adds a name/value entry to d for each field of the struct. -func (s *Struct) ToStringDict(d starlark.StringDict) { - for _, e := range s.entries { - d[e.name] = e.value - } -} - -func (s *Struct) String() string { - buf := new(strings.Builder) - switch constructor := s.constructor.(type) { - case starlark.String: - // NB: The Java implementation always prints struct - // even for Bazel provider instances. - buf.WriteString(constructor.GoString()) // avoid String()'s quotation - default: - buf.WriteString(s.constructor.String()) - } - buf.WriteByte('(') - for i, e := range s.entries { - if i > 0 { - buf.WriteString(", ") - } - buf.WriteString(e.name) - buf.WriteString(" = ") - buf.WriteString(e.value.String()) - } - buf.WriteByte(')') - return buf.String() -} - -// Constructor returns the constructor used to create this struct. -func (s *Struct) Constructor() starlark.Value { return s.constructor } - -func (s *Struct) Type() string { return "struct" } -func (s *Struct) Truth() starlark.Bool { return true } // even when empty -func (s *Struct) Hash() (uint32, error) { - // Same algorithm as Tuple.hash, but with different primes. - var x, m uint32 = 8731, 9839 - for _, e := range s.entries { - namehash, _ := starlark.String(e.name).Hash() - x = x ^ 3*namehash - y, err := e.value.Hash() - if err != nil { - return 0, err - } - x = x ^ y*m - m += 7349 - } - return x, nil -} -func (s *Struct) Freeze() { - for _, e := range s.entries { - e.value.Freeze() - } -} - -func (x *Struct) Binary(op syntax.Token, y starlark.Value, side starlark.Side) (starlark.Value, error) { - if y, ok := y.(*Struct); ok && op == syntax.PLUS { - if side == starlark.Right { - x, y = y, x - } - - if eq, err := starlark.Equal(x.constructor, y.constructor); err != nil { - return nil, fmt.Errorf("in %s + %s: error comparing constructors: %v", - x.constructor, y.constructor, err) - } else if !eq { - return nil, fmt.Errorf("cannot add structs of different constructors: %s + %s", - x.constructor, y.constructor) - } - - z := make(starlark.StringDict, x.len()+y.len()) - for _, e := range x.entries { - z[e.name] = e.value - } - for _, e := range y.entries { - z[e.name] = e.value - } - - return FromStringDict(x.constructor, z), nil - } - return nil, nil // unhandled -} - -// Attr returns the value of the specified field. -func (s *Struct) Attr(name string) (starlark.Value, error) { - // Binary search the entries. - // This implementation is a specialization of - // sort.Search that avoids dynamic dispatch. - n := len(s.entries) - i, j := 0, n - for i < j { - h := int(uint(i+j) >> 1) - if s.entries[h].name < name { - i = h + 1 - } else { - j = h - } - } - if i < n && s.entries[i].name == name { - return s.entries[i].value, nil - } - - var ctor string - if s.constructor != Default { - ctor = s.constructor.String() + " " - } - return nil, starlark.NoSuchAttrError( - fmt.Sprintf("%sstruct has no .%s attribute", ctor, name)) -} - -func (s *Struct) len() int { return len(s.entries) } - -// AttrNames returns a new sorted list of the struct fields. -func (s *Struct) AttrNames() []string { - names := make([]string, len(s.entries)) - for i, e := range s.entries { - names[i] = e.name - } - return names -} - -func (x *Struct) CompareSameType(op syntax.Token, y_ starlark.Value, depth int) (bool, error) { - y := y_.(*Struct) - switch op { - case syntax.EQL: - return structsEqual(x, y, depth) - case syntax.NEQ: - eq, err := structsEqual(x, y, depth) - return !eq, err - default: - return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type()) - } -} - -func structsEqual(x, y *Struct, depth int) (bool, error) { - if x.len() != y.len() { - return false, nil - } - - if eq, err := starlark.Equal(x.constructor, y.constructor); err != nil { - return false, fmt.Errorf("error comparing struct constructors %v and %v: %v", - x.constructor, y.constructor, err) - } else if !eq { - return false, nil - } - - for i, n := 0, x.len(); i < n; i++ { - if x.entries[i].name != y.entries[i].name { - return false, nil - } else if eq, err := starlark.EqualDepth(x.entries[i].value, y.entries[i].value, depth-1); err != nil { - return false, err - } else if !eq { - return false, nil - } - } - return true, nil -} diff --git a/tests/vendor/go.starlark.net/syntax/grammar.txt b/tests/vendor/go.starlark.net/syntax/grammar.txt deleted file mode 100644 index 7f5dfc811..000000000 --- a/tests/vendor/go.starlark.net/syntax/grammar.txt +++ /dev/null @@ -1,129 +0,0 @@ - -Grammar of Starlark -================== - -File = {Statement | newline} eof . - -Statement = DefStmt | IfStmt | ForStmt | WhileStmt | SimpleStmt . - -DefStmt = 'def' identifier '(' [Parameters [',']] ')' ':' Suite . - -Parameters = Parameter {',' Parameter}. - -Parameter = identifier | identifier '=' Test | '*' | '*' identifier | '**' identifier . - -IfStmt = 'if' Test ':' Suite {'elif' Test ':' Suite} ['else' ':' Suite] . - -ForStmt = 'for' LoopVariables 'in' Expression ':' Suite . - -WhileStmt = 'while' Test ':' Suite . - -Suite = [newline indent {Statement} outdent] | SimpleStmt . - -SimpleStmt = SmallStmt {';' SmallStmt} [';'] '\n' . -# NOTE: '\n' optional at EOF - -SmallStmt = ReturnStmt - | BreakStmt | ContinueStmt | PassStmt - | AssignStmt - | ExprStmt - | LoadStmt - . - -ReturnStmt = 'return' [Expression] . -BreakStmt = 'break' . -ContinueStmt = 'continue' . -PassStmt = 'pass' . -AssignStmt = Expression ('=' | '+=' | '-=' | '*=' | '/=' | '//=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=') Expression . -ExprStmt = Expression . - -LoadStmt = 'load' '(' string {',' [identifier '='] string} [','] ')' . - -Test = LambdaExpr - | IfExpr - | PrimaryExpr - | UnaryExpr - | BinaryExpr - . - -LambdaExpr = 'lambda' [Parameters] ':' Test . - -IfExpr = Test 'if' Test 'else' Test . - -PrimaryExpr = Operand - | PrimaryExpr DotSuffix - | PrimaryExpr CallSuffix - | PrimaryExpr SliceSuffix - . - -Operand = identifier - | int | float | string - | ListExpr | ListComp - | DictExpr | DictComp - | '(' [Expression [',']] ')' - | ('-' | '+') PrimaryExpr - . - -DotSuffix = '.' identifier . -CallSuffix = '(' [Arguments [',']] ')' . -SliceSuffix = '[' [Expression] [':' Test [':' Test]] ']' . - -Arguments = Argument {',' Argument} . -Argument = Test | identifier '=' Test | '*' Test | '**' Test . - -ListExpr = '[' [Expression [',']] ']' . -ListComp = '[' Test {CompClause} ']'. - -DictExpr = '{' [Entries [',']] '}' . -DictComp = '{' Entry {CompClause} '}' . -Entries = Entry {',' Entry} . -Entry = Test ':' Test . - -CompClause = 'for' LoopVariables 'in' Test | 'if' Test . - -UnaryExpr = 'not' Test . - -BinaryExpr = Test {Binop Test} . - -Binop = 'or' - | 'and' - | '==' | '!=' | '<' | '>' | '<=' | '>=' | 'in' | 'not' 'in' - | '|' - | '^' - | '&' - | '-' | '+' - | '*' | '%' | '/' | '//' - . - -Expression = Test {',' Test} . -# NOTE: trailing comma permitted only when within [...] or (...). - -LoopVariables = PrimaryExpr {',' PrimaryExpr} . - - -# Notation (similar to Go spec): -- lowercase and 'quoted' items are lexical tokens. -- Capitalized names denote grammar productions. -- (...) implies grouping -- x | y means either x or y. -- [x] means x is optional -- {x} means x is repeated zero or more times -- The end of each declaration is marked with a period. - -# Tokens -- spaces: newline, eof, indent, outdent. -- identifier. -- literals: string, int, float. -- plus all quoted tokens such as '+=', 'return'. - -# Notes: -- Ambiguity is resolved using operator precedence. -- The grammar does not enforce the legal order of params and args, - nor that the first compclause must be a 'for'. - -TODO: -- explain how the lexer generates indent, outdent, and newline tokens. -- why is unary NOT separated from unary - and +? -- the grammar is (mostly) in LL(1) style so, for example, - dot expressions are formed suffixes, not complete expressions, - which makes the spec harder to read. Reorganize into non-LL(1) form? diff --git a/tests/vendor/go.starlark.net/syntax/options.go b/tests/vendor/go.starlark.net/syntax/options.go deleted file mode 100644 index 51b263823..000000000 --- a/tests/vendor/go.starlark.net/syntax/options.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2023 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syntax - -import _ "unsafe" // for linkname - -// FileOptions specifies various per-file options that affect static -// aspects of an individual file such as parsing, name resolution, and -// code generation. (Options that affect global dynamics are typically -// controlled through [starlark.Thread].) -// -// The zero value of FileOptions is the default behavior. -// -// Many functions in this package come in two versions: the legacy -// standalone function (such as [Parse]) uses [LegacyFileOptions], -// whereas the more recent method (such as [Options.Parse]) honors the -// provided options. The second form is preferred. In other packages, -// the modern version is a standalone function with a leading -// FileOptions parameter and the name suffix "Options", such as -// [starlark.ExecFileOptions]. -type FileOptions struct { - // resolver - Set bool // allow references to the 'set' built-in function - While bool // allow 'while' statements - TopLevelControl bool // allow if/for/while statements at top-level - GlobalReassign bool // allow reassignment to top-level names - LoadBindsGlobally bool // load creates global not file-local bindings (deprecated) - - // compiler - Recursion bool // disable recursion check for functions in this file -} - -// TODO(adonovan): provide a canonical flag parser for FileOptions. -// (And use it in the testdata "options:" strings.) - -// LegacyFileOptions returns a new FileOptions containing the current -// values of the resolver package's legacy global variables such as -// [resolve.AllowRecursion], etc. -// These variables may be associated with command-line flags. -func LegacyFileOptions() *FileOptions { - return &FileOptions{ - Set: resolverAllowSet, - While: resolverAllowGlobalReassign, - TopLevelControl: resolverAllowGlobalReassign, - GlobalReassign: resolverAllowGlobalReassign, - Recursion: resolverAllowRecursion, - LoadBindsGlobally: resolverLoadBindsGlobally, - } -} - -// Access resolver (legacy) flags, if they are linked in; false otherwise. -var ( - //go:linkname resolverAllowSet go.starlark.net/resolve.AllowSet - resolverAllowSet bool - //go:linkname resolverAllowGlobalReassign go.starlark.net/resolve.AllowGlobalReassign - resolverAllowGlobalReassign bool - //go:linkname resolverAllowRecursion go.starlark.net/resolve.AllowRecursion - resolverAllowRecursion bool - //go:linkname resolverLoadBindsGlobally go.starlark.net/resolve.LoadBindsGlobally - resolverLoadBindsGlobally bool -) diff --git a/tests/vendor/go.starlark.net/syntax/parse.go b/tests/vendor/go.starlark.net/syntax/parse.go deleted file mode 100644 index 1183a03bf..000000000 --- a/tests/vendor/go.starlark.net/syntax/parse.go +++ /dev/null @@ -1,1057 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syntax - -// This file defines a recursive-descent parser for Starlark. -// The LL(1) grammar of Starlark and the names of many productions follow Python 2.7. -// -// TODO(adonovan): use syntax.Error more systematically throughout the -// package. Verify that error positions are correct using the -// chunkedfile mechanism. - -import "log" - -// Enable this flag to print the token stream and log.Fatal on the first error. -const debug = false - -// A Mode value is a set of flags (or 0) that controls optional parser functionality. -type Mode uint - -const ( - RetainComments Mode = 1 << iota // retain comments in AST; see Node.Comments -) - -// Parse calls the Parse method of LegacyFileOptions(). -// Deprecated: relies on legacy global variables. -func Parse(filename string, src interface{}, mode Mode) (f *File, err error) { - return LegacyFileOptions().Parse(filename, src, mode) -} - -// Parse parses the input data and returns the corresponding parse tree. -// -// If src != nil, Parse parses the source from src and the filename -// is only used when recording position information. -// The type of the argument for the src parameter must be string, -// []byte, io.Reader, or FilePortion. -// If src == nil, Parse parses the file specified by filename. -func (opts *FileOptions) Parse(filename string, src interface{}, mode Mode) (f *File, err error) { - in, err := newScanner(filename, src, mode&RetainComments != 0) - if err != nil { - return nil, err - } - p := parser{options: opts, in: in} - defer p.in.recover(&err) - - p.nextToken() // read first lookahead token - f = p.parseFile() - if f != nil { - f.Path = filename - } - p.assignComments(f) - return f, nil -} - -// ParseCompoundStmt calls the ParseCompoundStmt method of LegacyFileOptions(). -// Deprecated: relies on legacy global variables. -func ParseCompoundStmt(filename string, readline func() ([]byte, error)) (f *File, err error) { - return LegacyFileOptions().ParseCompoundStmt(filename, readline) -} - -// ParseCompoundStmt parses a single compound statement: -// a blank line, a def, for, while, or if statement, or a -// semicolon-separated list of simple statements followed -// by a newline. These are the units on which the REPL operates. -// ParseCompoundStmt does not consume any following input. -// The parser calls the readline function each -// time it needs a new line of input. -func (opts *FileOptions) ParseCompoundStmt(filename string, readline func() ([]byte, error)) (f *File, err error) { - in, err := newScanner(filename, readline, false) - if err != nil { - return nil, err - } - - p := parser{options: opts, in: in} - defer p.in.recover(&err) - - p.nextToken() // read first lookahead token - - var stmts []Stmt - switch p.tok { - case DEF, IF, FOR, WHILE: - stmts = p.parseStmt(stmts) - case NEWLINE: - // blank line - default: - stmts = p.parseSimpleStmt(stmts, false) - // Require but don't consume newline, to avoid blocking again. - if p.tok != NEWLINE { - p.in.errorf(p.in.pos, "invalid syntax") - } - } - - return &File{Options: opts, Path: filename, Stmts: stmts}, nil -} - -// ParseExpr calls the ParseExpr method of LegacyFileOptions(). -// Deprecated: relies on legacy global variables. -func ParseExpr(filename string, src interface{}, mode Mode) (expr Expr, err error) { - return LegacyFileOptions().ParseExpr(filename, src, mode) -} - -// ParseExpr parses a Starlark expression. -// A comma-separated list of expressions is parsed as a tuple. -// See Parse for explanation of parameters. -func (opts *FileOptions) ParseExpr(filename string, src interface{}, mode Mode) (expr Expr, err error) { - in, err := newScanner(filename, src, mode&RetainComments != 0) - if err != nil { - return nil, err - } - p := parser{options: opts, in: in} - defer p.in.recover(&err) - - p.nextToken() // read first lookahead token - - // Use parseExpr, not parseTest, to permit an unparenthesized tuple. - expr = p.parseExpr(false) - - // A following newline (e.g. "f()\n") appears outside any brackets, - // on a non-blank line, and thus results in a NEWLINE token. - if p.tok == NEWLINE { - p.nextToken() - } - - if p.tok != EOF { - p.in.errorf(p.in.pos, "got %#v after expression, want EOF", p.tok) - } - p.assignComments(expr) - return expr, nil -} - -type parser struct { - options *FileOptions - in *scanner - tok Token - tokval tokenValue -} - -// nextToken advances the scanner and returns the position of the -// previous token. -func (p *parser) nextToken() Position { - oldpos := p.tokval.pos - p.tok = p.in.nextToken(&p.tokval) - // enable to see the token stream - if debug { - log.Printf("nextToken: %-20s%+v\n", p.tok, p.tokval.pos) - } - return oldpos -} - -// file_input = (NEWLINE | stmt)* EOF -func (p *parser) parseFile() *File { - var stmts []Stmt - for p.tok != EOF { - if p.tok == NEWLINE { - p.nextToken() - continue - } - stmts = p.parseStmt(stmts) - } - return &File{Options: p.options, Stmts: stmts} -} - -func (p *parser) parseStmt(stmts []Stmt) []Stmt { - if p.tok == DEF { - return append(stmts, p.parseDefStmt()) - } else if p.tok == IF { - return append(stmts, p.parseIfStmt()) - } else if p.tok == FOR { - return append(stmts, p.parseForStmt()) - } else if p.tok == WHILE { - return append(stmts, p.parseWhileStmt()) - } - return p.parseSimpleStmt(stmts, true) -} - -func (p *parser) parseDefStmt() Stmt { - defpos := p.nextToken() // consume DEF - id := p.parseIdent() - lparen := p.consume(LPAREN) - params := p.parseParams() - rparen := p.consume(RPAREN) - p.consume(COLON) - body := p.parseSuite() - return &DefStmt{ - Def: defpos, - Name: id, - Lparen: lparen, - Params: params, - Rparen: rparen, - Body: body, - } -} - -func (p *parser) parseIfStmt() Stmt { - ifpos := p.nextToken() // consume IF - cond := p.parseTest() - p.consume(COLON) - body := p.parseSuite() - ifStmt := &IfStmt{ - If: ifpos, - Cond: cond, - True: body, - } - tail := ifStmt - for p.tok == ELIF { - elifpos := p.nextToken() // consume ELIF - cond := p.parseTest() - p.consume(COLON) - body := p.parseSuite() - elif := &IfStmt{ - If: elifpos, - Cond: cond, - True: body, - } - tail.ElsePos = elifpos - tail.False = []Stmt{elif} - tail = elif - } - if p.tok == ELSE { - tail.ElsePos = p.nextToken() // consume ELSE - p.consume(COLON) - tail.False = p.parseSuite() - } - return ifStmt -} - -func (p *parser) parseForStmt() Stmt { - forpos := p.nextToken() // consume FOR - vars := p.parseForLoopVariables() - p.consume(IN) - x := p.parseExpr(false) - p.consume(COLON) - body := p.parseSuite() - return &ForStmt{ - For: forpos, - Vars: vars, - X: x, - Body: body, - } -} - -func (p *parser) parseWhileStmt() Stmt { - whilepos := p.nextToken() // consume WHILE - cond := p.parseTest() - p.consume(COLON) - body := p.parseSuite() - return &WhileStmt{ - While: whilepos, - Cond: cond, - Body: body, - } -} - -// Equivalent to 'exprlist' production in Python grammar. -// -// loop_variables = primary_with_suffix (COMMA primary_with_suffix)* COMMA? -func (p *parser) parseForLoopVariables() Expr { - // Avoid parseExpr because it would consume the IN token - // following x in "for x in y: ...". - v := p.parsePrimaryWithSuffix() - if p.tok != COMMA { - return v - } - - list := []Expr{v} - for p.tok == COMMA { - p.nextToken() - if terminatesExprList(p.tok) { - break - } - list = append(list, p.parsePrimaryWithSuffix()) - } - return &TupleExpr{List: list} -} - -// simple_stmt = small_stmt (SEMI small_stmt)* SEMI? NEWLINE -// In REPL mode, it does not consume the NEWLINE. -func (p *parser) parseSimpleStmt(stmts []Stmt, consumeNL bool) []Stmt { - for { - stmts = append(stmts, p.parseSmallStmt()) - if p.tok != SEMI { - break - } - p.nextToken() // consume SEMI - if p.tok == NEWLINE || p.tok == EOF { - break - } - } - // EOF without NEWLINE occurs in `if x: pass`, for example. - if p.tok != EOF && consumeNL { - p.consume(NEWLINE) - } - - return stmts -} - -// small_stmt = RETURN expr? -// -// | PASS | BREAK | CONTINUE -// | LOAD ... -// | expr ('=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=') expr // assign -// | expr -func (p *parser) parseSmallStmt() Stmt { - switch p.tok { - case RETURN: - pos := p.nextToken() // consume RETURN - var result Expr - if p.tok != EOF && p.tok != NEWLINE && p.tok != SEMI { - result = p.parseExpr(false) - } - return &ReturnStmt{Return: pos, Result: result} - - case BREAK, CONTINUE, PASS: - tok := p.tok - pos := p.nextToken() // consume it - return &BranchStmt{Token: tok, TokenPos: pos} - - case LOAD: - return p.parseLoadStmt() - } - - // Assignment - x := p.parseExpr(false) - switch p.tok { - case EQ, PLUS_EQ, MINUS_EQ, STAR_EQ, SLASH_EQ, SLASHSLASH_EQ, PERCENT_EQ, AMP_EQ, PIPE_EQ, CIRCUMFLEX_EQ, LTLT_EQ, GTGT_EQ: - op := p.tok - pos := p.nextToken() // consume op - rhs := p.parseExpr(false) - return &AssignStmt{OpPos: pos, Op: op, LHS: x, RHS: rhs} - } - - // Expression statement (e.g. function call, doc string). - return &ExprStmt{X: x} -} - -// stmt = LOAD '(' STRING {',' (IDENT '=')? STRING} [','] ')' -func (p *parser) parseLoadStmt() *LoadStmt { - loadPos := p.nextToken() // consume LOAD - lparen := p.consume(LPAREN) - - if p.tok != STRING { - p.in.errorf(p.in.pos, "first operand of load statement must be a string literal") - } - module := p.parsePrimary().(*Literal) - - var from, to []*Ident - for p.tok != RPAREN && p.tok != EOF { - p.consume(COMMA) - if p.tok == RPAREN { - break // allow trailing comma - } - switch p.tok { - case STRING: - // load("module", "id") - // To name is same as original. - lit := p.parsePrimary().(*Literal) - id := &Ident{ - NamePos: lit.TokenPos.add(`"`), - Name: lit.Value.(string), - } - to = append(to, id) - from = append(from, id) - - case IDENT: - // load("module", to="from") - id := p.parseIdent() - to = append(to, id) - if p.tok != EQ { - p.in.errorf(p.in.pos, `load operand must be "%[1]s" or %[1]s="originalname" (want '=' after %[1]s)`, id.Name) - } - p.consume(EQ) - if p.tok != STRING { - p.in.errorf(p.in.pos, `original name of loaded symbol must be quoted: %s="originalname"`, id.Name) - } - lit := p.parsePrimary().(*Literal) - from = append(from, &Ident{ - NamePos: lit.TokenPos.add(`"`), - Name: lit.Value.(string), - }) - - case RPAREN: - p.in.errorf(p.in.pos, "trailing comma in load statement") - - default: - p.in.errorf(p.in.pos, `load operand must be "name" or localname="name" (got %#v)`, p.tok) - } - } - rparen := p.consume(RPAREN) - - if len(to) == 0 { - p.in.errorf(lparen, "load statement must import at least 1 symbol") - } - return &LoadStmt{ - Load: loadPos, - Module: module, - To: to, - From: from, - Rparen: rparen, - } -} - -// suite is typically what follows a COLON (e.g. after DEF or FOR). -// suite = simple_stmt | NEWLINE INDENT stmt+ OUTDENT -func (p *parser) parseSuite() []Stmt { - if p.tok == NEWLINE { - p.nextToken() // consume NEWLINE - p.consume(INDENT) - var stmts []Stmt - for p.tok != OUTDENT && p.tok != EOF { - stmts = p.parseStmt(stmts) - } - p.consume(OUTDENT) - return stmts - } - - return p.parseSimpleStmt(nil, true) -} - -func (p *parser) parseIdent() *Ident { - if p.tok != IDENT { - p.in.error(p.in.pos, "not an identifier") - } - id := &Ident{ - NamePos: p.tokval.pos, - Name: p.tokval.raw, - } - p.nextToken() - return id -} - -func (p *parser) consume(t Token) Position { - if p.tok != t { - p.in.errorf(p.in.pos, "got %#v, want %#v", p.tok, t) - } - return p.nextToken() -} - -// params = (param COMMA)* param COMMA? -// -// | -// -// param = IDENT -// -// | IDENT EQ test -// | STAR -// | STAR IDENT -// | STARSTAR IDENT -// -// parseParams parses a parameter list. The resulting expressions are of the form: -// -// *Ident x -// *Binary{Op: EQ, X: *Ident, Y: Expr} x=y -// *Unary{Op: STAR} * -// *Unary{Op: STAR, X: *Ident} *args -// *Unary{Op: STARSTAR, X: *Ident} **kwargs -func (p *parser) parseParams() []Expr { - var params []Expr - for p.tok != RPAREN && p.tok != COLON && p.tok != EOF { - if len(params) > 0 { - p.consume(COMMA) - } - if p.tok == RPAREN { - break - } - - // * or *args or **kwargs - if p.tok == STAR || p.tok == STARSTAR { - op := p.tok - pos := p.nextToken() - var x Expr - if op == STARSTAR || p.tok == IDENT { - x = p.parseIdent() - } - params = append(params, &UnaryExpr{ - OpPos: pos, - Op: op, - X: x, - }) - continue - } - - // IDENT - // IDENT = test - id := p.parseIdent() - if p.tok == EQ { // default value - eq := p.nextToken() - dflt := p.parseTest() - params = append(params, &BinaryExpr{ - X: id, - OpPos: eq, - Op: EQ, - Y: dflt, - }) - continue - } - - params = append(params, id) - } - return params -} - -// parseExpr parses an expression, possible consisting of a -// comma-separated list of 'test' expressions. -// -// In many cases we must use parseTest to avoid ambiguity such as -// f(x, y) vs. f((x, y)). -func (p *parser) parseExpr(inParens bool) Expr { - x := p.parseTest() - if p.tok != COMMA { - return x - } - - // tuple - exprs := p.parseExprs([]Expr{x}, inParens) - return &TupleExpr{List: exprs} -} - -// parseExprs parses a comma-separated list of expressions, starting with the comma. -// It is used to parse tuples and list elements. -// expr_list = (',' expr)* ','? -func (p *parser) parseExprs(exprs []Expr, allowTrailingComma bool) []Expr { - for p.tok == COMMA { - pos := p.nextToken() - if terminatesExprList(p.tok) { - if !allowTrailingComma { - p.in.error(pos, "unparenthesized tuple with trailing comma") - } - break - } - exprs = append(exprs, p.parseTest()) - } - return exprs -} - -// parseTest parses a 'test', a single-component expression. -func (p *parser) parseTest() Expr { - if p.tok == LAMBDA { - return p.parseLambda(true) - } - - x := p.parseTestPrec(0) - - // conditional expression (t IF cond ELSE f) - if p.tok == IF { - ifpos := p.nextToken() - cond := p.parseTestPrec(0) - if p.tok != ELSE { - p.in.error(ifpos, "conditional expression without else clause") - } - elsepos := p.nextToken() - else_ := p.parseTest() - return &CondExpr{If: ifpos, Cond: cond, True: x, ElsePos: elsepos, False: else_} - } - - return x -} - -// parseTestNoCond parses a a single-component expression without -// consuming a trailing 'if expr else expr'. -func (p *parser) parseTestNoCond() Expr { - if p.tok == LAMBDA { - return p.parseLambda(false) - } - return p.parseTestPrec(0) -} - -// parseLambda parses a lambda expression. -// The allowCond flag allows the body to be an 'a if b else c' conditional. -func (p *parser) parseLambda(allowCond bool) Expr { - lambda := p.nextToken() - var params []Expr - if p.tok != COLON { - params = p.parseParams() - } - p.consume(COLON) - - var body Expr - if allowCond { - body = p.parseTest() - } else { - body = p.parseTestNoCond() - } - - return &LambdaExpr{ - Lambda: lambda, - Params: params, - Body: body, - } -} - -func (p *parser) parseTestPrec(prec int) Expr { - if prec >= len(preclevels) { - return p.parsePrimaryWithSuffix() - } - - // expr = NOT expr - if p.tok == NOT && prec == int(precedence[NOT]) { - pos := p.nextToken() - x := p.parseTestPrec(prec) - return &UnaryExpr{ - OpPos: pos, - Op: NOT, - X: x, - } - } - - return p.parseBinopExpr(prec) -} - -// expr = test (OP test)* -// Uses precedence climbing; see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm#climbing. -func (p *parser) parseBinopExpr(prec int) Expr { - x := p.parseTestPrec(prec + 1) - for first := true; ; first = false { - if p.tok == NOT { - p.nextToken() // consume NOT - // In this context, NOT must be followed by IN. - // Replace NOT IN by a single NOT_IN token. - if p.tok != IN { - p.in.errorf(p.in.pos, "got %#v, want in", p.tok) - } - p.tok = NOT_IN - } - - // Binary operator of specified precedence? - opprec := int(precedence[p.tok]) - if opprec < prec { - return x - } - - // Comparisons are non-associative. - if !first && opprec == int(precedence[EQL]) { - p.in.errorf(p.in.pos, "%s does not associate with %s (use parens)", - x.(*BinaryExpr).Op, p.tok) - } - - op := p.tok - pos := p.nextToken() - y := p.parseTestPrec(opprec + 1) - x = &BinaryExpr{OpPos: pos, Op: op, X: x, Y: y} - } -} - -// precedence maps each operator to its precedence (0-7), or -1 for other tokens. -var precedence [maxToken]int8 - -// preclevels groups operators of equal precedence. -// Comparisons are nonassociative; other binary operators associate to the left. -// Unary MINUS, unary PLUS, and TILDE have higher precedence so are handled in parsePrimary. -// See https://github.com/google/starlark-go/blob/master/doc/spec.md#binary-operators -var preclevels = [...][]Token{ - {OR}, // or - {AND}, // and - {NOT}, // not (unary) - {EQL, NEQ, LT, GT, LE, GE, IN, NOT_IN}, // == != < > <= >= in not in - {PIPE}, // | - {CIRCUMFLEX}, // ^ - {AMP}, // & - {LTLT, GTGT}, // << >> - {MINUS, PLUS}, // - - {STAR, PERCENT, SLASH, SLASHSLASH}, // * % / // -} - -func init() { - // populate precedence table - for i := range precedence { - precedence[i] = -1 - } - for level, tokens := range preclevels { - for _, tok := range tokens { - precedence[tok] = int8(level) - } - } -} - -// primary_with_suffix = primary -// -// | primary '.' IDENT -// | primary slice_suffix -// | primary call_suffix -func (p *parser) parsePrimaryWithSuffix() Expr { - x := p.parsePrimary() - for { - switch p.tok { - case DOT: - dot := p.nextToken() - id := p.parseIdent() - x = &DotExpr{Dot: dot, X: x, Name: id} - case LBRACK: - x = p.parseSliceSuffix(x) - case LPAREN: - x = p.parseCallSuffix(x) - default: - return x - } - } -} - -// slice_suffix = '[' expr? ':' expr? ':' expr? ']' -func (p *parser) parseSliceSuffix(x Expr) Expr { - lbrack := p.nextToken() - var lo, hi, step Expr - if p.tok != COLON { - y := p.parseExpr(false) - - // index x[y] - if p.tok == RBRACK { - rbrack := p.nextToken() - return &IndexExpr{X: x, Lbrack: lbrack, Y: y, Rbrack: rbrack} - } - - lo = y - } - - // slice or substring x[lo:hi:step] - if p.tok == COLON { - p.nextToken() - if p.tok != COLON && p.tok != RBRACK { - hi = p.parseTest() - } - } - if p.tok == COLON { - p.nextToken() - if p.tok != RBRACK { - step = p.parseTest() - } - } - rbrack := p.consume(RBRACK) - return &SliceExpr{X: x, Lbrack: lbrack, Lo: lo, Hi: hi, Step: step, Rbrack: rbrack} -} - -// call_suffix = '(' arg_list? ')' -func (p *parser) parseCallSuffix(fn Expr) Expr { - lparen := p.consume(LPAREN) - var rparen Position - var args []Expr - if p.tok == RPAREN { - rparen = p.nextToken() - } else { - args = p.parseArgs() - rparen = p.consume(RPAREN) - } - return &CallExpr{Fn: fn, Lparen: lparen, Args: args, Rparen: rparen} -} - -// parseArgs parses a list of actual parameter values (arguments). -// It mirrors the structure of parseParams. -// arg_list = ((arg COMMA)* arg COMMA?)? -func (p *parser) parseArgs() []Expr { - var args []Expr - for p.tok != RPAREN && p.tok != EOF { - if len(args) > 0 { - p.consume(COMMA) - } - if p.tok == RPAREN { - break - } - - // *args or **kwargs - if p.tok == STAR || p.tok == STARSTAR { - op := p.tok - pos := p.nextToken() - x := p.parseTest() - args = append(args, &UnaryExpr{ - OpPos: pos, - Op: op, - X: x, - }) - continue - } - - // We use a different strategy from Bazel here to stay within LL(1). - // Instead of looking ahead two tokens (IDENT, EQ) we parse - // 'test = test' then check that the first was an IDENT. - x := p.parseTest() - - if p.tok == EQ { - // name = value - if _, ok := x.(*Ident); !ok { - p.in.errorf(p.in.pos, "keyword argument must have form name=expr") - } - eq := p.nextToken() - y := p.parseTest() - x = &BinaryExpr{ - X: x, - OpPos: eq, - Op: EQ, - Y: y, - } - } - - args = append(args, x) - } - return args -} - -// primary = IDENT -// -// | INT | FLOAT | STRING | BYTES -// | '[' ... // list literal or comprehension -// | '{' ... // dict literal or comprehension -// | '(' ... // tuple or parenthesized expression -// | ('-'|'+'|'~') primary_with_suffix -func (p *parser) parsePrimary() Expr { - switch p.tok { - case IDENT: - return p.parseIdent() - - case INT, FLOAT, STRING, BYTES: - var val interface{} - tok := p.tok - switch tok { - case INT: - if p.tokval.bigInt != nil { - val = p.tokval.bigInt - } else { - val = p.tokval.int - } - case FLOAT: - val = p.tokval.float - case STRING, BYTES: - val = p.tokval.string - } - raw := p.tokval.raw - pos := p.nextToken() - return &Literal{Token: tok, TokenPos: pos, Raw: raw, Value: val} - - case LBRACK: - return p.parseList() - - case LBRACE: - return p.parseDict() - - case LPAREN: - lparen := p.nextToken() - if p.tok == RPAREN { - // empty tuple - rparen := p.nextToken() - return &TupleExpr{Lparen: lparen, Rparen: rparen} - } - e := p.parseExpr(true) // allow trailing comma - rparen := p.consume(RPAREN) - return &ParenExpr{ - Lparen: lparen, - X: e, - Rparen: rparen, - } - - case MINUS, PLUS, TILDE: // unary - tok := p.tok - pos := p.nextToken() - x := p.parsePrimaryWithSuffix() - return &UnaryExpr{ - OpPos: pos, - Op: tok, - X: x, - } - } - p.in.errorf(p.in.pos, "got %#v, want primary expression", p.tok) - panic("unreachable") -} - -// list = '[' ']' -// -// | '[' expr ']' -// | '[' expr expr_list ']' -// | '[' expr (FOR loop_variables IN expr)+ ']' -func (p *parser) parseList() Expr { - lbrack := p.nextToken() - if p.tok == RBRACK { - // empty List - rbrack := p.nextToken() - return &ListExpr{Lbrack: lbrack, Rbrack: rbrack} - } - - x := p.parseTest() - - if p.tok == FOR { - // list comprehension - return p.parseComprehensionSuffix(lbrack, x, RBRACK) - } - - exprs := []Expr{x} - if p.tok == COMMA { - // multi-item list literal - exprs = p.parseExprs(exprs, true) // allow trailing comma - } - - rbrack := p.consume(RBRACK) - return &ListExpr{Lbrack: lbrack, List: exprs, Rbrack: rbrack} -} - -// dict = '{' '}' -// -// | '{' dict_entry_list '}' -// | '{' dict_entry FOR loop_variables IN expr '}' -func (p *parser) parseDict() Expr { - lbrace := p.nextToken() - if p.tok == RBRACE { - // empty dict - rbrace := p.nextToken() - return &DictExpr{Lbrace: lbrace, Rbrace: rbrace} - } - - x := p.parseDictEntry() - - if p.tok == FOR { - // dict comprehension - return p.parseComprehensionSuffix(lbrace, x, RBRACE) - } - - entries := []Expr{x} - for p.tok == COMMA { - p.nextToken() - if p.tok == RBRACE { - break - } - entries = append(entries, p.parseDictEntry()) - } - - rbrace := p.consume(RBRACE) - return &DictExpr{Lbrace: lbrace, List: entries, Rbrace: rbrace} -} - -// dict_entry = test ':' test -func (p *parser) parseDictEntry() *DictEntry { - k := p.parseTest() - colon := p.consume(COLON) - v := p.parseTest() - return &DictEntry{Key: k, Colon: colon, Value: v} -} - -// comp_suffix = FOR loopvars IN expr comp_suffix -// -// | IF expr comp_suffix -// | ']' or ')' (end) -// -// There can be multiple FOR/IF clauses; the first is always a FOR. -func (p *parser) parseComprehensionSuffix(lbrace Position, body Expr, endBrace Token) Expr { - var clauses []Node - for p.tok != endBrace { - if p.tok == FOR { - pos := p.nextToken() - vars := p.parseForLoopVariables() - in := p.consume(IN) - // Following Python 3, the operand of IN cannot be: - // - a conditional expression ('x if y else z'), - // due to conflicts in Python grammar - // ('if' is used by the comprehension); - // - a lambda expression - // - an unparenthesized tuple. - x := p.parseTestPrec(0) - clauses = append(clauses, &ForClause{For: pos, Vars: vars, In: in, X: x}) - } else if p.tok == IF { - pos := p.nextToken() - cond := p.parseTestNoCond() - clauses = append(clauses, &IfClause{If: pos, Cond: cond}) - } else { - p.in.errorf(p.in.pos, "got %#v, want '%s', for, or if", p.tok, endBrace) - } - } - rbrace := p.nextToken() - - return &Comprehension{ - Curly: endBrace == RBRACE, - Lbrack: lbrace, - Body: body, - Clauses: clauses, - Rbrack: rbrace, - } -} - -func terminatesExprList(tok Token) bool { - switch tok { - case EOF, NEWLINE, EQ, RBRACE, RBRACK, RPAREN, SEMI: - return true - } - return false -} - -// Comment assignment. -// We build two lists of all subnodes, preorder and postorder. -// The preorder list is ordered by start location, with outer nodes first. -// The postorder list is ordered by end location, with outer nodes last. -// We use the preorder list to assign each whole-line comment to the syntax -// immediately following it, and we use the postorder list to assign each -// end-of-line comment to the syntax immediately preceding it. - -// flattenAST returns the list of AST nodes, both in prefix order and in postfix -// order. -func flattenAST(root Node) (pre, post []Node) { - stack := []Node{} - Walk(root, func(n Node) bool { - if n != nil { - pre = append(pre, n) - stack = append(stack, n) - } else { - post = append(post, stack[len(stack)-1]) - stack = stack[:len(stack)-1] - } - return true - }) - return pre, post -} - -// assignComments attaches comments to nearby syntax. -func (p *parser) assignComments(n Node) { - // Leave early if there are no comments - if len(p.in.lineComments)+len(p.in.suffixComments) == 0 { - return - } - - pre, post := flattenAST(n) - - // Assign line comments to syntax immediately following. - line := p.in.lineComments - for _, x := range pre { - start, _ := x.Span() - - switch x.(type) { - case *File: - continue - } - - for len(line) > 0 && !start.isBefore(line[0].Start) { - x.AllocComments() - x.Comments().Before = append(x.Comments().Before, line[0]) - line = line[1:] - } - } - - // Remaining line comments go at end of file. - if len(line) > 0 { - n.AllocComments() - n.Comments().After = append(n.Comments().After, line...) - } - - // Assign suffix comments to syntax immediately before. - suffix := p.in.suffixComments - for i := len(post) - 1; i >= 0; i-- { - x := post[i] - - // Do not assign suffix comments to file - switch x.(type) { - case *File: - continue - } - - _, end := x.Span() - if len(suffix) > 0 && end.isBefore(suffix[len(suffix)-1].Start) { - x.AllocComments() - x.Comments().Suffix = append(x.Comments().Suffix, suffix[len(suffix)-1]) - suffix = suffix[:len(suffix)-1] - } - } -} diff --git a/tests/vendor/go.starlark.net/syntax/quote.go b/tests/vendor/go.starlark.net/syntax/quote.go deleted file mode 100644 index 741e106ad..000000000 --- a/tests/vendor/go.starlark.net/syntax/quote.go +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syntax - -// Starlark quoted string utilities. - -import ( - "fmt" - "strconv" - "strings" - "unicode" - "unicode/utf8" -) - -// unesc maps single-letter chars following \ to their actual values. -var unesc = [256]byte{ - 'a': '\a', - 'b': '\b', - 'f': '\f', - 'n': '\n', - 'r': '\r', - 't': '\t', - 'v': '\v', - '\\': '\\', - '\'': '\'', - '"': '"', -} - -// esc maps escape-worthy bytes to the char that should follow \. -var esc = [256]byte{ - '\a': 'a', - '\b': 'b', - '\f': 'f', - '\n': 'n', - '\r': 'r', - '\t': 't', - '\v': 'v', - '\\': '\\', - '\'': '\'', - '"': '"', -} - -// unquote unquotes the quoted string, returning the actual -// string value, whether the original was triple-quoted, -// whether it was a byte string, and an error describing invalid input. -func unquote(quoted string) (s string, triple, isByte bool, err error) { - // Check for raw prefix: means don't interpret the inner \. - raw := false - if strings.HasPrefix(quoted, "r") { - raw = true - quoted = quoted[1:] - } - // Check for bytes prefix. - if strings.HasPrefix(quoted, "b") { - isByte = true - quoted = quoted[1:] - } - - if len(quoted) < 2 { - err = fmt.Errorf("string literal too short") - return - } - - if quoted[0] != '"' && quoted[0] != '\'' || quoted[0] != quoted[len(quoted)-1] { - err = fmt.Errorf("string literal has invalid quotes") - return - } - - // Check for triple quoted string. - quote := quoted[0] - if len(quoted) >= 6 && quoted[1] == quote && quoted[2] == quote && quoted[:3] == quoted[len(quoted)-3:] { - triple = true - quoted = quoted[3 : len(quoted)-3] - } else { - quoted = quoted[1 : len(quoted)-1] - } - - // Now quoted is the quoted data, but no quotes. - // If we're in raw mode or there are no escapes or - // carriage returns, we're done. - var unquoteChars string - if raw { - unquoteChars = "\r" - } else { - unquoteChars = "\\\r" - } - if !strings.ContainsAny(quoted, unquoteChars) { - s = quoted - return - } - - // Otherwise process quoted string. - // Each iteration processes one escape sequence along with the - // plain text leading up to it. - buf := new(strings.Builder) - for { - // Remove prefix before escape sequence. - i := strings.IndexAny(quoted, unquoteChars) - if i < 0 { - i = len(quoted) - } - buf.WriteString(quoted[:i]) - quoted = quoted[i:] - - if len(quoted) == 0 { - break - } - - // Process carriage return. - if quoted[0] == '\r' { - buf.WriteByte('\n') - if len(quoted) > 1 && quoted[1] == '\n' { - quoted = quoted[2:] - } else { - quoted = quoted[1:] - } - continue - } - - // Process escape sequence. - if len(quoted) == 1 { - err = fmt.Errorf(`truncated escape sequence \`) - return - } - - switch quoted[1] { - default: - // In Starlark, like Go, a backslash must escape something. - // (Python still treats unnecessary backslashes literally, - // but since 3.6 has emitted a deprecation warning.) - err = fmt.Errorf("invalid escape sequence \\%c", quoted[1]) - return - - case '\n': - // Ignore the escape and the line break. - quoted = quoted[2:] - - case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"': - // One-char escape. - // Escapes are allowed for both kinds of quotation - // mark, not just the kind in use. - buf.WriteByte(unesc[quoted[1]]) - quoted = quoted[2:] - - case '0', '1', '2', '3', '4', '5', '6', '7': - // Octal escape, up to 3 digits, \OOO. - n := int(quoted[1] - '0') - quoted = quoted[2:] - for i := 1; i < 3; i++ { - if len(quoted) == 0 || quoted[0] < '0' || '7' < quoted[0] { - break - } - n = n*8 + int(quoted[0]-'0') - quoted = quoted[1:] - } - if !isByte && n > 127 { - err = fmt.Errorf(`non-ASCII octal escape \%o (use \u%04X for the UTF-8 encoding of U+%04X)`, n, n, n) - return - } - if n >= 256 { - // NOTE: Python silently discards the high bit, - // so that '\541' == '\141' == 'a'. - // Let's see if we can avoid doing that in BUILD files. - err = fmt.Errorf(`invalid escape sequence \%03o`, n) - return - } - buf.WriteByte(byte(n)) - - case 'x': - // Hexadecimal escape, exactly 2 digits, \xXX. [0-127] - if len(quoted) < 4 { - err = fmt.Errorf(`truncated escape sequence %s`, quoted) - return - } - n, err1 := strconv.ParseUint(quoted[2:4], 16, 0) - if err1 != nil { - err = fmt.Errorf(`invalid escape sequence %s`, quoted[:4]) - return - } - if !isByte && n > 127 { - err = fmt.Errorf(`non-ASCII hex escape %s (use \u%04X for the UTF-8 encoding of U+%04X)`, - quoted[:4], n, n) - return - } - buf.WriteByte(byte(n)) - quoted = quoted[4:] - - case 'u', 'U': - // Unicode code point, 4 (\uXXXX) or 8 (\UXXXXXXXX) hex digits. - sz := 6 - if quoted[1] == 'U' { - sz = 10 - } - if len(quoted) < sz { - err = fmt.Errorf(`truncated escape sequence %s`, quoted) - return - } - n, err1 := strconv.ParseUint(quoted[2:sz], 16, 0) - if err1 != nil { - err = fmt.Errorf(`invalid escape sequence %s`, quoted[:sz]) - return - } - if n > unicode.MaxRune { - err = fmt.Errorf(`code point out of range: %s (max \U%08x)`, - quoted[:sz], n) - return - } - // As in Go, surrogates are disallowed. - if 0xD800 <= n && n < 0xE000 { - err = fmt.Errorf(`invalid Unicode code point U+%04X`, n) - return - } - buf.WriteRune(rune(n)) - quoted = quoted[sz:] - } - } - - s = buf.String() - return -} - -// indexByte returns the index of the first instance of b in s, or else -1. -func indexByte(s string, b byte) int { - for i := 0; i < len(s); i++ { - if s[i] == b { - return i - } - } - return -1 -} - -// Quote returns a Starlark literal that denotes s. -// If b, it returns a bytes literal. -func Quote(s string, b bool) string { - const hex = "0123456789abcdef" - var runeTmp [utf8.UTFMax]byte - - buf := make([]byte, 0, 3*len(s)/2) - if b { - buf = append(buf, 'b') - } - buf = append(buf, '"') - for width := 0; len(s) > 0; s = s[width:] { - r := rune(s[0]) - width = 1 - if r >= utf8.RuneSelf { - r, width = utf8.DecodeRuneInString(s) - } - if width == 1 && r == utf8.RuneError { - // String (!b) literals accept \xXX escapes only for ASCII, - // but we must use them here to represent invalid bytes. - // The result is not a legal literal. - buf = append(buf, `\x`...) - buf = append(buf, hex[s[0]>>4]) - buf = append(buf, hex[s[0]&0xF]) - continue - } - if r == '"' || r == '\\' { // always backslashed - buf = append(buf, '\\') - buf = append(buf, byte(r)) - continue - } - if strconv.IsPrint(r) { - n := utf8.EncodeRune(runeTmp[:], r) - buf = append(buf, runeTmp[:n]...) - continue - } - switch r { - case '\a': - buf = append(buf, `\a`...) - case '\b': - buf = append(buf, `\b`...) - case '\f': - buf = append(buf, `\f`...) - case '\n': - buf = append(buf, `\n`...) - case '\r': - buf = append(buf, `\r`...) - case '\t': - buf = append(buf, `\t`...) - case '\v': - buf = append(buf, `\v`...) - default: - switch { - case r < ' ' || r == 0x7f: - buf = append(buf, `\x`...) - buf = append(buf, hex[byte(r)>>4]) - buf = append(buf, hex[byte(r)&0xF]) - case r > utf8.MaxRune: - r = 0xFFFD - fallthrough - case r < 0x10000: - buf = append(buf, `\u`...) - for s := 12; s >= 0; s -= 4 { - buf = append(buf, hex[r>>uint(s)&0xF]) - } - default: - buf = append(buf, `\U`...) - for s := 28; s >= 0; s -= 4 { - buf = append(buf, hex[r>>uint(s)&0xF]) - } - } - } - } - buf = append(buf, '"') - return string(buf) -} diff --git a/tests/vendor/go.starlark.net/syntax/scan.go b/tests/vendor/go.starlark.net/syntax/scan.go deleted file mode 100644 index 95499772f..000000000 --- a/tests/vendor/go.starlark.net/syntax/scan.go +++ /dev/null @@ -1,1124 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syntax - -// A lexical scanner for Starlark. - -import ( - "fmt" - "io" - "log" - "math/big" - "os" - "strconv" - "strings" - "unicode" - "unicode/utf8" -) - -// A Token represents a Starlark lexical token. -type Token int8 - -const ( - ILLEGAL Token = iota - EOF - - NEWLINE - INDENT - OUTDENT - - // Tokens with values - IDENT // x - INT // 123 - FLOAT // 1.23e45 - STRING // "foo" or 'foo' or '''foo''' or r'foo' or r"foo" - BYTES // b"foo", etc - - // Punctuation - PLUS // + - MINUS // - - STAR // * - SLASH // / - SLASHSLASH // // - PERCENT // % - AMP // & - PIPE // | - CIRCUMFLEX // ^ - LTLT // << - GTGT // >> - TILDE // ~ - DOT // . - COMMA // , - EQ // = - SEMI // ; - COLON // : - LPAREN // ( - RPAREN // ) - LBRACK // [ - RBRACK // ] - LBRACE // { - RBRACE // } - LT // < - GT // > - GE // >= - LE // <= - EQL // == - NEQ // != - PLUS_EQ // += (keep order consistent with PLUS..GTGT) - MINUS_EQ // -= - STAR_EQ // *= - SLASH_EQ // /= - SLASHSLASH_EQ // //= - PERCENT_EQ // %= - AMP_EQ // &= - PIPE_EQ // |= - CIRCUMFLEX_EQ // ^= - LTLT_EQ // <<= - GTGT_EQ // >>= - STARSTAR // ** - - // Keywords - AND - BREAK - CONTINUE - DEF - ELIF - ELSE - FOR - IF - IN - LAMBDA - LOAD - NOT - NOT_IN // synthesized by parser from NOT IN - OR - PASS - RETURN - WHILE - - maxToken -) - -func (tok Token) String() string { return tokenNames[tok] } - -// GoString is like String but quotes punctuation tokens. -// Use Sprintf("%#v", tok) when constructing error messages. -func (tok Token) GoString() string { - if tok >= PLUS && tok <= STARSTAR { - return "'" + tokenNames[tok] + "'" - } - return tokenNames[tok] -} - -var tokenNames = [...]string{ - ILLEGAL: "illegal token", - EOF: "end of file", - NEWLINE: "newline", - INDENT: "indent", - OUTDENT: "outdent", - IDENT: "identifier", - INT: "int literal", - FLOAT: "float literal", - STRING: "string literal", - PLUS: "+", - MINUS: "-", - STAR: "*", - SLASH: "/", - SLASHSLASH: "//", - PERCENT: "%", - AMP: "&", - PIPE: "|", - CIRCUMFLEX: "^", - LTLT: "<<", - GTGT: ">>", - TILDE: "~", - DOT: ".", - COMMA: ",", - EQ: "=", - SEMI: ";", - COLON: ":", - LPAREN: "(", - RPAREN: ")", - LBRACK: "[", - RBRACK: "]", - LBRACE: "{", - RBRACE: "}", - LT: "<", - GT: ">", - GE: ">=", - LE: "<=", - EQL: "==", - NEQ: "!=", - PLUS_EQ: "+=", - MINUS_EQ: "-=", - STAR_EQ: "*=", - SLASH_EQ: "/=", - SLASHSLASH_EQ: "//=", - PERCENT_EQ: "%=", - AMP_EQ: "&=", - PIPE_EQ: "|=", - CIRCUMFLEX_EQ: "^=", - LTLT_EQ: "<<=", - GTGT_EQ: ">>=", - STARSTAR: "**", - AND: "and", - BREAK: "break", - CONTINUE: "continue", - DEF: "def", - ELIF: "elif", - ELSE: "else", - FOR: "for", - IF: "if", - IN: "in", - LAMBDA: "lambda", - LOAD: "load", - NOT: "not", - NOT_IN: "not in", - OR: "or", - PASS: "pass", - RETURN: "return", - WHILE: "while", -} - -// A FilePortion describes the content of a portion of a file. -// Callers may provide a FilePortion for the src argument of Parse -// when the desired initial line and column numbers are not (1, 1), -// such as when an expression is parsed from within larger file. -type FilePortion struct { - Content []byte - FirstLine, FirstCol int32 -} - -// A Position describes the location of a rune of input. -type Position struct { - file *string // filename (indirect for compactness) - Line int32 // 1-based line number; 0 if line unknown - Col int32 // 1-based column (rune) number; 0 if column unknown -} - -// IsValid reports whether the position is valid. -func (p Position) IsValid() bool { return p.file != nil } - -// Filename returns the name of the file containing this position. -func (p Position) Filename() string { - if p.file != nil { - return *p.file - } - return "" -} - -// MakePosition returns position with the specified components. -func MakePosition(file *string, line, col int32) Position { return Position{file, line, col} } - -// add returns the position at the end of s, assuming it starts at p. -func (p Position) add(s string) Position { - if n := strings.Count(s, "\n"); n > 0 { - p.Line += int32(n) - s = s[strings.LastIndex(s, "\n")+1:] - p.Col = 1 - } - p.Col += int32(utf8.RuneCountInString(s)) - return p -} - -func (p Position) String() string { - file := p.Filename() - if p.Line > 0 { - if p.Col > 0 { - return fmt.Sprintf("%s:%d:%d", file, p.Line, p.Col) - } - return fmt.Sprintf("%s:%d", file, p.Line) - } - return file -} - -func (p Position) isBefore(q Position) bool { - if p.Line != q.Line { - return p.Line < q.Line - } - return p.Col < q.Col -} - -// An scanner represents a single input file being parsed. -type scanner struct { - rest []byte // rest of input (in REPL, a line of input) - token []byte // token being scanned - pos Position // current input position - depth int // nesting of [ ] { } ( ) - indentstk []int // stack of indentation levels - dents int // number of saved INDENT (>0) or OUTDENT (<0) tokens to return - lineStart bool // after NEWLINE; convert spaces to indentation tokens - keepComments bool // accumulate comments in slice - lineComments []Comment // list of full line comments (if keepComments) - suffixComments []Comment // list of suffix comments (if keepComments) - - readline func() ([]byte, error) // read next line of input (REPL only) -} - -func newScanner(filename string, src interface{}, keepComments bool) (*scanner, error) { - var firstLine, firstCol int32 = 1, 1 - if portion, ok := src.(FilePortion); ok { - firstLine, firstCol = portion.FirstLine, portion.FirstCol - } - sc := &scanner{ - pos: MakePosition(&filename, firstLine, firstCol), - indentstk: make([]int, 1, 10), // []int{0} + spare capacity - lineStart: true, - keepComments: keepComments, - } - sc.readline, _ = src.(func() ([]byte, error)) // ParseCompoundStmt (REPL) only - if sc.readline == nil { - data, err := readSource(filename, src) - if err != nil { - return nil, err - } - sc.rest = data - } - return sc, nil -} - -func readSource(filename string, src interface{}) ([]byte, error) { - switch src := src.(type) { - case string: - return []byte(src), nil - case []byte: - return src, nil - case io.Reader: - data, err := io.ReadAll(src) - if err != nil { - err = &os.PathError{Op: "read", Path: filename, Err: err} - return nil, err - } - return data, nil - case FilePortion: - return src.Content, nil - case nil: - return os.ReadFile(filename) - default: - return nil, fmt.Errorf("invalid source: %T", src) - } -} - -// An Error describes the nature and position of a scanner or parser error. -type Error struct { - Pos Position - Msg string -} - -func (e Error) Error() string { return e.Pos.String() + ": " + e.Msg } - -// errorf is called to report an error. -// errorf does not return: it panics. -func (sc *scanner) error(pos Position, s string) { - panic(Error{pos, s}) -} - -func (sc *scanner) errorf(pos Position, format string, args ...interface{}) { - sc.error(pos, fmt.Sprintf(format, args...)) -} - -func (sc *scanner) recover(err *error) { - // The scanner and parser panic both for routine errors like - // syntax errors and for programmer bugs like array index - // errors. Turn both into error returns. Catching bug panics - // is especially important when processing many files. - switch e := recover().(type) { - case nil: - // no panic - case Error: - *err = e - default: - *err = Error{sc.pos, fmt.Sprintf("internal error: %v", e)} - if debug { - log.Fatal(*err) - } - } -} - -// eof reports whether the input has reached end of file. -func (sc *scanner) eof() bool { - return len(sc.rest) == 0 && !sc.readLine() -} - -// readLine attempts to read another line of input. -// Precondition: len(sc.rest)==0. -func (sc *scanner) readLine() bool { - if sc.readline != nil { - var err error - sc.rest, err = sc.readline() - if err != nil { - sc.errorf(sc.pos, "%v", err) // EOF or ErrInterrupt - } - return len(sc.rest) > 0 - } - return false -} - -// peekRune returns the next rune in the input without consuming it. -// Newlines in Unix, DOS, or Mac format are treated as one rune, '\n'. -func (sc *scanner) peekRune() rune { - // TODO(adonovan): opt: measure and perhaps inline eof. - if sc.eof() { - return 0 - } - - // fast path: ASCII - if b := sc.rest[0]; b < utf8.RuneSelf { - if b == '\r' { - return '\n' - } - return rune(b) - } - - r, _ := utf8.DecodeRune(sc.rest) - return r -} - -// readRune consumes and returns the next rune in the input. -// Newlines in Unix, DOS, or Mac format are treated as one rune, '\n'. -func (sc *scanner) readRune() rune { - // eof() has been inlined here, both to avoid a call - // and to establish len(rest)>0 to avoid a bounds check. - if len(sc.rest) == 0 { - if !sc.readLine() { - sc.error(sc.pos, "internal scanner error: readRune at EOF") - } - // Redundant, but eliminates the bounds-check below. - if len(sc.rest) == 0 { - return 0 - } - } - - // fast path: ASCII - if b := sc.rest[0]; b < utf8.RuneSelf { - r := rune(b) - sc.rest = sc.rest[1:] - if r == '\r' { - if len(sc.rest) > 0 && sc.rest[0] == '\n' { - sc.rest = sc.rest[1:] - } - r = '\n' - } - if r == '\n' { - sc.pos.Line++ - sc.pos.Col = 1 - } else { - sc.pos.Col++ - } - return r - } - - r, size := utf8.DecodeRune(sc.rest) - sc.rest = sc.rest[size:] - sc.pos.Col++ - return r -} - -// tokenValue records the position and value associated with each token. -type tokenValue struct { - raw string // raw text of token - int int64 // decoded int - bigInt *big.Int // decoded integers > int64 - float float64 // decoded float - string string // decoded string or bytes - pos Position // start position of token -} - -// startToken marks the beginning of the next input token. -// It must be followed by a call to endToken once the token has -// been consumed using readRune. -func (sc *scanner) startToken(val *tokenValue) { - sc.token = sc.rest - val.raw = "" - val.pos = sc.pos -} - -// endToken marks the end of an input token. -// It records the actual token string in val.raw if the caller -// has not done that already. -func (sc *scanner) endToken(val *tokenValue) { - if val.raw == "" { - val.raw = string(sc.token[:len(sc.token)-len(sc.rest)]) - } -} - -// nextToken is called by the parser to obtain the next input token. -// It returns the token value and sets val to the data associated with -// the token. -// -// For all our input tokens, the associated data is val.pos (the -// position where the token begins), val.raw (the input string -// corresponding to the token). For string and int tokens, the string -// and int fields additionally contain the token's interpreted value. -func (sc *scanner) nextToken(val *tokenValue) Token { - - // The following distribution of tokens guides case ordering: - // - // COMMA 27 % - // STRING 23 % - // IDENT 15 % - // EQL 11 % - // LBRACK 5.5 % - // RBRACK 5.5 % - // NEWLINE 3 % - // LPAREN 2.9 % - // RPAREN 2.9 % - // INT 2 % - // others < 1 % - // - // Although NEWLINE tokens are infrequent, and lineStart is - // usually (~97%) false on entry, skipped newlines account for - // about 50% of all iterations of the 'start' loop. - -start: - var c rune - - // Deal with leading spaces and indentation. - blank := false - savedLineStart := sc.lineStart - if sc.lineStart { - sc.lineStart = false - col := 0 - for { - c = sc.peekRune() - if c == ' ' { - col++ - sc.readRune() - } else if c == '\t' { - const tab = 8 - col += int(tab - (sc.pos.Col-1)%tab) - sc.readRune() - } else { - break - } - } - - // The third clause matches EOF. - if c == '#' || c == '\n' || c == 0 { - blank = true - } - - // Compute indentation level for non-blank lines not - // inside an expression. This is not the common case. - if !blank && sc.depth == 0 { - cur := sc.indentstk[len(sc.indentstk)-1] - if col > cur { - // indent - sc.dents++ - sc.indentstk = append(sc.indentstk, col) - } else if col < cur { - // outdent(s) - for len(sc.indentstk) > 0 && col < sc.indentstk[len(sc.indentstk)-1] { - sc.dents-- - sc.indentstk = sc.indentstk[:len(sc.indentstk)-1] // pop - } - if col != sc.indentstk[len(sc.indentstk)-1] { - sc.error(sc.pos, "unindent does not match any outer indentation level") - } - } - } - } - - // Return saved indentation tokens. - if sc.dents != 0 { - sc.startToken(val) - sc.endToken(val) - if sc.dents < 0 { - sc.dents++ - return OUTDENT - } else { - sc.dents-- - return INDENT - } - } - - // start of line proper - c = sc.peekRune() - - // Skip spaces. - for c == ' ' || c == '\t' { - sc.readRune() - c = sc.peekRune() - } - - // comment - if c == '#' { - if sc.keepComments { - sc.startToken(val) - } - // Consume up to newline (included). - for c != 0 && c != '\n' { - sc.readRune() - c = sc.peekRune() - } - if sc.keepComments { - sc.endToken(val) - if blank { - sc.lineComments = append(sc.lineComments, Comment{val.pos, val.raw}) - } else { - sc.suffixComments = append(sc.suffixComments, Comment{val.pos, val.raw}) - } - } - } - - // newline - if c == '\n' { - sc.lineStart = true - - // Ignore newlines within expressions (common case). - if sc.depth > 0 { - sc.readRune() - goto start - } - - // Ignore blank lines, except in the REPL, - // where they emit OUTDENTs and NEWLINE. - if blank { - if sc.readline == nil { - sc.readRune() - goto start - } else if len(sc.indentstk) > 1 { - sc.dents = 1 - len(sc.indentstk) - sc.indentstk = sc.indentstk[:1] - goto start - } - } - - // At top-level (not in an expression). - sc.startToken(val) - sc.readRune() - val.raw = "\n" - return NEWLINE - } - - // end of file - if c == 0 { - // Emit OUTDENTs for unfinished indentation, - // preceded by a NEWLINE if we haven't just emitted one. - if len(sc.indentstk) > 1 { - if savedLineStart { - sc.dents = 1 - len(sc.indentstk) - sc.indentstk = sc.indentstk[:1] - goto start - } else { - sc.lineStart = true - sc.startToken(val) - val.raw = "\n" - return NEWLINE - } - } - - sc.startToken(val) - sc.endToken(val) - return EOF - } - - // line continuation - if c == '\\' { - sc.readRune() - if sc.peekRune() != '\n' { - sc.errorf(sc.pos, "stray backslash in program") - } - sc.readRune() - goto start - } - - // start of the next token - sc.startToken(val) - - // comma (common case) - if c == ',' { - sc.readRune() - sc.endToken(val) - return COMMA - } - - // string literal - if c == '"' || c == '\'' { - return sc.scanString(val, c) - } - - // identifier or keyword - if isIdentStart(c) { - if (c == 'r' || c == 'b') && len(sc.rest) > 1 && (sc.rest[1] == '"' || sc.rest[1] == '\'') { - // r"..." - // b"..." - sc.readRune() - c = sc.peekRune() - return sc.scanString(val, c) - } else if c == 'r' && len(sc.rest) > 2 && sc.rest[1] == 'b' && (sc.rest[2] == '"' || sc.rest[2] == '\'') { - // rb"..." - sc.readRune() - sc.readRune() - c = sc.peekRune() - return sc.scanString(val, c) - } - - for isIdent(c) { - sc.readRune() - c = sc.peekRune() - } - sc.endToken(val) - if k, ok := keywordToken[val.raw]; ok { - return k - } - - return IDENT - } - - // brackets - switch c { - case '[', '(', '{': - sc.depth++ - sc.readRune() - sc.endToken(val) - switch c { - case '[': - return LBRACK - case '(': - return LPAREN - case '{': - return LBRACE - } - panic("unreachable") - - case ']', ')', '}': - if sc.depth == 0 { - sc.errorf(sc.pos, "unexpected %q", c) - } else { - sc.depth-- - } - sc.readRune() - sc.endToken(val) - switch c { - case ']': - return RBRACK - case ')': - return RPAREN - case '}': - return RBRACE - } - panic("unreachable") - } - - // int or float literal, or period - if isdigit(c) || c == '.' { - return sc.scanNumber(val, c) - } - - // other punctuation - defer sc.endToken(val) - switch c { - case '=', '<', '>', '!', '+', '-', '%', '/', '&', '|', '^': // possibly followed by '=' - start := sc.pos - sc.readRune() - if sc.peekRune() == '=' { - sc.readRune() - switch c { - case '<': - return LE - case '>': - return GE - case '=': - return EQL - case '!': - return NEQ - case '+': - return PLUS_EQ - case '-': - return MINUS_EQ - case '/': - return SLASH_EQ - case '%': - return PERCENT_EQ - case '&': - return AMP_EQ - case '|': - return PIPE_EQ - case '^': - return CIRCUMFLEX_EQ - } - } - switch c { - case '=': - return EQ - case '<': - if sc.peekRune() == '<' { - sc.readRune() - if sc.peekRune() == '=' { - sc.readRune() - return LTLT_EQ - } else { - return LTLT - } - } - return LT - case '>': - if sc.peekRune() == '>' { - sc.readRune() - if sc.peekRune() == '=' { - sc.readRune() - return GTGT_EQ - } else { - return GTGT - } - } - return GT - case '!': - sc.error(start, "unexpected input character '!'") - case '+': - return PLUS - case '-': - return MINUS - case '/': - if sc.peekRune() == '/' { - sc.readRune() - if sc.peekRune() == '=' { - sc.readRune() - return SLASHSLASH_EQ - } else { - return SLASHSLASH - } - } - return SLASH - case '%': - return PERCENT - case '&': - return AMP - case '|': - return PIPE - case '^': - return CIRCUMFLEX - } - panic("unreachable") - - case ':', ';', '~': // single-char tokens (except comma) - sc.readRune() - switch c { - case ':': - return COLON - case ';': - return SEMI - case '~': - return TILDE - } - panic("unreachable") - - case '*': // possibly followed by '*' or '=' - sc.readRune() - switch sc.peekRune() { - case '*': - sc.readRune() - return STARSTAR - case '=': - sc.readRune() - return STAR_EQ - } - return STAR - } - - sc.errorf(sc.pos, "unexpected input character %#q", c) - panic("unreachable") -} - -func (sc *scanner) scanString(val *tokenValue, quote rune) Token { - start := sc.pos - triple := len(sc.rest) >= 3 && sc.rest[0] == byte(quote) && sc.rest[1] == byte(quote) && sc.rest[2] == byte(quote) - sc.readRune() - - // String literals may contain escaped or unescaped newlines, - // causing them to span multiple lines (gulps) of REPL input; - // they are the only such token. Thus we cannot call endToken, - // as it assumes sc.rest is unchanged since startToken. - // Instead, buffer the token here. - // TODO(adonovan): opt: buffer only if we encounter a newline. - raw := new(strings.Builder) - - // Copy the prefix, e.g. r' or " (see startToken). - raw.Write(sc.token[:len(sc.token)-len(sc.rest)]) - - if !triple { - // single-quoted string literal - for { - if sc.eof() { - sc.error(val.pos, "unexpected EOF in string") - } - c := sc.readRune() - raw.WriteRune(c) - if c == quote { - break - } - if c == '\n' { - sc.error(val.pos, "unexpected newline in string") - } - if c == '\\' { - if sc.eof() { - sc.error(val.pos, "unexpected EOF in string") - } - c = sc.readRune() - raw.WriteRune(c) - } - } - } else { - // triple-quoted string literal - sc.readRune() - raw.WriteRune(quote) - sc.readRune() - raw.WriteRune(quote) - - quoteCount := 0 - for { - if sc.eof() { - sc.error(val.pos, "unexpected EOF in string") - } - c := sc.readRune() - raw.WriteRune(c) - if c == quote { - quoteCount++ - if quoteCount == 3 { - break - } - } else { - quoteCount = 0 - } - if c == '\\' { - if sc.eof() { - sc.error(val.pos, "unexpected EOF in string") - } - c = sc.readRune() - raw.WriteRune(c) - } - } - } - val.raw = raw.String() - - s, _, isByte, err := unquote(val.raw) - if err != nil { - sc.error(start, err.Error()) - } - val.string = s - if isByte { - return BYTES - } else { - return STRING - } -} - -func (sc *scanner) scanNumber(val *tokenValue, c rune) Token { - // https://github.com/google/starlark-go/blob/master/doc/spec.md#lexical-elements - // - // Python features not supported: - // - integer literals of >64 bits of precision - // - 123L or 123l long suffix - // - traditional octal: 0755 - // https://docs.python.org/2/reference/lexical_analysis.html#integer-and-long-integer-literals - - start := sc.pos - fraction, exponent := false, false - - if c == '.' { - // dot or start of fraction - sc.readRune() - c = sc.peekRune() - if !isdigit(c) { - sc.endToken(val) - return DOT - } - fraction = true - } else if c == '0' { - // hex, octal, binary or float - sc.readRune() - c = sc.peekRune() - - if c == '.' { - fraction = true - } else if c == 'x' || c == 'X' { - // hex - sc.readRune() - c = sc.peekRune() - if !isxdigit(c) { - sc.error(start, "invalid hex literal") - } - for isxdigit(c) { - sc.readRune() - c = sc.peekRune() - } - } else if c == 'o' || c == 'O' { - // octal - sc.readRune() - c = sc.peekRune() - if !isodigit(c) { - sc.error(sc.pos, "invalid octal literal") - } - for isodigit(c) { - sc.readRune() - c = sc.peekRune() - } - } else if c == 'b' || c == 'B' { - // binary - sc.readRune() - c = sc.peekRune() - if !isbdigit(c) { - sc.error(sc.pos, "invalid binary literal") - } - for isbdigit(c) { - sc.readRune() - c = sc.peekRune() - } - } else { - // float (or obsolete octal "0755") - allzeros, octal := true, true - for isdigit(c) { - if c != '0' { - allzeros = false - } - if c > '7' { - octal = false - } - sc.readRune() - c = sc.peekRune() - } - if c == '.' { - fraction = true - } else if c == 'e' || c == 'E' { - exponent = true - } else if octal && !allzeros { - sc.endToken(val) - sc.errorf(sc.pos, "obsolete form of octal literal; use 0o%s", val.raw[1:]) - } - } - } else { - // decimal - for isdigit(c) { - sc.readRune() - c = sc.peekRune() - } - - if c == '.' { - fraction = true - } else if c == 'e' || c == 'E' { - exponent = true - } - } - - if fraction { - sc.readRune() // consume '.' - c = sc.peekRune() - for isdigit(c) { - sc.readRune() - c = sc.peekRune() - } - - if c == 'e' || c == 'E' { - exponent = true - } - } - - if exponent { - sc.readRune() // consume [eE] - c = sc.peekRune() - if c == '+' || c == '-' { - sc.readRune() - c = sc.peekRune() - if !isdigit(c) { - sc.error(sc.pos, "invalid float literal") - } - } - for isdigit(c) { - sc.readRune() - c = sc.peekRune() - } - } - - sc.endToken(val) - if fraction || exponent { - var err error - val.float, err = strconv.ParseFloat(val.raw, 64) - if err != nil { - sc.error(sc.pos, "invalid float literal") - } - return FLOAT - } else { - var err error - s := val.raw - val.bigInt = nil - if len(s) > 2 && s[0] == '0' && (s[1] == 'o' || s[1] == 'O') { - val.int, err = strconv.ParseInt(s[2:], 8, 64) - } else if len(s) > 2 && s[0] == '0' && (s[1] == 'b' || s[1] == 'B') { - val.int, err = strconv.ParseInt(s[2:], 2, 64) - } else { - val.int, err = strconv.ParseInt(s, 0, 64) - if err != nil { - num := new(big.Int) - var ok bool - val.bigInt, ok = num.SetString(s, 0) - if ok { - err = nil - } - } - } - if err != nil { - sc.error(start, "invalid int literal") - } - return INT - } -} - -// isIdent reports whether c is an identifier rune. -func isIdent(c rune) bool { - return isdigit(c) || isIdentStart(c) -} - -func isIdentStart(c rune) bool { - return 'a' <= c && c <= 'z' || - 'A' <= c && c <= 'Z' || - c == '_' || - unicode.IsLetter(c) -} - -func isdigit(c rune) bool { return '0' <= c && c <= '9' } -func isodigit(c rune) bool { return '0' <= c && c <= '7' } -func isxdigit(c rune) bool { return isdigit(c) || 'A' <= c && c <= 'F' || 'a' <= c && c <= 'f' } -func isbdigit(c rune) bool { return '0' == c || c == '1' } - -// keywordToken records the special tokens for -// strings that should not be treated as ordinary identifiers. -var keywordToken = map[string]Token{ - "and": AND, - "break": BREAK, - "continue": CONTINUE, - "def": DEF, - "elif": ELIF, - "else": ELSE, - "for": FOR, - "if": IF, - "in": IN, - "lambda": LAMBDA, - "load": LOAD, - "not": NOT, - "or": OR, - "pass": PASS, - "return": RETURN, - "while": WHILE, - - // reserved words: - "as": ILLEGAL, - // "assert": ILLEGAL, // heavily used by our tests - "async": ILLEGAL, - "await": ILLEGAL, - "class": ILLEGAL, - "del": ILLEGAL, - "except": ILLEGAL, - "finally": ILLEGAL, - "from": ILLEGAL, - "global": ILLEGAL, - "import": ILLEGAL, - "is": ILLEGAL, - "nonlocal": ILLEGAL, - "raise": ILLEGAL, - "try": ILLEGAL, - "with": ILLEGAL, - "yield": ILLEGAL, -} diff --git a/tests/vendor/go.starlark.net/syntax/syntax.go b/tests/vendor/go.starlark.net/syntax/syntax.go deleted file mode 100644 index 5bfbcec39..000000000 --- a/tests/vendor/go.starlark.net/syntax/syntax.go +++ /dev/null @@ -1,529 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package syntax provides a Starlark parser and abstract syntax tree. -package syntax // import "go.starlark.net/syntax" - -// A Node is a node in a Starlark syntax tree. -type Node interface { - // Span returns the start and end position of the expression. - Span() (start, end Position) - - // Comments returns the comments associated with this node. - // It returns nil if RetainComments was not specified during parsing, - // or if AllocComments was not called. - Comments() *Comments - - // AllocComments allocates a new Comments node if there was none. - // This makes possible to add new comments using Comments() method. - AllocComments() -} - -// A Comment represents a single # comment. -type Comment struct { - Start Position - Text string // without trailing newline -} - -// Comments collects the comments associated with an expression. -type Comments struct { - Before []Comment // whole-line comments before this expression - Suffix []Comment // end-of-line comments after this expression (up to 1) - - // For top-level expressions only, After lists whole-line - // comments following the expression. - After []Comment -} - -// A commentsRef is a possibly-nil reference to a set of comments. -// A commentsRef is embedded in each type of syntax node, -// and provides its Comments and AllocComments methods. -type commentsRef struct{ ref *Comments } - -// Comments returns the comments associated with a syntax node, -// or nil if AllocComments has not yet been called. -func (cr commentsRef) Comments() *Comments { return cr.ref } - -// AllocComments enables comments to be associated with a syntax node. -func (cr *commentsRef) AllocComments() { - if cr.ref == nil { - cr.ref = new(Comments) - } -} - -// Start returns the start position of the expression. -func Start(n Node) Position { - start, _ := n.Span() - return start -} - -// End returns the end position of the expression. -func End(n Node) Position { - _, end := n.Span() - return end -} - -// A File represents a Starlark file. -type File struct { - commentsRef - Path string - Stmts []Stmt - - Module interface{} // a *resolve.Module, set by resolver - Options *FileOptions -} - -func (x *File) Span() (start, end Position) { - if len(x.Stmts) == 0 { - return - } - start, _ = x.Stmts[0].Span() - _, end = x.Stmts[len(x.Stmts)-1].Span() - return start, end -} - -// A Stmt is a Starlark statement. -type Stmt interface { - Node - stmt() -} - -func (*AssignStmt) stmt() {} -func (*BranchStmt) stmt() {} -func (*DefStmt) stmt() {} -func (*ExprStmt) stmt() {} -func (*ForStmt) stmt() {} -func (*WhileStmt) stmt() {} -func (*IfStmt) stmt() {} -func (*LoadStmt) stmt() {} -func (*ReturnStmt) stmt() {} - -// An AssignStmt represents an assignment: -// -// x = 0 -// x, y = y, x -// x += 1 -type AssignStmt struct { - commentsRef - OpPos Position - Op Token // = EQ | {PLUS,MINUS,STAR,PERCENT}_EQ - LHS Expr - RHS Expr -} - -func (x *AssignStmt) Span() (start, end Position) { - start, _ = x.LHS.Span() - _, end = x.RHS.Span() - return -} - -// A DefStmt represents a function definition. -type DefStmt struct { - commentsRef - Def Position - Name *Ident - Lparen Position - Params []Expr // param = ident | ident=expr | * | *ident | **ident - Rparen Position - Body []Stmt - - Function interface{} // a *resolve.Function, set by resolver -} - -func (x *DefStmt) Span() (start, end Position) { - _, end = x.Body[len(x.Body)-1].Span() - return x.Def, end -} - -// An ExprStmt is an expression evaluated for side effects. -type ExprStmt struct { - commentsRef - X Expr -} - -func (x *ExprStmt) Span() (start, end Position) { - return x.X.Span() -} - -// An IfStmt is a conditional: If Cond: True; else: False. -// 'elseif' is desugared into a chain of IfStmts. -type IfStmt struct { - commentsRef - If Position // IF or ELIF - Cond Expr - True []Stmt - ElsePos Position // ELSE or ELIF - False []Stmt // optional -} - -func (x *IfStmt) Span() (start, end Position) { - body := x.False - if body == nil { - body = x.True - } - _, end = body[len(body)-1].Span() - return x.If, end -} - -// A LoadStmt loads another module and binds names from it: -// load(Module, "x", y="foo"). -// -// The AST is slightly unfaithful to the concrete syntax here because -// Starlark's load statement, so that it can be implemented in Python, -// binds some names (like y above) with an identifier and some (like x) -// without. For consistency we create fake identifiers for all the -// strings. -type LoadStmt struct { - commentsRef - Load Position - Module *Literal // a string - From []*Ident // name defined in loading module - To []*Ident // name in loaded module - Rparen Position -} - -func (x *LoadStmt) Span() (start, end Position) { - return x.Load, x.Rparen -} - -// ModuleName returns the name of the module loaded by this statement. -func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) } - -// A BranchStmt changes the flow of control: break, continue, pass. -type BranchStmt struct { - commentsRef - Token Token // = BREAK | CONTINUE | PASS - TokenPos Position -} - -func (x *BranchStmt) Span() (start, end Position) { - return x.TokenPos, x.TokenPos.add(x.Token.String()) -} - -// A ReturnStmt returns from a function. -type ReturnStmt struct { - commentsRef - Return Position - Result Expr // may be nil -} - -func (x *ReturnStmt) Span() (start, end Position) { - if x.Result == nil { - return x.Return, x.Return.add("return") - } - _, end = x.Result.Span() - return x.Return, end -} - -// An Expr is a Starlark expression. -type Expr interface { - Node - expr() -} - -func (*BinaryExpr) expr() {} -func (*CallExpr) expr() {} -func (*Comprehension) expr() {} -func (*CondExpr) expr() {} -func (*DictEntry) expr() {} -func (*DictExpr) expr() {} -func (*DotExpr) expr() {} -func (*Ident) expr() {} -func (*IndexExpr) expr() {} -func (*LambdaExpr) expr() {} -func (*ListExpr) expr() {} -func (*Literal) expr() {} -func (*ParenExpr) expr() {} -func (*SliceExpr) expr() {} -func (*TupleExpr) expr() {} -func (*UnaryExpr) expr() {} - -// An Ident represents an identifier. -type Ident struct { - commentsRef - NamePos Position - Name string - - Binding interface{} // a *resolver.Binding, set by resolver -} - -func (x *Ident) Span() (start, end Position) { - return x.NamePos, x.NamePos.add(x.Name) -} - -// A Literal represents a literal string or number. -type Literal struct { - commentsRef - Token Token // = STRING | BYTES | INT | FLOAT - TokenPos Position - Raw string // uninterpreted text - Value interface{} // = string | int64 | *big.Int | float64 -} - -func (x *Literal) Span() (start, end Position) { - return x.TokenPos, x.TokenPos.add(x.Raw) -} - -// A ParenExpr represents a parenthesized expression: (X). -type ParenExpr struct { - commentsRef - Lparen Position - X Expr - Rparen Position -} - -func (x *ParenExpr) Span() (start, end Position) { - return x.Lparen, x.Rparen.add(")") -} - -// A CallExpr represents a function call expression: Fn(Args). -type CallExpr struct { - commentsRef - Fn Expr - Lparen Position - Args []Expr // arg = expr | ident=expr | *expr | **expr - Rparen Position -} - -func (x *CallExpr) Span() (start, end Position) { - start, _ = x.Fn.Span() - return start, x.Rparen.add(")") -} - -// A DotExpr represents a field or method selector: X.Name. -type DotExpr struct { - commentsRef - X Expr - Dot Position - NamePos Position - Name *Ident -} - -func (x *DotExpr) Span() (start, end Position) { - start, _ = x.X.Span() - _, end = x.Name.Span() - return -} - -// A Comprehension represents a list or dict comprehension: -// [Body for ... if ...] or {Body for ... if ...} -type Comprehension struct { - commentsRef - Curly bool // {x:y for ...} or {x for ...}, not [x for ...] - Lbrack Position - Body Expr - Clauses []Node // = *ForClause | *IfClause - Rbrack Position -} - -func (x *Comprehension) Span() (start, end Position) { - return x.Lbrack, x.Rbrack.add("]") -} - -// A ForStmt represents a loop: for Vars in X: Body. -type ForStmt struct { - commentsRef - For Position - Vars Expr // name, or tuple of names - X Expr - Body []Stmt -} - -func (x *ForStmt) Span() (start, end Position) { - _, end = x.Body[len(x.Body)-1].Span() - return x.For, end -} - -// A WhileStmt represents a while loop: while X: Body. -type WhileStmt struct { - commentsRef - While Position - Cond Expr - Body []Stmt -} - -func (x *WhileStmt) Span() (start, end Position) { - _, end = x.Body[len(x.Body)-1].Span() - return x.While, end -} - -// A ForClause represents a for clause in a list comprehension: for Vars in X. -type ForClause struct { - commentsRef - For Position - Vars Expr // name, or tuple of names - In Position - X Expr -} - -func (x *ForClause) Span() (start, end Position) { - _, end = x.X.Span() - return x.For, end -} - -// An IfClause represents an if clause in a list comprehension: if Cond. -type IfClause struct { - commentsRef - If Position - Cond Expr -} - -func (x *IfClause) Span() (start, end Position) { - _, end = x.Cond.Span() - return x.If, end -} - -// A DictExpr represents a dictionary literal: { List }. -type DictExpr struct { - commentsRef - Lbrace Position - List []Expr // all *DictEntrys - Rbrace Position -} - -func (x *DictExpr) Span() (start, end Position) { - return x.Lbrace, x.Rbrace.add("}") -} - -// A DictEntry represents a dictionary entry: Key: Value. -// Used only within a DictExpr. -type DictEntry struct { - commentsRef - Key Expr - Colon Position - Value Expr -} - -func (x *DictEntry) Span() (start, end Position) { - start, _ = x.Key.Span() - _, end = x.Value.Span() - return start, end -} - -// A LambdaExpr represents an inline function abstraction. -type LambdaExpr struct { - commentsRef - Lambda Position - Params []Expr // param = ident | ident=expr | * | *ident | **ident - Body Expr - - Function interface{} // a *resolve.Function, set by resolver -} - -func (x *LambdaExpr) Span() (start, end Position) { - _, end = x.Body.Span() - return x.Lambda, end -} - -// A ListExpr represents a list literal: [ List ]. -type ListExpr struct { - commentsRef - Lbrack Position - List []Expr - Rbrack Position -} - -func (x *ListExpr) Span() (start, end Position) { - return x.Lbrack, x.Rbrack.add("]") -} - -// CondExpr represents the conditional: X if COND else ELSE. -type CondExpr struct { - commentsRef - If Position - Cond Expr - True Expr - ElsePos Position - False Expr -} - -func (x *CondExpr) Span() (start, end Position) { - start, _ = x.True.Span() - _, end = x.False.Span() - return start, end -} - -// A TupleExpr represents a tuple literal: (List). -type TupleExpr struct { - commentsRef - Lparen Position // optional (e.g. in x, y = 0, 1), but required if List is empty - List []Expr - Rparen Position -} - -func (x *TupleExpr) Span() (start, end Position) { - if x.Lparen.IsValid() { - return x.Lparen, x.Rparen - } else { - return Start(x.List[0]), End(x.List[len(x.List)-1]) - } -} - -// A UnaryExpr represents a unary expression: Op X. -// -// As a special case, UnaryOp{Op:Star} may also represent -// the star parameter in def f(*args) or def f(*, x). -type UnaryExpr struct { - commentsRef - OpPos Position - Op Token - X Expr // may be nil if Op==STAR -} - -func (x *UnaryExpr) Span() (start, end Position) { - if x.X != nil { - _, end = x.X.Span() - } else { - end = x.OpPos.add("*") - } - return x.OpPos, end -} - -// A BinaryExpr represents a binary expression: X Op Y. -// -// As a special case, BinaryExpr{Op:EQ} may also -// represent a named argument in a call f(k=v) -// or a named parameter in a function declaration -// def f(param=default). -type BinaryExpr struct { - commentsRef - X Expr - OpPos Position - Op Token - Y Expr -} - -func (x *BinaryExpr) Span() (start, end Position) { - start, _ = x.X.Span() - _, end = x.Y.Span() - return start, end -} - -// A SliceExpr represents a slice or substring expression: X[Lo:Hi:Step]. -type SliceExpr struct { - commentsRef - X Expr - Lbrack Position - Lo, Hi, Step Expr // all optional - Rbrack Position -} - -func (x *SliceExpr) Span() (start, end Position) { - start, _ = x.X.Span() - return start, x.Rbrack -} - -// An IndexExpr represents an index expression: X[Y]. -type IndexExpr struct { - commentsRef - X Expr - Lbrack Position - Y Expr - Rbrack Position -} - -func (x *IndexExpr) Span() (start, end Position) { - start, _ = x.X.Span() - return start, x.Rbrack -} diff --git a/tests/vendor/go.starlark.net/syntax/walk.go b/tests/vendor/go.starlark.net/syntax/walk.go deleted file mode 100644 index 5e6c805c2..000000000 --- a/tests/vendor/go.starlark.net/syntax/walk.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2017 The Bazel Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syntax - -// Walk traverses a syntax tree in depth-first order. -// It starts by calling f(n); n must not be nil. -// If f returns true, Walk calls itself -// recursively for each non-nil child of n. -// Walk then calls f(nil). -func Walk(n Node, f func(Node) bool) { - if n == nil { - panic("nil") - } - if !f(n) { - return - } - - // TODO(adonovan): opt: order cases using profile data. - switch n := n.(type) { - case *File: - walkStmts(n.Stmts, f) - - case *ExprStmt: - Walk(n.X, f) - - case *BranchStmt: - // no-op - - case *IfStmt: - Walk(n.Cond, f) - walkStmts(n.True, f) - walkStmts(n.False, f) - - case *AssignStmt: - Walk(n.LHS, f) - Walk(n.RHS, f) - - case *DefStmt: - Walk(n.Name, f) - for _, param := range n.Params { - Walk(param, f) - } - walkStmts(n.Body, f) - - case *ForStmt: - Walk(n.Vars, f) - Walk(n.X, f) - walkStmts(n.Body, f) - - case *ReturnStmt: - if n.Result != nil { - Walk(n.Result, f) - } - - case *LoadStmt: - Walk(n.Module, f) - for _, from := range n.From { - Walk(from, f) - } - for _, to := range n.To { - Walk(to, f) - } - - case *Ident, *Literal: - // no-op - - case *ListExpr: - for _, x := range n.List { - Walk(x, f) - } - - case *ParenExpr: - Walk(n.X, f) - - case *CondExpr: - Walk(n.Cond, f) - Walk(n.True, f) - Walk(n.False, f) - - case *IndexExpr: - Walk(n.X, f) - Walk(n.Y, f) - - case *DictEntry: - Walk(n.Key, f) - Walk(n.Value, f) - - case *SliceExpr: - Walk(n.X, f) - if n.Lo != nil { - Walk(n.Lo, f) - } - if n.Hi != nil { - Walk(n.Hi, f) - } - if n.Step != nil { - Walk(n.Step, f) - } - - case *Comprehension: - Walk(n.Body, f) - for _, clause := range n.Clauses { - Walk(clause, f) - } - - case *IfClause: - Walk(n.Cond, f) - - case *ForClause: - Walk(n.Vars, f) - Walk(n.X, f) - - case *TupleExpr: - for _, x := range n.List { - Walk(x, f) - } - - case *DictExpr: - for _, entry := range n.List { - Walk(entry, f) - } - - case *UnaryExpr: - if n.X != nil { - Walk(n.X, f) - } - - case *BinaryExpr: - Walk(n.X, f) - Walk(n.Y, f) - - case *DotExpr: - Walk(n.X, f) - Walk(n.Name, f) - - case *CallExpr: - Walk(n.Fn, f) - for _, arg := range n.Args { - Walk(arg, f) - } - - case *LambdaExpr: - for _, param := range n.Params { - Walk(param, f) - } - Walk(n.Body, f) - - default: - panic(n) - } - - f(nil) -} - -func walkStmts(stmts []Stmt, f func(Node) bool) { - for _, stmt := range stmts { - Walk(stmt, f) - } -} diff --git a/tests/vendor/google.golang.org/grpc/grpclog/component.go b/tests/vendor/google.golang.org/grpc/grpclog/component.go index ac73c9ced..f1ae080dc 100644 --- a/tests/vendor/google.golang.org/grpc/grpclog/component.go +++ b/tests/vendor/google.golang.org/grpc/grpclog/component.go @@ -20,8 +20,6 @@ package grpclog import ( "fmt" - - "google.golang.org/grpc/internal/grpclog" ) // componentData records the settings for a component. @@ -33,22 +31,22 @@ var cache = map[string]*componentData{} func (c *componentData) InfoDepth(depth int, args ...any) { args = append([]any{"[" + string(c.name) + "]"}, args...) - grpclog.InfoDepth(depth+1, args...) + InfoDepth(depth+1, args...) } func (c *componentData) WarningDepth(depth int, args ...any) { args = append([]any{"[" + string(c.name) + "]"}, args...) - grpclog.WarningDepth(depth+1, args...) + WarningDepth(depth+1, args...) } func (c *componentData) ErrorDepth(depth int, args ...any) { args = append([]any{"[" + string(c.name) + "]"}, args...) - grpclog.ErrorDepth(depth+1, args...) + ErrorDepth(depth+1, args...) } func (c *componentData) FatalDepth(depth int, args ...any) { args = append([]any{"[" + string(c.name) + "]"}, args...) - grpclog.FatalDepth(depth+1, args...) + FatalDepth(depth+1, args...) } func (c *componentData) Info(args ...any) { diff --git a/tests/vendor/google.golang.org/grpc/grpclog/grpclog.go b/tests/vendor/google.golang.org/grpc/grpclog/grpclog.go index 16928c9cb..db320105e 100644 --- a/tests/vendor/google.golang.org/grpc/grpclog/grpclog.go +++ b/tests/vendor/google.golang.org/grpc/grpclog/grpclog.go @@ -18,18 +18,15 @@ // Package grpclog defines logging for grpc. // -// All logs in transport and grpclb packages only go to verbose level 2. -// All logs in other packages in grpc are logged in spite of the verbosity level. -// -// In the default logger, -// severity level can be set by environment variable GRPC_GO_LOG_SEVERITY_LEVEL, -// verbosity level can be set by GRPC_GO_LOG_VERBOSITY_LEVEL. -package grpclog // import "google.golang.org/grpc/grpclog" +// In the default logger, severity level can be set by environment variable +// GRPC_GO_LOG_SEVERITY_LEVEL, verbosity level can be set by +// GRPC_GO_LOG_VERBOSITY_LEVEL. +package grpclog import ( "os" - "google.golang.org/grpc/internal/grpclog" + "google.golang.org/grpc/grpclog/internal" ) func init() { @@ -38,58 +35,58 @@ func init() { // V reports whether verbosity level l is at least the requested verbose level. func V(l int) bool { - return grpclog.Logger.V(l) + return internal.LoggerV2Impl.V(l) } // Info logs to the INFO log. func Info(args ...any) { - grpclog.Logger.Info(args...) + internal.LoggerV2Impl.Info(args...) } // Infof logs to the INFO log. Arguments are handled in the manner of fmt.Printf. func Infof(format string, args ...any) { - grpclog.Logger.Infof(format, args...) + internal.LoggerV2Impl.Infof(format, args...) } // Infoln logs to the INFO log. Arguments are handled in the manner of fmt.Println. func Infoln(args ...any) { - grpclog.Logger.Infoln(args...) + internal.LoggerV2Impl.Infoln(args...) } // Warning logs to the WARNING log. func Warning(args ...any) { - grpclog.Logger.Warning(args...) + internal.LoggerV2Impl.Warning(args...) } // Warningf logs to the WARNING log. Arguments are handled in the manner of fmt.Printf. func Warningf(format string, args ...any) { - grpclog.Logger.Warningf(format, args...) + internal.LoggerV2Impl.Warningf(format, args...) } // Warningln logs to the WARNING log. Arguments are handled in the manner of fmt.Println. func Warningln(args ...any) { - grpclog.Logger.Warningln(args...) + internal.LoggerV2Impl.Warningln(args...) } // Error logs to the ERROR log. func Error(args ...any) { - grpclog.Logger.Error(args...) + internal.LoggerV2Impl.Error(args...) } // Errorf logs to the ERROR log. Arguments are handled in the manner of fmt.Printf. func Errorf(format string, args ...any) { - grpclog.Logger.Errorf(format, args...) + internal.LoggerV2Impl.Errorf(format, args...) } // Errorln logs to the ERROR log. Arguments are handled in the manner of fmt.Println. func Errorln(args ...any) { - grpclog.Logger.Errorln(args...) + internal.LoggerV2Impl.Errorln(args...) } // Fatal logs to the FATAL log. Arguments are handled in the manner of fmt.Print. // It calls os.Exit() with exit code 1. func Fatal(args ...any) { - grpclog.Logger.Fatal(args...) + internal.LoggerV2Impl.Fatal(args...) // Make sure fatal logs will exit. os.Exit(1) } @@ -97,15 +94,15 @@ func Fatal(args ...any) { // Fatalf logs to the FATAL log. Arguments are handled in the manner of fmt.Printf. // It calls os.Exit() with exit code 1. func Fatalf(format string, args ...any) { - grpclog.Logger.Fatalf(format, args...) + internal.LoggerV2Impl.Fatalf(format, args...) // Make sure fatal logs will exit. os.Exit(1) } // Fatalln logs to the FATAL log. Arguments are handled in the manner of fmt.Println. -// It calle os.Exit()) with exit code 1. +// It calls os.Exit() with exit code 1. func Fatalln(args ...any) { - grpclog.Logger.Fatalln(args...) + internal.LoggerV2Impl.Fatalln(args...) // Make sure fatal logs will exit. os.Exit(1) } @@ -114,19 +111,76 @@ func Fatalln(args ...any) { // // Deprecated: use Info. func Print(args ...any) { - grpclog.Logger.Info(args...) + internal.LoggerV2Impl.Info(args...) } // Printf prints to the logger. Arguments are handled in the manner of fmt.Printf. // // Deprecated: use Infof. func Printf(format string, args ...any) { - grpclog.Logger.Infof(format, args...) + internal.LoggerV2Impl.Infof(format, args...) } // Println prints to the logger. Arguments are handled in the manner of fmt.Println. // // Deprecated: use Infoln. func Println(args ...any) { - grpclog.Logger.Infoln(args...) + internal.LoggerV2Impl.Infoln(args...) +} + +// InfoDepth logs to the INFO log at the specified depth. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func InfoDepth(depth int, args ...any) { + if internal.DepthLoggerV2Impl != nil { + internal.DepthLoggerV2Impl.InfoDepth(depth, args...) + } else { + internal.LoggerV2Impl.Infoln(args...) + } +} + +// WarningDepth logs to the WARNING log at the specified depth. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func WarningDepth(depth int, args ...any) { + if internal.DepthLoggerV2Impl != nil { + internal.DepthLoggerV2Impl.WarningDepth(depth, args...) + } else { + internal.LoggerV2Impl.Warningln(args...) + } +} + +// ErrorDepth logs to the ERROR log at the specified depth. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func ErrorDepth(depth int, args ...any) { + if internal.DepthLoggerV2Impl != nil { + internal.DepthLoggerV2Impl.ErrorDepth(depth, args...) + } else { + internal.LoggerV2Impl.Errorln(args...) + } +} + +// FatalDepth logs to the FATAL log at the specified depth. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func FatalDepth(depth int, args ...any) { + if internal.DepthLoggerV2Impl != nil { + internal.DepthLoggerV2Impl.FatalDepth(depth, args...) + } else { + internal.LoggerV2Impl.Fatalln(args...) + } + os.Exit(1) } diff --git a/tests/vendor/google.golang.org/grpc/grpclog/internal/grpclog.go b/tests/vendor/google.golang.org/grpc/grpclog/internal/grpclog.go new file mode 100644 index 000000000..59c03bc14 --- /dev/null +++ b/tests/vendor/google.golang.org/grpc/grpclog/internal/grpclog.go @@ -0,0 +1,26 @@ +/* + * + * Copyright 2024 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package internal contains functionality internal to the grpclog package. +package internal + +// LoggerV2Impl is the logger used for the non-depth log functions. +var LoggerV2Impl LoggerV2 + +// DepthLoggerV2Impl is the logger used for the depth log functions. +var DepthLoggerV2Impl DepthLoggerV2 diff --git a/tests/vendor/google.golang.org/grpc/grpclog/internal/logger.go b/tests/vendor/google.golang.org/grpc/grpclog/internal/logger.go new file mode 100644 index 000000000..e524fdd40 --- /dev/null +++ b/tests/vendor/google.golang.org/grpc/grpclog/internal/logger.go @@ -0,0 +1,87 @@ +/* + * + * Copyright 2024 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package internal + +// Logger mimics golang's standard Logger as an interface. +// +// Deprecated: use LoggerV2. +type Logger interface { + Fatal(args ...any) + Fatalf(format string, args ...any) + Fatalln(args ...any) + Print(args ...any) + Printf(format string, args ...any) + Println(args ...any) +} + +// LoggerWrapper wraps Logger into a LoggerV2. +type LoggerWrapper struct { + Logger +} + +// Info logs to INFO log. Arguments are handled in the manner of fmt.Print. +func (l *LoggerWrapper) Info(args ...any) { + l.Logger.Print(args...) +} + +// Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println. +func (l *LoggerWrapper) Infoln(args ...any) { + l.Logger.Println(args...) +} + +// Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf. +func (l *LoggerWrapper) Infof(format string, args ...any) { + l.Logger.Printf(format, args...) +} + +// Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print. +func (l *LoggerWrapper) Warning(args ...any) { + l.Logger.Print(args...) +} + +// Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println. +func (l *LoggerWrapper) Warningln(args ...any) { + l.Logger.Println(args...) +} + +// Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf. +func (l *LoggerWrapper) Warningf(format string, args ...any) { + l.Logger.Printf(format, args...) +} + +// Error logs to ERROR log. Arguments are handled in the manner of fmt.Print. +func (l *LoggerWrapper) Error(args ...any) { + l.Logger.Print(args...) +} + +// Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println. +func (l *LoggerWrapper) Errorln(args ...any) { + l.Logger.Println(args...) +} + +// Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. +func (l *LoggerWrapper) Errorf(format string, args ...any) { + l.Logger.Printf(format, args...) +} + +// V reports whether verbosity level l is at least the requested verbose level. +func (*LoggerWrapper) V(int) bool { + // Returns true for all verbose level. + return true +} diff --git a/tests/vendor/google.golang.org/grpc/grpclog/internal/loggerv2.go b/tests/vendor/google.golang.org/grpc/grpclog/internal/loggerv2.go new file mode 100644 index 000000000..ed90060c3 --- /dev/null +++ b/tests/vendor/google.golang.org/grpc/grpclog/internal/loggerv2.go @@ -0,0 +1,267 @@ +/* + * + * Copyright 2024 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package internal + +import ( + "encoding/json" + "fmt" + "io" + "log" + "os" +) + +// LoggerV2 does underlying logging work for grpclog. +type LoggerV2 interface { + // Info logs to INFO log. Arguments are handled in the manner of fmt.Print. + Info(args ...any) + // Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println. + Infoln(args ...any) + // Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf. + Infof(format string, args ...any) + // Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print. + Warning(args ...any) + // Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println. + Warningln(args ...any) + // Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf. + Warningf(format string, args ...any) + // Error logs to ERROR log. Arguments are handled in the manner of fmt.Print. + Error(args ...any) + // Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println. + Errorln(args ...any) + // Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. + Errorf(format string, args ...any) + // Fatal logs to ERROR log. Arguments are handled in the manner of fmt.Print. + // gRPC ensures that all Fatal logs will exit with os.Exit(1). + // Implementations may also call os.Exit() with a non-zero exit code. + Fatal(args ...any) + // Fatalln logs to ERROR log. Arguments are handled in the manner of fmt.Println. + // gRPC ensures that all Fatal logs will exit with os.Exit(1). + // Implementations may also call os.Exit() with a non-zero exit code. + Fatalln(args ...any) + // Fatalf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. + // gRPC ensures that all Fatal logs will exit with os.Exit(1). + // Implementations may also call os.Exit() with a non-zero exit code. + Fatalf(format string, args ...any) + // V reports whether verbosity level l is at least the requested verbose level. + V(l int) bool +} + +// DepthLoggerV2 logs at a specified call frame. If a LoggerV2 also implements +// DepthLoggerV2, the below functions will be called with the appropriate stack +// depth set for trivial functions the logger may ignore. +// +// # Experimental +// +// Notice: This type is EXPERIMENTAL and may be changed or removed in a +// later release. +type DepthLoggerV2 interface { + LoggerV2 + // InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println. + InfoDepth(depth int, args ...any) + // WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println. + WarningDepth(depth int, args ...any) + // ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println. + ErrorDepth(depth int, args ...any) + // FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println. + FatalDepth(depth int, args ...any) +} + +const ( + // infoLog indicates Info severity. + infoLog int = iota + // warningLog indicates Warning severity. + warningLog + // errorLog indicates Error severity. + errorLog + // fatalLog indicates Fatal severity. + fatalLog +) + +// severityName contains the string representation of each severity. +var severityName = []string{ + infoLog: "INFO", + warningLog: "WARNING", + errorLog: "ERROR", + fatalLog: "FATAL", +} + +// sprintf is fmt.Sprintf. +// These vars exist to make it possible to test that expensive format calls aren't made unnecessarily. +var sprintf = fmt.Sprintf + +// sprint is fmt.Sprint. +// These vars exist to make it possible to test that expensive format calls aren't made unnecessarily. +var sprint = fmt.Sprint + +// sprintln is fmt.Sprintln. +// These vars exist to make it possible to test that expensive format calls aren't made unnecessarily. +var sprintln = fmt.Sprintln + +// exit is os.Exit. +// This var exists to make it possible to test functions calling os.Exit. +var exit = os.Exit + +// loggerT is the default logger used by grpclog. +type loggerT struct { + m []*log.Logger + v int + jsonFormat bool +} + +func (g *loggerT) output(severity int, s string) { + sevStr := severityName[severity] + if !g.jsonFormat { + g.m[severity].Output(2, sevStr+": "+s) + return + } + // TODO: we can also include the logging component, but that needs more + // (API) changes. + b, _ := json.Marshal(map[string]string{ + "severity": sevStr, + "message": s, + }) + g.m[severity].Output(2, string(b)) +} + +func (g *loggerT) printf(severity int, format string, args ...any) { + // Note the discard check is duplicated in each print func, rather than in + // output, to avoid the expensive Sprint calls. + // De-duplicating this by moving to output would be a significant performance regression! + if lg := g.m[severity]; lg.Writer() == io.Discard { + return + } + g.output(severity, sprintf(format, args...)) +} + +func (g *loggerT) print(severity int, v ...any) { + if lg := g.m[severity]; lg.Writer() == io.Discard { + return + } + g.output(severity, sprint(v...)) +} + +func (g *loggerT) println(severity int, v ...any) { + if lg := g.m[severity]; lg.Writer() == io.Discard { + return + } + g.output(severity, sprintln(v...)) +} + +func (g *loggerT) Info(args ...any) { + g.print(infoLog, args...) +} + +func (g *loggerT) Infoln(args ...any) { + g.println(infoLog, args...) +} + +func (g *loggerT) Infof(format string, args ...any) { + g.printf(infoLog, format, args...) +} + +func (g *loggerT) Warning(args ...any) { + g.print(warningLog, args...) +} + +func (g *loggerT) Warningln(args ...any) { + g.println(warningLog, args...) +} + +func (g *loggerT) Warningf(format string, args ...any) { + g.printf(warningLog, format, args...) +} + +func (g *loggerT) Error(args ...any) { + g.print(errorLog, args...) +} + +func (g *loggerT) Errorln(args ...any) { + g.println(errorLog, args...) +} + +func (g *loggerT) Errorf(format string, args ...any) { + g.printf(errorLog, format, args...) +} + +func (g *loggerT) Fatal(args ...any) { + g.print(fatalLog, args...) + exit(1) +} + +func (g *loggerT) Fatalln(args ...any) { + g.println(fatalLog, args...) + exit(1) +} + +func (g *loggerT) Fatalf(format string, args ...any) { + g.printf(fatalLog, format, args...) + exit(1) +} + +func (g *loggerT) V(l int) bool { + return l <= g.v +} + +// LoggerV2Config configures the LoggerV2 implementation. +type LoggerV2Config struct { + // Verbosity sets the verbosity level of the logger. + Verbosity int + // FormatJSON controls whether the logger should output logs in JSON format. + FormatJSON bool +} + +// combineLoggers returns a combined logger for both higher & lower severity logs, +// or only one if the other is io.Discard. +// +// This uses io.Discard instead of io.MultiWriter when all loggers +// are set to io.Discard. Both this package and the standard log package have +// significant optimizations for io.Discard, which io.MultiWriter lacks (as of +// this writing). +func combineLoggers(lower, higher io.Writer) io.Writer { + if lower == io.Discard { + return higher + } + if higher == io.Discard { + return lower + } + return io.MultiWriter(lower, higher) +} + +// NewLoggerV2 creates a new LoggerV2 instance with the provided configuration. +// The infoW, warningW, and errorW writers are used to write log messages of +// different severity levels. +func NewLoggerV2(infoW, warningW, errorW io.Writer, c LoggerV2Config) LoggerV2 { + flag := log.LstdFlags + if c.FormatJSON { + flag = 0 + } + + warningW = combineLoggers(infoW, warningW) + errorW = combineLoggers(errorW, warningW) + + fatalW := errorW + + m := []*log.Logger{ + log.New(infoW, "", flag), + log.New(warningW, "", flag), + log.New(errorW, "", flag), + log.New(fatalW, "", flag), + } + return &loggerT{m: m, v: c.Verbosity, jsonFormat: c.FormatJSON} +} diff --git a/tests/vendor/google.golang.org/grpc/grpclog/logger.go b/tests/vendor/google.golang.org/grpc/grpclog/logger.go index b1674d826..4b2035857 100644 --- a/tests/vendor/google.golang.org/grpc/grpclog/logger.go +++ b/tests/vendor/google.golang.org/grpc/grpclog/logger.go @@ -18,70 +18,17 @@ package grpclog -import "google.golang.org/grpc/internal/grpclog" +import "google.golang.org/grpc/grpclog/internal" // Logger mimics golang's standard Logger as an interface. // // Deprecated: use LoggerV2. -type Logger interface { - Fatal(args ...any) - Fatalf(format string, args ...any) - Fatalln(args ...any) - Print(args ...any) - Printf(format string, args ...any) - Println(args ...any) -} +type Logger internal.Logger // SetLogger sets the logger that is used in grpc. Call only from // init() functions. // // Deprecated: use SetLoggerV2. func SetLogger(l Logger) { - grpclog.Logger = &loggerWrapper{Logger: l} -} - -// loggerWrapper wraps Logger into a LoggerV2. -type loggerWrapper struct { - Logger -} - -func (g *loggerWrapper) Info(args ...any) { - g.Logger.Print(args...) -} - -func (g *loggerWrapper) Infoln(args ...any) { - g.Logger.Println(args...) -} - -func (g *loggerWrapper) Infof(format string, args ...any) { - g.Logger.Printf(format, args...) -} - -func (g *loggerWrapper) Warning(args ...any) { - g.Logger.Print(args...) -} - -func (g *loggerWrapper) Warningln(args ...any) { - g.Logger.Println(args...) -} - -func (g *loggerWrapper) Warningf(format string, args ...any) { - g.Logger.Printf(format, args...) -} - -func (g *loggerWrapper) Error(args ...any) { - g.Logger.Print(args...) -} - -func (g *loggerWrapper) Errorln(args ...any) { - g.Logger.Println(args...) -} - -func (g *loggerWrapper) Errorf(format string, args ...any) { - g.Logger.Printf(format, args...) -} - -func (g *loggerWrapper) V(l int) bool { - // Returns true for all verbose level. - return true + internal.LoggerV2Impl = &internal.LoggerWrapper{Logger: l} } diff --git a/tests/vendor/google.golang.org/grpc/grpclog/loggerv2.go b/tests/vendor/google.golang.org/grpc/grpclog/loggerv2.go index ecfd36d71..892dc13d1 100644 --- a/tests/vendor/google.golang.org/grpc/grpclog/loggerv2.go +++ b/tests/vendor/google.golang.org/grpc/grpclog/loggerv2.go @@ -19,52 +19,16 @@ package grpclog import ( - "encoding/json" - "fmt" "io" - "log" "os" "strconv" "strings" - "google.golang.org/grpc/internal/grpclog" + "google.golang.org/grpc/grpclog/internal" ) // LoggerV2 does underlying logging work for grpclog. -type LoggerV2 interface { - // Info logs to INFO log. Arguments are handled in the manner of fmt.Print. - Info(args ...any) - // Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println. - Infoln(args ...any) - // Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf. - Infof(format string, args ...any) - // Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print. - Warning(args ...any) - // Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println. - Warningln(args ...any) - // Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf. - Warningf(format string, args ...any) - // Error logs to ERROR log. Arguments are handled in the manner of fmt.Print. - Error(args ...any) - // Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println. - Errorln(args ...any) - // Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. - Errorf(format string, args ...any) - // Fatal logs to ERROR log. Arguments are handled in the manner of fmt.Print. - // gRPC ensures that all Fatal logs will exit with os.Exit(1). - // Implementations may also call os.Exit() with a non-zero exit code. - Fatal(args ...any) - // Fatalln logs to ERROR log. Arguments are handled in the manner of fmt.Println. - // gRPC ensures that all Fatal logs will exit with os.Exit(1). - // Implementations may also call os.Exit() with a non-zero exit code. - Fatalln(args ...any) - // Fatalf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. - // gRPC ensures that all Fatal logs will exit with os.Exit(1). - // Implementations may also call os.Exit() with a non-zero exit code. - Fatalf(format string, args ...any) - // V reports whether verbosity level l is at least the requested verbose level. - V(l int) bool -} +type LoggerV2 internal.LoggerV2 // SetLoggerV2 sets logger that is used in grpc to a V2 logger. // Not mutex-protected, should be called before any gRPC functions. @@ -72,34 +36,8 @@ func SetLoggerV2(l LoggerV2) { if _, ok := l.(*componentData); ok { panic("cannot use component logger as grpclog logger") } - grpclog.Logger = l - grpclog.DepthLogger, _ = l.(grpclog.DepthLoggerV2) -} - -const ( - // infoLog indicates Info severity. - infoLog int = iota - // warningLog indicates Warning severity. - warningLog - // errorLog indicates Error severity. - errorLog - // fatalLog indicates Fatal severity. - fatalLog -) - -// severityName contains the string representation of each severity. -var severityName = []string{ - infoLog: "INFO", - warningLog: "WARNING", - errorLog: "ERROR", - fatalLog: "FATAL", -} - -// loggerT is the default logger used by grpclog. -type loggerT struct { - m []*log.Logger - v int - jsonFormat bool + internal.LoggerV2Impl = l + internal.DepthLoggerV2Impl, _ = l.(internal.DepthLoggerV2) } // NewLoggerV2 creates a loggerV2 with the provided writers. @@ -108,32 +46,13 @@ type loggerT struct { // Warning logs will be written to warningW and infoW. // Info logs will be written to infoW. func NewLoggerV2(infoW, warningW, errorW io.Writer) LoggerV2 { - return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{}) + return internal.NewLoggerV2(infoW, warningW, errorW, internal.LoggerV2Config{}) } // NewLoggerV2WithVerbosity creates a loggerV2 with the provided writers and // verbosity level. func NewLoggerV2WithVerbosity(infoW, warningW, errorW io.Writer, v int) LoggerV2 { - return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{verbose: v}) -} - -type loggerV2Config struct { - verbose int - jsonFormat bool -} - -func newLoggerV2WithConfig(infoW, warningW, errorW io.Writer, c loggerV2Config) LoggerV2 { - var m []*log.Logger - flag := log.LstdFlags - if c.jsonFormat { - flag = 0 - } - m = append(m, log.New(infoW, "", flag)) - m = append(m, log.New(io.MultiWriter(infoW, warningW), "", flag)) - ew := io.MultiWriter(infoW, warningW, errorW) // ew will be used for error and fatal. - m = append(m, log.New(ew, "", flag)) - m = append(m, log.New(ew, "", flag)) - return &loggerT{m: m, v: c.verbose, jsonFormat: c.jsonFormat} + return internal.NewLoggerV2(infoW, warningW, errorW, internal.LoggerV2Config{Verbosity: v}) } // newLoggerV2 creates a loggerV2 to be used as default logger. @@ -161,80 +80,10 @@ func newLoggerV2() LoggerV2 { jsonFormat := strings.EqualFold(os.Getenv("GRPC_GO_LOG_FORMATTER"), "json") - return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{ - verbose: v, - jsonFormat: jsonFormat, - }) -} - -func (g *loggerT) output(severity int, s string) { - sevStr := severityName[severity] - if !g.jsonFormat { - g.m[severity].Output(2, fmt.Sprintf("%v: %v", sevStr, s)) - return - } - // TODO: we can also include the logging component, but that needs more - // (API) changes. - b, _ := json.Marshal(map[string]string{ - "severity": sevStr, - "message": s, + return internal.NewLoggerV2(infoW, warningW, errorW, internal.LoggerV2Config{ + Verbosity: v, + FormatJSON: jsonFormat, }) - g.m[severity].Output(2, string(b)) -} - -func (g *loggerT) Info(args ...any) { - g.output(infoLog, fmt.Sprint(args...)) -} - -func (g *loggerT) Infoln(args ...any) { - g.output(infoLog, fmt.Sprintln(args...)) -} - -func (g *loggerT) Infof(format string, args ...any) { - g.output(infoLog, fmt.Sprintf(format, args...)) -} - -func (g *loggerT) Warning(args ...any) { - g.output(warningLog, fmt.Sprint(args...)) -} - -func (g *loggerT) Warningln(args ...any) { - g.output(warningLog, fmt.Sprintln(args...)) -} - -func (g *loggerT) Warningf(format string, args ...any) { - g.output(warningLog, fmt.Sprintf(format, args...)) -} - -func (g *loggerT) Error(args ...any) { - g.output(errorLog, fmt.Sprint(args...)) -} - -func (g *loggerT) Errorln(args ...any) { - g.output(errorLog, fmt.Sprintln(args...)) -} - -func (g *loggerT) Errorf(format string, args ...any) { - g.output(errorLog, fmt.Sprintf(format, args...)) -} - -func (g *loggerT) Fatal(args ...any) { - g.output(fatalLog, fmt.Sprint(args...)) - os.Exit(1) -} - -func (g *loggerT) Fatalln(args ...any) { - g.output(fatalLog, fmt.Sprintln(args...)) - os.Exit(1) -} - -func (g *loggerT) Fatalf(format string, args ...any) { - g.output(fatalLog, fmt.Sprintf(format, args...)) - os.Exit(1) -} - -func (g *loggerT) V(l int) bool { - return l <= g.v } // DepthLoggerV2 logs at a specified call frame. If a LoggerV2 also implements @@ -245,14 +94,4 @@ func (g *loggerT) V(l int) bool { // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. -type DepthLoggerV2 interface { - LoggerV2 - // InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println. - InfoDepth(depth int, args ...any) - // WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println. - WarningDepth(depth int, args ...any) - // ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println. - ErrorDepth(depth int, args ...any) - // FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println. - FatalDepth(depth int, args ...any) -} +type DepthLoggerV2 internal.DepthLoggerV2 diff --git a/tests/vendor/google.golang.org/grpc/internal/experimental.go b/tests/vendor/google.golang.org/grpc/internal/experimental.go index 7f7044e17..7617be215 100644 --- a/tests/vendor/google.golang.org/grpc/internal/experimental.go +++ b/tests/vendor/google.golang.org/grpc/internal/experimental.go @@ -18,11 +18,11 @@ package internal var ( - // WithRecvBufferPool is implemented by the grpc package and returns a dial + // WithBufferPool is implemented by the grpc package and returns a dial // option to configure a shared buffer pool for a grpc.ClientConn. - WithRecvBufferPool any // func (grpc.SharedBufferPool) grpc.DialOption + WithBufferPool any // func (grpc.SharedBufferPool) grpc.DialOption - // RecvBufferPool is implemented by the grpc package and returns a server + // BufferPool is implemented by the grpc package and returns a server // option to configure a shared buffer pool for a grpc.Server. - RecvBufferPool any // func (grpc.SharedBufferPool) grpc.ServerOption + BufferPool any // func (grpc.SharedBufferPool) grpc.ServerOption ) diff --git a/tests/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go b/tests/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go deleted file mode 100644 index bfc45102a..000000000 --- a/tests/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go +++ /dev/null @@ -1,126 +0,0 @@ -/* - * - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -// Package grpclog (internal) defines depth logging for grpc. -package grpclog - -import ( - "os" -) - -// Logger is the logger used for the non-depth log functions. -var Logger LoggerV2 - -// DepthLogger is the logger used for the depth log functions. -var DepthLogger DepthLoggerV2 - -// InfoDepth logs to the INFO log at the specified depth. -func InfoDepth(depth int, args ...any) { - if DepthLogger != nil { - DepthLogger.InfoDepth(depth, args...) - } else { - Logger.Infoln(args...) - } -} - -// WarningDepth logs to the WARNING log at the specified depth. -func WarningDepth(depth int, args ...any) { - if DepthLogger != nil { - DepthLogger.WarningDepth(depth, args...) - } else { - Logger.Warningln(args...) - } -} - -// ErrorDepth logs to the ERROR log at the specified depth. -func ErrorDepth(depth int, args ...any) { - if DepthLogger != nil { - DepthLogger.ErrorDepth(depth, args...) - } else { - Logger.Errorln(args...) - } -} - -// FatalDepth logs to the FATAL log at the specified depth. -func FatalDepth(depth int, args ...any) { - if DepthLogger != nil { - DepthLogger.FatalDepth(depth, args...) - } else { - Logger.Fatalln(args...) - } - os.Exit(1) -} - -// LoggerV2 does underlying logging work for grpclog. -// This is a copy of the LoggerV2 defined in the external grpclog package. It -// is defined here to avoid a circular dependency. -type LoggerV2 interface { - // Info logs to INFO log. Arguments are handled in the manner of fmt.Print. - Info(args ...any) - // Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println. - Infoln(args ...any) - // Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf. - Infof(format string, args ...any) - // Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print. - Warning(args ...any) - // Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println. - Warningln(args ...any) - // Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf. - Warningf(format string, args ...any) - // Error logs to ERROR log. Arguments are handled in the manner of fmt.Print. - Error(args ...any) - // Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println. - Errorln(args ...any) - // Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. - Errorf(format string, args ...any) - // Fatal logs to ERROR log. Arguments are handled in the manner of fmt.Print. - // gRPC ensures that all Fatal logs will exit with os.Exit(1). - // Implementations may also call os.Exit() with a non-zero exit code. - Fatal(args ...any) - // Fatalln logs to ERROR log. Arguments are handled in the manner of fmt.Println. - // gRPC ensures that all Fatal logs will exit with os.Exit(1). - // Implementations may also call os.Exit() with a non-zero exit code. - Fatalln(args ...any) - // Fatalf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. - // gRPC ensures that all Fatal logs will exit with os.Exit(1). - // Implementations may also call os.Exit() with a non-zero exit code. - Fatalf(format string, args ...any) - // V reports whether verbosity level l is at least the requested verbose level. - V(l int) bool -} - -// DepthLoggerV2 logs at a specified call frame. If a LoggerV2 also implements -// DepthLoggerV2, the below functions will be called with the appropriate stack -// depth set for trivial functions the logger may ignore. -// This is a copy of the DepthLoggerV2 defined in the external grpclog package. -// It is defined here to avoid a circular dependency. -// -// # Experimental -// -// Notice: This type is EXPERIMENTAL and may be changed or removed in a -// later release. -type DepthLoggerV2 interface { - // InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println. - InfoDepth(depth int, args ...any) - // WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println. - WarningDepth(depth int, args ...any) - // ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println. - ErrorDepth(depth int, args ...any) - // FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println. - FatalDepth(depth int, args ...any) -} diff --git a/tests/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go b/tests/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go deleted file mode 100644 index faa998de7..000000000 --- a/tests/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go +++ /dev/null @@ -1,93 +0,0 @@ -/* - * - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package grpclog - -import ( - "fmt" -) - -// PrefixLogger does logging with a prefix. -// -// Logging method on a nil logs without any prefix. -type PrefixLogger struct { - logger DepthLoggerV2 - prefix string -} - -// Infof does info logging. -func (pl *PrefixLogger) Infof(format string, args ...any) { - if pl != nil { - // Handle nil, so the tests can pass in a nil logger. - format = pl.prefix + format - pl.logger.InfoDepth(1, fmt.Sprintf(format, args...)) - return - } - InfoDepth(1, fmt.Sprintf(format, args...)) -} - -// Warningf does warning logging. -func (pl *PrefixLogger) Warningf(format string, args ...any) { - if pl != nil { - format = pl.prefix + format - pl.logger.WarningDepth(1, fmt.Sprintf(format, args...)) - return - } - WarningDepth(1, fmt.Sprintf(format, args...)) -} - -// Errorf does error logging. -func (pl *PrefixLogger) Errorf(format string, args ...any) { - if pl != nil { - format = pl.prefix + format - pl.logger.ErrorDepth(1, fmt.Sprintf(format, args...)) - return - } - ErrorDepth(1, fmt.Sprintf(format, args...)) -} - -// Debugf does info logging at verbose level 2. -func (pl *PrefixLogger) Debugf(format string, args ...any) { - // TODO(6044): Refactor interfaces LoggerV2 and DepthLogger, and maybe - // rewrite PrefixLogger a little to ensure that we don't use the global - // `Logger` here, and instead use the `logger` field. - if !Logger.V(2) { - return - } - if pl != nil { - // Handle nil, so the tests can pass in a nil logger. - format = pl.prefix + format - pl.logger.InfoDepth(1, fmt.Sprintf(format, args...)) - return - } - InfoDepth(1, fmt.Sprintf(format, args...)) - -} - -// V reports whether verbosity level l is at least the requested verbose level. -func (pl *PrefixLogger) V(l int) bool { - // TODO(6044): Refactor interfaces LoggerV2 and DepthLogger, and maybe - // rewrite PrefixLogger a little to ensure that we don't use the global - // `Logger` here, and instead use the `logger` field. - return Logger.V(l) -} - -// NewPrefixLogger creates a prefix logger with the given prefix. -func NewPrefixLogger(logger DepthLoggerV2, prefix string) *PrefixLogger { - return &PrefixLogger{logger: logger, prefix: prefix} -} diff --git a/tests/vendor/google.golang.org/grpc/internal/internal.go b/tests/vendor/google.golang.org/grpc/internal/internal.go index 5d6653986..3afc18134 100644 --- a/tests/vendor/google.golang.org/grpc/internal/internal.go +++ b/tests/vendor/google.golang.org/grpc/internal/internal.go @@ -29,8 +29,6 @@ import ( ) var ( - // WithHealthCheckFunc is set by dialoptions.go - WithHealthCheckFunc any // func (HealthChecker) DialOption // HealthCheckFunc is used to provide client-side LB channel health checking HealthCheckFunc HealthChecker // BalancerUnregister is exported by package balancer to unregister a balancer. @@ -149,6 +147,20 @@ var ( // other features, including the CSDS service. NewXDSResolverWithConfigForTesting any // func([]byte) (resolver.Builder, error) + // NewXDSResolverWithClientForTesting creates a new xDS resolver builder + // using the provided xDS client instead of creating a new one using the + // bootstrap configuration specified by the supported environment variables. + // The resolver.Builder is meant to be used in conjunction with the + // grpc.WithResolvers DialOption. The resolver.Builder does not take + // ownership of the provided xDS client and it is the responsibility of the + // caller to close the client when no longer required. + // + // Testing Only + // + // This function should ONLY be used for testing and may not work with some + // other features, including the CSDS service. + NewXDSResolverWithClientForTesting any // func(xdsclient.XDSClient) (resolver.Builder, error) + // RegisterRLSClusterSpecifierPluginForTesting registers the RLS Cluster // Specifier Plugin for testing purposes, regardless of the XDSRLS environment // variable. @@ -183,7 +195,7 @@ var ( // GRPCResolverSchemeExtraMetadata determines when gRPC will add extra // metadata to RPCs. - GRPCResolverSchemeExtraMetadata string = "xds" + GRPCResolverSchemeExtraMetadata = "xds" // EnterIdleModeForTesting gets the ClientConn to enter IDLE mode. EnterIdleModeForTesting any // func(*grpc.ClientConn) @@ -191,6 +203,8 @@ var ( // ExitIdleModeForTesting gets the ClientConn to exit IDLE mode. ExitIdleModeForTesting any // func(*grpc.ClientConn) error + // ChannelzTurnOffForTesting disables the Channelz service for testing + // purposes. ChannelzTurnOffForTesting func() // TriggerXDSResourceNotFoundForTesting causes the provided xDS Client to @@ -203,11 +217,27 @@ var ( // UserSetDefaultScheme is set to true if the user has overridden the // default resolver scheme. - UserSetDefaultScheme bool = false + UserSetDefaultScheme = false - // ShuffleAddressListForTesting pseudo-randomizes the order of addresses. n - // is the number of elements. swap swaps the elements with indexes i and j. - ShuffleAddressListForTesting any // func(n int, swap func(i, j int)) + // ConnectedAddress returns the connected address for a SubConnState. The + // address is only valid if the state is READY. + ConnectedAddress any // func (scs SubConnState) resolver.Address + + // SetConnectedAddress sets the connected address for a SubConnState. + SetConnectedAddress any // func(scs *SubConnState, addr resolver.Address) + + // SnapshotMetricRegistryForTesting snapshots the global data of the metric + // registry. Returns a cleanup function that sets the metric registry to its + // original state. Only called in testing functions. + SnapshotMetricRegistryForTesting func() func() + + // SetDefaultBufferPoolForTesting updates the default buffer pool, for + // testing purposes. + SetDefaultBufferPoolForTesting any // func(mem.BufferPool) + + // SetBufferPoolingThresholdForTesting updates the buffer pooling threshold, for + // testing purposes. + SetBufferPoolingThresholdForTesting any // func(int) ) // HealthChecker defines the signature of the client-side LB channel health @@ -215,7 +245,7 @@ var ( // // The implementation is expected to create a health checking RPC stream by // calling newStream(), watch for the health status of serviceName, and report -// it's health back by calling setConnectivityState(). +// its health back by calling setConnectivityState(). // // The health checking protocol is defined at: // https://github.com/grpc/grpc/blob/master/doc/health-checking.md @@ -237,3 +267,9 @@ const ( // It currently has an experimental suffix which would be removed once // end-to-end testing of the policy is completed. const RLSLoadBalancingPolicyName = "rls_experimental" + +// EnforceSubConnEmbedding is used to enforce proper SubConn implementation +// embedding. +type EnforceSubConnEmbedding interface { + enforceSubConnEmbedding() +} diff --git a/tests/vendor/google.golang.org/grpc/internal/status/status.go b/tests/vendor/google.golang.org/grpc/internal/status/status.go index c7dbc8205..1186f1e9a 100644 --- a/tests/vendor/google.golang.org/grpc/internal/status/status.go +++ b/tests/vendor/google.golang.org/grpc/internal/status/status.go @@ -138,17 +138,19 @@ func (s *Status) WithDetails(details ...protoadapt.MessageV1) (*Status, error) { // s.Code() != OK implies that s.Proto() != nil. p := s.Proto() for _, detail := range details { - any, err := anypb.New(protoadapt.MessageV2Of(detail)) + m, err := anypb.New(protoadapt.MessageV2Of(detail)) if err != nil { return nil, err } - p.Details = append(p.Details, any) + p.Details = append(p.Details, m) } return &Status{s: p}, nil } // Details returns a slice of details messages attached to the status. // If a detail cannot be decoded, the error is returned in place of the detail. +// If the detail can be decoded, the proto message returned is of the same +// type that was given to WithDetails(). func (s *Status) Details() []any { if s == nil || s.s == nil { return nil @@ -160,7 +162,38 @@ func (s *Status) Details() []any { details = append(details, err) continue } - details = append(details, detail) + // The call to MessageV1Of is required to unwrap the proto message if + // it implemented only the MessageV1 API. The proto message would have + // been wrapped in a V2 wrapper in Status.WithDetails. V2 messages are + // added to a global registry used by any.UnmarshalNew(). + // MessageV1Of has the following behaviour: + // 1. If the given message is a wrapped MessageV1, it returns the + // unwrapped value. + // 2. If the given message already implements MessageV1, it returns it + // as is. + // 3. Else, it wraps the MessageV2 in a MessageV1 wrapper. + // + // Since the Status.WithDetails() API only accepts MessageV1, calling + // MessageV1Of ensures we return the same type that was given to + // WithDetails: + // * If the give type implemented only MessageV1, the unwrapping from + // point 1 above will restore the type. + // * If the given type implemented both MessageV1 and MessageV2, point 2 + // above will ensure no wrapping is performed. + // * If the given type implemented only MessageV2 and was wrapped using + // MessageV1Of before passing to WithDetails(), it would be unwrapped + // in WithDetails by calling MessageV2Of(). Point 3 above will ensure + // that the type is wrapped in a MessageV1 wrapper again before + // returning. Note that protoc-gen-go doesn't generate code which + // implements ONLY MessageV2 at the time of writing. + // + // NOTE: Status details can also be added using the FromProto method. + // This could theoretically allow passing a Detail message that only + // implements the V2 API. In such a case the message will be wrapped in + // a MessageV1 wrapper when fetched using Details(). + // Since protoc-gen-go generates only code that implements both V1 and + // V2 APIs for backward compatibility, this is not a concern. + details = append(details, protoadapt.MessageV1Of(detail)) } return details } diff --git a/tests/vendor/google.golang.org/grpc/internal/tcp_keepalive_unix.go b/tests/vendor/google.golang.org/grpc/internal/tcp_keepalive_unix.go index 078137b7f..7e7aaa546 100644 --- a/tests/vendor/google.golang.org/grpc/internal/tcp_keepalive_unix.go +++ b/tests/vendor/google.golang.org/grpc/internal/tcp_keepalive_unix.go @@ -44,7 +44,7 @@ func NetDialerWithTCPKeepalive() *net.Dialer { // combination of unconditionally enabling TCP keepalives here, and // disabling the overriding of TCP keepalive parameters by setting the // KeepAlive field to a negative value above, results in OS defaults for - // the TCP keealive interval and time parameters. + // the TCP keepalive interval and time parameters. Control: func(_, _ string, c syscall.RawConn) error { return c.Control(func(fd uintptr) { unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 1) diff --git a/tests/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go b/tests/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go index fd7d43a89..d5c1085ee 100644 --- a/tests/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go +++ b/tests/vendor/google.golang.org/grpc/internal/tcp_keepalive_windows.go @@ -44,7 +44,7 @@ func NetDialerWithTCPKeepalive() *net.Dialer { // combination of unconditionally enabling TCP keepalives here, and // disabling the overriding of TCP keepalive parameters by setting the // KeepAlive field to a negative value above, results in OS defaults for - // the TCP keealive interval and time parameters. + // the TCP keepalive interval and time parameters. Control: func(_, _ string, c syscall.RawConn) error { return c.Control(func(fd uintptr) { windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_KEEPALIVE, 1) diff --git a/tests/vendor/gopkg.in/evanphx/json-patch.v5/.gitignore b/tests/vendor/gopkg.in/evanphx/json-patch.v5/.gitignore deleted file mode 100644 index b7ed7f956..000000000 --- a/tests/vendor/gopkg.in/evanphx/json-patch.v5/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# editor and IDE paraphernalia -.idea -.vscode - -# macOS paraphernalia -.DS_Store diff --git a/tests/vendor/gopkg.in/evanphx/json-patch.v5/LICENSE b/tests/vendor/gopkg.in/evanphx/json-patch.v5/LICENSE deleted file mode 100644 index df76d7d77..000000000 --- a/tests/vendor/gopkg.in/evanphx/json-patch.v5/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2014, Evan Phoenix -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -* Neither the name of the Evan Phoenix nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/vendor/gopkg.in/evanphx/json-patch.v5/README.md b/tests/vendor/gopkg.in/evanphx/json-patch.v5/README.md deleted file mode 100644 index 97e319b21..000000000 --- a/tests/vendor/gopkg.in/evanphx/json-patch.v5/README.md +++ /dev/null @@ -1,317 +0,0 @@ -# JSON-Patch -`jsonpatch` is a library which provides functionality for both applying -[RFC6902 JSON patches](http://tools.ietf.org/html/rfc6902) against documents, as -well as for calculating & applying [RFC7396 JSON merge patches](https://tools.ietf.org/html/rfc7396). - -[![GoDoc](https://godoc.org/github.com/evanphx/json-patch?status.svg)](http://godoc.org/github.com/evanphx/json-patch) -[![Build Status](https://github.com/evanphx/json-patch/actions/workflows/go.yml/badge.svg)](https://github.com/evanphx/json-patch/actions/workflows/go.yml) -[![Report Card](https://goreportcard.com/badge/github.com/evanphx/json-patch)](https://goreportcard.com/report/github.com/evanphx/json-patch) - -# Get It! - -**Latest and greatest**: -```bash -go get -u github.com/evanphx/json-patch/v5 -``` - -**Stable Versions**: -* Version 5: `go get -u gopkg.in/evanphx/json-patch.v5` -* Version 4: `go get -u gopkg.in/evanphx/json-patch.v4` - -(previous versions below `v3` are unavailable) - -# Use It! -* [Create and apply a merge patch](#create-and-apply-a-merge-patch) -* [Create and apply a JSON Patch](#create-and-apply-a-json-patch) -* [Comparing JSON documents](#comparing-json-documents) -* [Combine merge patches](#combine-merge-patches) - - -# Configuration - -* There is a global configuration variable `jsonpatch.SupportNegativeIndices`. - This defaults to `true` and enables the non-standard practice of allowing - negative indices to mean indices starting at the end of an array. This - functionality can be disabled by setting `jsonpatch.SupportNegativeIndices = - false`. - -* There is a global configuration variable `jsonpatch.AccumulatedCopySizeLimit`, - which limits the total size increase in bytes caused by "copy" operations in a - patch. It defaults to 0, which means there is no limit. - -These global variables control the behavior of `jsonpatch.Apply`. - -An alternative to `jsonpatch.Apply` is `jsonpatch.ApplyWithOptions` whose behavior -is controlled by an `options` parameter of type `*jsonpatch.ApplyOptions`. - -Structure `jsonpatch.ApplyOptions` includes the configuration options above -and adds two new options: `AllowMissingPathOnRemove` and `EnsurePathExistsOnAdd`. - -When `AllowMissingPathOnRemove` is set to `true`, `jsonpatch.ApplyWithOptions` will ignore -`remove` operations whose `path` points to a non-existent location in the JSON document. -`AllowMissingPathOnRemove` defaults to `false` which will lead to `jsonpatch.ApplyWithOptions` -returning an error when hitting a missing `path` on `remove`. - -When `EnsurePathExistsOnAdd` is set to `true`, `jsonpatch.ApplyWithOptions` will make sure -that `add` operations produce all the `path` elements that are missing from the target object. - -Use `jsonpatch.NewApplyOptions` to create an instance of `jsonpatch.ApplyOptions` -whose values are populated from the global configuration variables. - -## Create and apply a merge patch -Given both an original JSON document and a modified JSON document, you can create -a [Merge Patch](https://tools.ietf.org/html/rfc7396) document. - -It can describe the changes needed to convert from the original to the -modified JSON document. - -Once you have a merge patch, you can apply it to other JSON documents using the -`jsonpatch.MergePatch(document, patch)` function. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - // Let's create a merge patch from these two documents... - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - target := []byte(`{"name": "Jane", "age": 24}`) - - patch, err := jsonpatch.CreateMergePatch(original, target) - if err != nil { - panic(err) - } - - // Now lets apply the patch against a different JSON document... - - alternative := []byte(`{"name": "Tina", "age": 28, "height": 3.75}`) - modifiedAlternative, err := jsonpatch.MergePatch(alternative, patch) - - fmt.Printf("patch document: %s\n", patch) - fmt.Printf("updated alternative doc: %s\n", modifiedAlternative) -} -``` - -When ran, you get the following output: - -```bash -$ go run main.go -patch document: {"height":null,"name":"Jane"} -updated alternative doc: {"age":28,"name":"Jane"} -``` - -## Create and apply a JSON Patch -You can create patch objects using `DecodePatch([]byte)`, which can then -be applied against JSON documents. - -The following is an example of creating a patch from two operations, and -applying it against a JSON document. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - patchJSON := []byte(`[ - {"op": "replace", "path": "/name", "value": "Jane"}, - {"op": "remove", "path": "/height"} - ]`) - - patch, err := jsonpatch.DecodePatch(patchJSON) - if err != nil { - panic(err) - } - - modified, err := patch.Apply(original) - if err != nil { - panic(err) - } - - fmt.Printf("Original document: %s\n", original) - fmt.Printf("Modified document: %s\n", modified) -} -``` - -When ran, you get the following output: - -```bash -$ go run main.go -Original document: {"name": "John", "age": 24, "height": 3.21} -Modified document: {"age":24,"name":"Jane"} -``` - -## Comparing JSON documents -Due to potential whitespace and ordering differences, one cannot simply compare -JSON strings or byte-arrays directly. - -As such, you can instead use `jsonpatch.Equal(document1, document2)` to -determine if two JSON documents are _structurally_ equal. This ignores -whitespace differences, and key-value ordering. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - similar := []byte(` - { - "age": 24, - "height": 3.21, - "name": "John" - } - `) - different := []byte(`{"name": "Jane", "age": 20, "height": 3.37}`) - - if jsonpatch.Equal(original, similar) { - fmt.Println(`"original" is structurally equal to "similar"`) - } - - if !jsonpatch.Equal(original, different) { - fmt.Println(`"original" is _not_ structurally equal to "different"`) - } -} -``` - -When ran, you get the following output: -```bash -$ go run main.go -"original" is structurally equal to "similar" -"original" is _not_ structurally equal to "different" -``` - -## Combine merge patches -Given two JSON merge patch documents, it is possible to combine them into a -single merge patch which can describe both set of changes. - -The resulting merge patch can be used such that applying it results in a -document structurally similar as merging each merge patch to the document -in succession. - -```go -package main - -import ( - "fmt" - - jsonpatch "github.com/evanphx/json-patch" -) - -func main() { - original := []byte(`{"name": "John", "age": 24, "height": 3.21}`) - - nameAndHeight := []byte(`{"height":null,"name":"Jane"}`) - ageAndEyes := []byte(`{"age":4.23,"eyes":"blue"}`) - - // Let's combine these merge patch documents... - combinedPatch, err := jsonpatch.MergeMergePatches(nameAndHeight, ageAndEyes) - if err != nil { - panic(err) - } - - // Apply each patch individual against the original document - withoutCombinedPatch, err := jsonpatch.MergePatch(original, nameAndHeight) - if err != nil { - panic(err) - } - - withoutCombinedPatch, err = jsonpatch.MergePatch(withoutCombinedPatch, ageAndEyes) - if err != nil { - panic(err) - } - - // Apply the combined patch against the original document - - withCombinedPatch, err := jsonpatch.MergePatch(original, combinedPatch) - if err != nil { - panic(err) - } - - // Do both result in the same thing? They should! - if jsonpatch.Equal(withCombinedPatch, withoutCombinedPatch) { - fmt.Println("Both JSON documents are structurally the same!") - } - - fmt.Printf("combined merge patch: %s", combinedPatch) -} -``` - -When ran, you get the following output: -```bash -$ go run main.go -Both JSON documents are structurally the same! -combined merge patch: {"age":4.23,"eyes":"blue","height":null,"name":"Jane"} -``` - -# CLI for comparing JSON documents -You can install the commandline program `json-patch`. - -This program can take multiple JSON patch documents as arguments, -and fed a JSON document from `stdin`. It will apply the patch(es) against -the document and output the modified doc. - -**patch.1.json** -```json -[ - {"op": "replace", "path": "/name", "value": "Jane"}, - {"op": "remove", "path": "/height"} -] -``` - -**patch.2.json** -```json -[ - {"op": "add", "path": "/address", "value": "123 Main St"}, - {"op": "replace", "path": "/age", "value": "21"} -] -``` - -**document.json** -```json -{ - "name": "John", - "age": 24, - "height": 3.21 -} -``` - -You can then run: - -```bash -$ go install github.com/evanphx/json-patch/cmd/json-patch -$ cat document.json | json-patch -p patch.1.json -p patch.2.json -{"address":"123 Main St","age":"21","name":"Jane"} -``` - -# Help It! -Contributions are welcomed! Leave [an issue](https://github.com/evanphx/json-patch/issues) -or [create a PR](https://github.com/evanphx/json-patch/compare). - - -Before creating a pull request, we'd ask that you make sure tests are passing -and that you have added new tests when applicable. - -Contributors can run tests using: - -```bash -go test -cover ./... -``` - -Builds for pull requests are tested automatically -using [GitHub Actions](https://github.com/evanphx/json-patch/actions/workflows/go.yml). diff --git a/tests/vendor/gopkg.in/evanphx/json-patch.v5/errors.go b/tests/vendor/gopkg.in/evanphx/json-patch.v5/errors.go deleted file mode 100644 index 75304b443..000000000 --- a/tests/vendor/gopkg.in/evanphx/json-patch.v5/errors.go +++ /dev/null @@ -1,38 +0,0 @@ -package jsonpatch - -import "fmt" - -// AccumulatedCopySizeError is an error type returned when the accumulated size -// increase caused by copy operations in a patch operation has exceeded the -// limit. -type AccumulatedCopySizeError struct { - limit int64 - accumulated int64 -} - -// NewAccumulatedCopySizeError returns an AccumulatedCopySizeError. -func NewAccumulatedCopySizeError(l, a int64) *AccumulatedCopySizeError { - return &AccumulatedCopySizeError{limit: l, accumulated: a} -} - -// Error implements the error interface. -func (a *AccumulatedCopySizeError) Error() string { - return fmt.Sprintf("Unable to complete the copy, the accumulated size increase of copy is %d, exceeding the limit %d", a.accumulated, a.limit) -} - -// ArraySizeError is an error type returned when the array size has exceeded -// the limit. -type ArraySizeError struct { - limit int - size int -} - -// NewArraySizeError returns an ArraySizeError. -func NewArraySizeError(l, s int) *ArraySizeError { - return &ArraySizeError{limit: l, size: s} -} - -// Error implements the error interface. -func (a *ArraySizeError) Error() string { - return fmt.Sprintf("Unable to create array of size %d, limit is %d", a.size, a.limit) -} diff --git a/tests/vendor/gopkg.in/evanphx/json-patch.v5/merge.go b/tests/vendor/gopkg.in/evanphx/json-patch.v5/merge.go deleted file mode 100644 index ad88d4018..000000000 --- a/tests/vendor/gopkg.in/evanphx/json-patch.v5/merge.go +++ /dev/null @@ -1,389 +0,0 @@ -package jsonpatch - -import ( - "bytes" - "encoding/json" - "fmt" - "reflect" -) - -func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode { - curDoc, err := cur.intoDoc() - - if err != nil { - pruneNulls(patch) - return patch - } - - patchDoc, err := patch.intoDoc() - - if err != nil { - return patch - } - - mergeDocs(curDoc, patchDoc, mergeMerge) - - return cur -} - -func mergeDocs(doc, patch *partialDoc, mergeMerge bool) { - for k, v := range *patch { - if v == nil { - if mergeMerge { - (*doc)[k] = nil - } else { - delete(*doc, k) - } - } else { - cur, ok := (*doc)[k] - - if !ok || cur == nil { - if !mergeMerge { - pruneNulls(v) - } - - (*doc)[k] = v - } else { - (*doc)[k] = merge(cur, v, mergeMerge) - } - } - } -} - -func pruneNulls(n *lazyNode) { - sub, err := n.intoDoc() - - if err == nil { - pruneDocNulls(sub) - } else { - ary, err := n.intoAry() - - if err == nil { - pruneAryNulls(ary) - } - } -} - -func pruneDocNulls(doc *partialDoc) *partialDoc { - for k, v := range *doc { - if v == nil { - delete(*doc, k) - } else { - pruneNulls(v) - } - } - - return doc -} - -func pruneAryNulls(ary *partialArray) *partialArray { - newAry := []*lazyNode{} - - for _, v := range *ary { - if v != nil { - pruneNulls(v) - } - newAry = append(newAry, v) - } - - *ary = newAry - - return ary -} - -var ErrBadJSONDoc = fmt.Errorf("Invalid JSON Document") -var ErrBadJSONPatch = fmt.Errorf("Invalid JSON Patch") -var errBadMergeTypes = fmt.Errorf("Mismatched JSON Documents") - -// MergeMergePatches merges two merge patches together, such that -// applying this resulting merged merge patch to a document yields the same -// as merging each merge patch to the document in succession. -func MergeMergePatches(patch1Data, patch2Data []byte) ([]byte, error) { - return doMergePatch(patch1Data, patch2Data, true) -} - -// MergePatch merges the patchData into the docData. -func MergePatch(docData, patchData []byte) ([]byte, error) { - return doMergePatch(docData, patchData, false) -} - -func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) { - doc := &partialDoc{} - - docErr := json.Unmarshal(docData, doc) - - patch := &partialDoc{} - - patchErr := json.Unmarshal(patchData, patch) - - if _, ok := docErr.(*json.SyntaxError); ok { - return nil, ErrBadJSONDoc - } - - if _, ok := patchErr.(*json.SyntaxError); ok { - return nil, ErrBadJSONPatch - } - - if docErr == nil && *doc == nil { - return nil, ErrBadJSONDoc - } - - if patchErr == nil && *patch == nil { - return nil, ErrBadJSONPatch - } - - if docErr != nil || patchErr != nil { - // Not an error, just not a doc, so we turn straight into the patch - if patchErr == nil { - if mergeMerge { - doc = patch - } else { - doc = pruneDocNulls(patch) - } - } else { - patchAry := &partialArray{} - patchErr = json.Unmarshal(patchData, patchAry) - - if patchErr != nil { - return nil, ErrBadJSONPatch - } - - pruneAryNulls(patchAry) - - out, patchErr := json.Marshal(patchAry) - - if patchErr != nil { - return nil, ErrBadJSONPatch - } - - return out, nil - } - } else { - mergeDocs(doc, patch, mergeMerge) - } - - return json.Marshal(doc) -} - -// resemblesJSONArray indicates whether the byte-slice "appears" to be -// a JSON array or not. -// False-positives are possible, as this function does not check the internal -// structure of the array. It only checks that the outer syntax is present and -// correct. -func resemblesJSONArray(input []byte) bool { - input = bytes.TrimSpace(input) - - hasPrefix := bytes.HasPrefix(input, []byte("[")) - hasSuffix := bytes.HasSuffix(input, []byte("]")) - - return hasPrefix && hasSuffix -} - -// CreateMergePatch will return a merge patch document capable of converting -// the original document(s) to the modified document(s). -// The parameters can be bytes of either two JSON Documents, or two arrays of -// JSON documents. -// The merge patch returned follows the specification defined at http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch-07 -func CreateMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { - originalResemblesArray := resemblesJSONArray(originalJSON) - modifiedResemblesArray := resemblesJSONArray(modifiedJSON) - - // Do both byte-slices seem like JSON arrays? - if originalResemblesArray && modifiedResemblesArray { - return createArrayMergePatch(originalJSON, modifiedJSON) - } - - // Are both byte-slices are not arrays? Then they are likely JSON objects... - if !originalResemblesArray && !modifiedResemblesArray { - return createObjectMergePatch(originalJSON, modifiedJSON) - } - - // None of the above? Then return an error because of mismatched types. - return nil, errBadMergeTypes -} - -// createObjectMergePatch will return a merge-patch document capable of -// converting the original document to the modified document. -func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { - originalDoc := map[string]interface{}{} - modifiedDoc := map[string]interface{}{} - - err := json.Unmarshal(originalJSON, &originalDoc) - if err != nil { - return nil, ErrBadJSONDoc - } - - err = json.Unmarshal(modifiedJSON, &modifiedDoc) - if err != nil { - return nil, ErrBadJSONDoc - } - - dest, err := getDiff(originalDoc, modifiedDoc) - if err != nil { - return nil, err - } - - return json.Marshal(dest) -} - -// createArrayMergePatch will return an array of merge-patch documents capable -// of converting the original document to the modified document for each -// pair of JSON documents provided in the arrays. -// Arrays of mismatched sizes will result in an error. -func createArrayMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { - originalDocs := []json.RawMessage{} - modifiedDocs := []json.RawMessage{} - - err := json.Unmarshal(originalJSON, &originalDocs) - if err != nil { - return nil, ErrBadJSONDoc - } - - err = json.Unmarshal(modifiedJSON, &modifiedDocs) - if err != nil { - return nil, ErrBadJSONDoc - } - - total := len(originalDocs) - if len(modifiedDocs) != total { - return nil, ErrBadJSONDoc - } - - result := []json.RawMessage{} - for i := 0; i < len(originalDocs); i++ { - original := originalDocs[i] - modified := modifiedDocs[i] - - patch, err := createObjectMergePatch(original, modified) - if err != nil { - return nil, err - } - - result = append(result, json.RawMessage(patch)) - } - - return json.Marshal(result) -} - -// Returns true if the array matches (must be json types). -// As is idiomatic for go, an empty array is not the same as a nil array. -func matchesArray(a, b []interface{}) bool { - if len(a) != len(b) { - return false - } - if (a == nil && b != nil) || (a != nil && b == nil) { - return false - } - for i := range a { - if !matchesValue(a[i], b[i]) { - return false - } - } - return true -} - -// Returns true if the values matches (must be json types) -// The types of the values must match, otherwise it will always return false -// If two map[string]interface{} are given, all elements must match. -func matchesValue(av, bv interface{}) bool { - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - return false - } - switch at := av.(type) { - case string: - bt := bv.(string) - if bt == at { - return true - } - case float64: - bt := bv.(float64) - if bt == at { - return true - } - case bool: - bt := bv.(bool) - if bt == at { - return true - } - case nil: - // Both nil, fine. - return true - case map[string]interface{}: - bt := bv.(map[string]interface{}) - if len(bt) != len(at) { - return false - } - for key := range bt { - av, aOK := at[key] - bv, bOK := bt[key] - if aOK != bOK { - return false - } - if !matchesValue(av, bv) { - return false - } - } - return true - case []interface{}: - bt := bv.([]interface{}) - return matchesArray(at, bt) - } - return false -} - -// getDiff returns the (recursive) difference between a and b as a map[string]interface{}. -func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) { - into := map[string]interface{}{} - for key, bv := range b { - av, ok := a[key] - // value was added - if !ok { - into[key] = bv - continue - } - // If types have changed, replace completely - if reflect.TypeOf(av) != reflect.TypeOf(bv) { - into[key] = bv - continue - } - // Types are the same, compare values - switch at := av.(type) { - case map[string]interface{}: - bt := bv.(map[string]interface{}) - dst := make(map[string]interface{}, len(bt)) - dst, err := getDiff(at, bt) - if err != nil { - return nil, err - } - if len(dst) > 0 { - into[key] = dst - } - case string, float64, bool: - if !matchesValue(av, bv) { - into[key] = bv - } - case []interface{}: - bt := bv.([]interface{}) - if !matchesArray(at, bt) { - into[key] = bv - } - case nil: - switch bv.(type) { - case nil: - // Both nil, fine. - default: - into[key] = bv - } - default: - panic(fmt.Sprintf("Unknown type:%T in key %s", av, key)) - } - } - // Now add all deleted values as nil - for key := range a { - _, found := b[key] - if !found { - into[key] = nil - } - } - return into, nil -} diff --git a/tests/vendor/gopkg.in/evanphx/json-patch.v5/patch.go b/tests/vendor/gopkg.in/evanphx/json-patch.v5/patch.go deleted file mode 100644 index cd0274e1e..000000000 --- a/tests/vendor/gopkg.in/evanphx/json-patch.v5/patch.go +++ /dev/null @@ -1,851 +0,0 @@ -package jsonpatch - -import ( - "bytes" - "encoding/json" - "fmt" - "strconv" - "strings" - - "github.com/pkg/errors" -) - -const ( - eRaw = iota - eDoc - eAry -) - -var ( - // SupportNegativeIndices decides whether to support non-standard practice of - // allowing negative indices to mean indices starting at the end of an array. - // Default to true. - SupportNegativeIndices bool = true - // AccumulatedCopySizeLimit limits the total size increase in bytes caused by - // "copy" operations in a patch. - AccumulatedCopySizeLimit int64 = 0 -) - -var ( - ErrTestFailed = errors.New("test failed") - ErrMissing = errors.New("missing value") - ErrUnknownType = errors.New("unknown object type") - ErrInvalid = errors.New("invalid state detected") - ErrInvalidIndex = errors.New("invalid index referenced") -) - -type lazyNode struct { - raw *json.RawMessage - doc partialDoc - ary partialArray - which int -} - -// Operation is a single JSON-Patch step, such as a single 'add' operation. -type Operation map[string]*json.RawMessage - -// Patch is an ordered collection of Operations. -type Patch []Operation - -type partialDoc map[string]*lazyNode -type partialArray []*lazyNode - -type container interface { - get(key string) (*lazyNode, error) - set(key string, val *lazyNode) error - add(key string, val *lazyNode) error - remove(key string) error -} - -func newLazyNode(raw *json.RawMessage) *lazyNode { - return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw} -} - -func (n *lazyNode) MarshalJSON() ([]byte, error) { - switch n.which { - case eRaw: - return json.Marshal(n.raw) - case eDoc: - return json.Marshal(n.doc) - case eAry: - return json.Marshal(n.ary) - default: - return nil, ErrUnknownType - } -} - -func (n *lazyNode) UnmarshalJSON(data []byte) error { - dest := make(json.RawMessage, len(data)) - copy(dest, data) - n.raw = &dest - n.which = eRaw - return nil -} - -func deepCopy(src *lazyNode) (*lazyNode, int, error) { - if src == nil { - return nil, 0, nil - } - a, err := src.MarshalJSON() - if err != nil { - return nil, 0, err - } - sz := len(a) - ra := make(json.RawMessage, sz) - copy(ra, a) - return newLazyNode(&ra), sz, nil -} - -func (n *lazyNode) intoDoc() (*partialDoc, error) { - if n.which == eDoc { - return &n.doc, nil - } - - if n.raw == nil { - return nil, ErrInvalid - } - - err := json.Unmarshal(*n.raw, &n.doc) - - if err != nil { - return nil, err - } - - n.which = eDoc - return &n.doc, nil -} - -func (n *lazyNode) intoAry() (*partialArray, error) { - if n.which == eAry { - return &n.ary, nil - } - - if n.raw == nil { - return nil, ErrInvalid - } - - err := json.Unmarshal(*n.raw, &n.ary) - - if err != nil { - return nil, err - } - - n.which = eAry - return &n.ary, nil -} - -func (n *lazyNode) compact() []byte { - buf := &bytes.Buffer{} - - if n.raw == nil { - return nil - } - - err := json.Compact(buf, *n.raw) - - if err != nil { - return *n.raw - } - - return buf.Bytes() -} - -func (n *lazyNode) tryDoc() bool { - if n.raw == nil { - return false - } - - err := json.Unmarshal(*n.raw, &n.doc) - - if err != nil { - return false - } - - n.which = eDoc - return true -} - -func (n *lazyNode) tryAry() bool { - if n.raw == nil { - return false - } - - err := json.Unmarshal(*n.raw, &n.ary) - - if err != nil { - return false - } - - n.which = eAry - return true -} - -func (n *lazyNode) equal(o *lazyNode) bool { - if n.which == eRaw { - if !n.tryDoc() && !n.tryAry() { - if o.which != eRaw { - return false - } - - return bytes.Equal(n.compact(), o.compact()) - } - } - - if n.which == eDoc { - if o.which == eRaw { - if !o.tryDoc() { - return false - } - } - - if o.which != eDoc { - return false - } - - if len(n.doc) != len(o.doc) { - return false - } - - for k, v := range n.doc { - ov, ok := o.doc[k] - - if !ok { - return false - } - - if (v == nil) != (ov == nil) { - return false - } - - if v == nil && ov == nil { - continue - } - - if !v.equal(ov) { - return false - } - } - - return true - } - - if o.which != eAry && !o.tryAry() { - return false - } - - if len(n.ary) != len(o.ary) { - return false - } - - for idx, val := range n.ary { - if !val.equal(o.ary[idx]) { - return false - } - } - - return true -} - -// Kind reads the "op" field of the Operation. -func (o Operation) Kind() string { - if obj, ok := o["op"]; ok && obj != nil { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown" - } - - return op - } - - return "unknown" -} - -// Path reads the "path" field of the Operation. -func (o Operation) Path() (string, error) { - if obj, ok := o["path"]; ok && obj != nil { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown", err - } - - return op, nil - } - - return "unknown", errors.Wrapf(ErrMissing, "operation missing path field") -} - -// From reads the "from" field of the Operation. -func (o Operation) From() (string, error) { - if obj, ok := o["from"]; ok && obj != nil { - var op string - - err := json.Unmarshal(*obj, &op) - - if err != nil { - return "unknown", err - } - - return op, nil - } - - return "unknown", errors.Wrapf(ErrMissing, "operation, missing from field") -} - -func (o Operation) value() *lazyNode { - if obj, ok := o["value"]; ok { - return newLazyNode(obj) - } - - return nil -} - -// ValueInterface decodes the operation value into an interface. -func (o Operation) ValueInterface() (interface{}, error) { - if obj, ok := o["value"]; ok && obj != nil { - var v interface{} - - err := json.Unmarshal(*obj, &v) - - if err != nil { - return nil, err - } - - return v, nil - } - - return nil, errors.Wrapf(ErrMissing, "operation, missing value field") -} - -func isArray(buf []byte) bool { -Loop: - for _, c := range buf { - switch c { - case ' ': - case '\n': - case '\t': - continue - case '[': - return true - default: - break Loop - } - } - - return false -} - -func findObject(pd *container, path string) (container, string) { - doc := *pd - - split := strings.Split(path, "/") - - if len(split) < 2 { - return nil, "" - } - - parts := split[1 : len(split)-1] - - key := split[len(split)-1] - - var err error - - for _, part := range parts { - - next, ok := doc.get(decodePatchKey(part)) - - if next == nil || ok != nil || next.raw == nil { - return nil, "" - } - - if isArray(*next.raw) { - doc, err = next.intoAry() - - if err != nil { - return nil, "" - } - } else { - doc, err = next.intoDoc() - - if err != nil { - return nil, "" - } - } - } - - return doc, decodePatchKey(key) -} - -func (d *partialDoc) set(key string, val *lazyNode) error { - (*d)[key] = val - return nil -} - -func (d *partialDoc) add(key string, val *lazyNode) error { - (*d)[key] = val - return nil -} - -func (d *partialDoc) get(key string) (*lazyNode, error) { - return (*d)[key], nil -} - -func (d *partialDoc) remove(key string) error { - _, ok := (*d)[key] - if !ok { - return errors.Wrapf(ErrMissing, "Unable to remove nonexistent key: %s", key) - } - - delete(*d, key) - return nil -} - -// set should only be used to implement the "replace" operation, so "key" must -// be an already existing index in "d". -func (d *partialArray) set(key string, val *lazyNode) error { - idx, err := strconv.Atoi(key) - if err != nil { - return err - } - - if idx < 0 { - if !SupportNegativeIndices { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(*d) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(*d) - } - - (*d)[idx] = val - return nil -} - -func (d *partialArray) add(key string, val *lazyNode) error { - if key == "-" { - *d = append(*d, val) - return nil - } - - idx, err := strconv.Atoi(key) - if err != nil { - return errors.Wrapf(err, "value was not a proper array index: '%s'", key) - } - - sz := len(*d) + 1 - - ary := make([]*lazyNode, sz) - - cur := *d - - if idx >= len(ary) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - - if idx < 0 { - if !SupportNegativeIndices { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(ary) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(ary) - } - - copy(ary[0:idx], cur[0:idx]) - ary[idx] = val - copy(ary[idx+1:], cur[idx:]) - - *d = ary - return nil -} - -func (d *partialArray) get(key string) (*lazyNode, error) { - idx, err := strconv.Atoi(key) - - if err != nil { - return nil, err - } - - if idx < 0 { - if !SupportNegativeIndices { - return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(*d) { - return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(*d) - } - - if idx >= len(*d) { - return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - - return (*d)[idx], nil -} - -func (d *partialArray) remove(key string) error { - idx, err := strconv.Atoi(key) - if err != nil { - return err - } - - cur := *d - - if idx >= len(cur) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - - if idx < 0 { - if !SupportNegativeIndices { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - if idx < -len(cur) { - return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx) - } - idx += len(cur) - } - - ary := make([]*lazyNode, len(cur)-1) - - copy(ary[0:idx], cur[0:idx]) - copy(ary[idx:], cur[idx+1:]) - - *d = ary - return nil - -} - -func (p Patch) add(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(ErrMissing, "add operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "add operation does not apply: doc is missing path: \"%s\"", path) - } - - err = con.add(key, op.value()) - if err != nil { - return errors.Wrapf(err, "error in add for path: '%s'", path) - } - - return nil -} - -func (p Patch) remove(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(ErrMissing, "remove operation failed to decode path") - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "remove operation does not apply: doc is missing path: \"%s\"", path) - } - - err = con.remove(key) - if err != nil { - return errors.Wrapf(err, "error in remove for path: '%s'", path) - } - - return nil -} - -func (p Patch) replace(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(err, "replace operation failed to decode path") - } - - if path == "" { - val := op.value() - - if val.which == eRaw { - if !val.tryDoc() { - if !val.tryAry() { - return errors.Wrapf(err, "replace operation value must be object or array") - } - } - } - - switch val.which { - case eAry: - *doc = &val.ary - case eDoc: - *doc = &val.doc - case eRaw: - return errors.Wrapf(err, "replace operation hit impossible case") - } - - return nil - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing path: %s", path) - } - - _, ok := con.get(key) - if ok != nil { - return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing key: %s", path) - } - - err = con.set(key, op.value()) - if err != nil { - return errors.Wrapf(err, "error in remove for path: '%s'", path) - } - - return nil -} - -func (p Patch) move(doc *container, op Operation) error { - from, err := op.From() - if err != nil { - return errors.Wrapf(err, "move operation failed to decode from") - } - - con, key := findObject(doc, from) - - if con == nil { - return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing from path: %s", from) - } - - val, err := con.get(key) - if err != nil { - return errors.Wrapf(err, "error in move for path: '%s'", key) - } - - err = con.remove(key) - if err != nil { - return errors.Wrapf(err, "error in move for path: '%s'", key) - } - - path, err := op.Path() - if err != nil { - return errors.Wrapf(err, "move operation failed to decode path") - } - - con, key = findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing destination path: %s", path) - } - - err = con.add(key, val) - if err != nil { - return errors.Wrapf(err, "error in move for path: '%s'", path) - } - - return nil -} - -func (p Patch) test(doc *container, op Operation) error { - path, err := op.Path() - if err != nil { - return errors.Wrapf(err, "test operation failed to decode path") - } - - if path == "" { - var self lazyNode - - switch sv := (*doc).(type) { - case *partialDoc: - self.doc = *sv - self.which = eDoc - case *partialArray: - self.ary = *sv - self.which = eAry - } - - if self.equal(op.value()) { - return nil - } - - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) - } - - con, key := findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "test operation does not apply: is missing path: %s", path) - } - - val, err := con.get(key) - if err != nil { - return errors.Wrapf(err, "error in test for path: '%s'", path) - } - - if val == nil { - if op.value() == nil || op.value().raw == nil { - return nil - } - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) - } else if op.value() == nil { - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) - } - - if val.equal(op.value()) { - return nil - } - - return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) -} - -func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) error { - from, err := op.From() - if err != nil { - return errors.Wrapf(err, "copy operation failed to decode from") - } - - con, key := findObject(doc, from) - - if con == nil { - return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing from path: %s", from) - } - - val, err := con.get(key) - if err != nil { - return errors.Wrapf(err, "error in copy for from: '%s'", from) - } - - path, err := op.Path() - if err != nil { - return errors.Wrapf(ErrMissing, "copy operation failed to decode path") - } - - con, key = findObject(doc, path) - - if con == nil { - return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing destination path: %s", path) - } - - valCopy, sz, err := deepCopy(val) - if err != nil { - return errors.Wrapf(err, "error while performing deep copy") - } - - (*accumulatedCopySize) += int64(sz) - if AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > AccumulatedCopySizeLimit { - return NewAccumulatedCopySizeError(AccumulatedCopySizeLimit, *accumulatedCopySize) - } - - err = con.add(key, valCopy) - if err != nil { - return errors.Wrapf(err, "error while adding value during copy") - } - - return nil -} - -// Equal indicates if 2 JSON documents have the same structural equality. -func Equal(a, b []byte) bool { - ra := make(json.RawMessage, len(a)) - copy(ra, a) - la := newLazyNode(&ra) - - rb := make(json.RawMessage, len(b)) - copy(rb, b) - lb := newLazyNode(&rb) - - return la.equal(lb) -} - -// DecodePatch decodes the passed JSON document as an RFC 6902 patch. -func DecodePatch(buf []byte) (Patch, error) { - var p Patch - - err := json.Unmarshal(buf, &p) - - if err != nil { - return nil, err - } - - return p, nil -} - -// Apply mutates a JSON document according to the patch, and returns the new -// document. -func (p Patch) Apply(doc []byte) ([]byte, error) { - return p.ApplyIndent(doc, "") -} - -// ApplyIndent mutates a JSON document according to the patch, and returns the new -// document indented. -func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) { - if len(doc) == 0 { - return doc, nil - } - - var pd container - if doc[0] == '[' { - pd = &partialArray{} - } else { - pd = &partialDoc{} - } - - err := json.Unmarshal(doc, pd) - - if err != nil { - return nil, err - } - - err = nil - - var accumulatedCopySize int64 - - for _, op := range p { - switch op.Kind() { - case "add": - err = p.add(&pd, op) - case "remove": - err = p.remove(&pd, op) - case "replace": - err = p.replace(&pd, op) - case "move": - err = p.move(&pd, op) - case "test": - err = p.test(&pd, op) - case "copy": - err = p.copy(&pd, op, &accumulatedCopySize) - default: - err = fmt.Errorf("Unexpected kind: %s", op.Kind()) - } - - if err != nil { - return nil, err - } - } - - if indent != "" { - return json.MarshalIndent(pd, "", indent) - } - - return json.Marshal(pd) -} - -// From http://tools.ietf.org/html/rfc6901#section-4 : -// -// Evaluation of each reference token begins by decoding any escaped -// character sequence. This is performed by first transforming any -// occurrence of the sequence '~1' to '/', and then transforming any -// occurrence of the sequence '~0' to '~'. - -var ( - rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~") -) - -func decodePatchKey(k string) string { - return rfc6901Decoder.Replace(k) -} diff --git a/tests/vendor/k8s.io/cli-runtime/pkg/genericclioptions/builder_flags_fake.go b/tests/vendor/k8s.io/cli-runtime/pkg/genericclioptions/builder_flags_fake.go index d43b0c25e..adc496feb 100644 --- a/tests/vendor/k8s.io/cli-runtime/pkg/genericclioptions/builder_flags_fake.go +++ b/tests/vendor/k8s.io/cli-runtime/pkg/genericclioptions/builder_flags_fake.go @@ -21,29 +21,40 @@ import ( ) // NewSimpleFakeResourceFinder builds a super simple ResourceFinder that just iterates over the objects you provided -func NewSimpleFakeResourceFinder(infos ...*resource.Info) ResourceFinder { - return &fakeResourceFinder{ +func NewSimpleFakeResourceFinder(infos ...*resource.Info) *FakeResourceFinder { + return &FakeResourceFinder{ Infos: infos, } } -type fakeResourceFinder struct { +func (f *FakeResourceFinder) WithError(err error) *FakeResourceFinder { + f.err = err + return f +} + +type FakeResourceFinder struct { Infos []*resource.Info + err error } // Do implements the interface -func (f *fakeResourceFinder) Do() resource.Visitor { +func (f *FakeResourceFinder) Do() resource.Visitor { return &fakeResourceResult{ Infos: f.Infos, + err: f.err, } } type fakeResourceResult struct { Infos []*resource.Info + err error } // Visit just iterates over info func (r *fakeResourceResult) Visit(fn resource.VisitorFunc) error { + if r.err != nil { + return r.err + } for _, info := range r.Infos { err := fn(info, nil) if err != nil { diff --git a/tests/vendor/k8s.io/cli-runtime/pkg/genericclioptions/record_flags.go b/tests/vendor/k8s.io/cli-runtime/pkg/genericclioptions/record_flags.go index a5f307de5..e3cee3473 100644 --- a/tests/vendor/k8s.io/cli-runtime/pkg/genericclioptions/record_flags.go +++ b/tests/vendor/k8s.io/cli-runtime/pkg/genericclioptions/record_flags.go @@ -21,9 +21,9 @@ import ( "path/filepath" "strings" - jsonpatch "github.com/evanphx/json-patch" "github.com/spf13/cobra" "github.com/spf13/pflag" + jsonpatch "gopkg.in/evanphx/json-patch.v4" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" diff --git a/tests/vendor/k8s.io/cli-runtime/pkg/printers/json.go b/tests/vendor/k8s.io/cli-runtime/pkg/printers/json.go index 8ab2235f8..7d14a4e5a 100644 --- a/tests/vendor/k8s.io/cli-runtime/pkg/printers/json.go +++ b/tests/vendor/k8s.io/cli-runtime/pkg/printers/json.go @@ -19,6 +19,7 @@ package printers import ( "bytes" "encoding/json" + "errors" "fmt" "io" "reflect" @@ -36,13 +37,13 @@ func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error { // we need an actual value in order to retrieve the package path for an object. // using reflect.Indirect indiscriminately is valid here, as all runtime.Objects are supposed to be pointers. if InternalObjectPreventer.IsForbidden(reflect.Indirect(reflect.ValueOf(obj)).Type().PkgPath()) { - return fmt.Errorf(InternalObjectPrinterErr) + return errors.New(InternalObjectPrinterErr) } switch obj := obj.(type) { case *metav1.WatchEvent: if InternalObjectPreventer.IsForbidden(reflect.Indirect(reflect.ValueOf(obj.Object.Object)).Type().PkgPath()) { - return fmt.Errorf(InternalObjectPrinterErr) + return errors.New(InternalObjectPrinterErr) } data, err := json.Marshal(obj) if err != nil { diff --git a/tests/vendor/k8s.io/cli-runtime/pkg/printers/jsonpath.go b/tests/vendor/k8s.io/cli-runtime/pkg/printers/jsonpath.go index 769960d66..216449ec4 100644 --- a/tests/vendor/k8s.io/cli-runtime/pkg/printers/jsonpath.go +++ b/tests/vendor/k8s.io/cli-runtime/pkg/printers/jsonpath.go @@ -19,6 +19,7 @@ package printers import ( "bytes" "encoding/json" + "errors" "fmt" "io" "reflect" @@ -119,7 +120,7 @@ func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error { // we need an actual value in order to retrieve the package path for an object. // using reflect.Indirect indiscriminately is valid here, as all runtime.Objects are supposed to be pointers. if InternalObjectPreventer.IsForbidden(reflect.Indirect(reflect.ValueOf(obj)).Type().PkgPath()) { - return fmt.Errorf(InternalObjectPrinterErr) + return errors.New(InternalObjectPrinterErr) } var queryObj interface{} = obj diff --git a/tests/vendor/k8s.io/cli-runtime/pkg/printers/name.go b/tests/vendor/k8s.io/cli-runtime/pkg/printers/name.go index 086166af2..1d2fe7f96 100644 --- a/tests/vendor/k8s.io/cli-runtime/pkg/printers/name.go +++ b/tests/vendor/k8s.io/cli-runtime/pkg/printers/name.go @@ -17,6 +17,7 @@ limitations under the License. package printers import ( + "errors" "fmt" "io" "reflect" @@ -52,7 +53,7 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error { // using reflect.Indirect indiscriminately is valid here, as all runtime.Objects are supposed to be pointers. // we need an actual value in order to retrieve the package path for an object. if InternalObjectPreventer.IsForbidden(reflect.Indirect(reflect.ValueOf(obj)).Type().PkgPath()) { - return fmt.Errorf(InternalObjectPrinterErr) + return errors.New(InternalObjectPrinterErr) } if meta.IsListType(obj) { diff --git a/tests/vendor/k8s.io/cli-runtime/pkg/printers/template.go b/tests/vendor/k8s.io/cli-runtime/pkg/printers/template.go index ccff54226..4b08573ce 100644 --- a/tests/vendor/k8s.io/cli-runtime/pkg/printers/template.go +++ b/tests/vendor/k8s.io/cli-runtime/pkg/printers/template.go @@ -18,6 +18,7 @@ package printers import ( "encoding/base64" + "errors" "fmt" "io" "reflect" @@ -61,7 +62,7 @@ func (p *GoTemplatePrinter) AllowMissingKeys(allow bool) { // PrintObj formats the obj with the Go Template. func (p *GoTemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error { if InternalObjectPreventer.IsForbidden(reflect.Indirect(reflect.ValueOf(obj)).Type().PkgPath()) { - return fmt.Errorf(InternalObjectPrinterErr) + return errors.New(InternalObjectPrinterErr) } var data []byte diff --git a/tests/vendor/k8s.io/cli-runtime/pkg/printers/yaml.go b/tests/vendor/k8s.io/cli-runtime/pkg/printers/yaml.go index 9c444bdc2..8c6be82fe 100644 --- a/tests/vendor/k8s.io/cli-runtime/pkg/printers/yaml.go +++ b/tests/vendor/k8s.io/cli-runtime/pkg/printers/yaml.go @@ -17,6 +17,7 @@ limitations under the License. package printers import ( + "errors" "fmt" "io" "reflect" @@ -42,7 +43,7 @@ func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error { // we need an actual value in order to retrieve the package path for an object. // using reflect.Indirect indiscriminately is valid here, as all runtime.Objects are supposed to be pointers. if InternalObjectPreventer.IsForbidden(reflect.Indirect(reflect.ValueOf(obj)).Type().PkgPath()) { - return fmt.Errorf(InternalObjectPrinterErr) + return errors.New(InternalObjectPrinterErr) } count := atomic.AddInt64(&p.printCount, 1) @@ -55,7 +56,7 @@ func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error { switch obj := obj.(type) { case *metav1.WatchEvent: if InternalObjectPreventer.IsForbidden(reflect.Indirect(reflect.ValueOf(obj.Object.Object)).Type().PkgPath()) { - return fmt.Errorf(InternalObjectPrinterErr) + return errors.New(InternalObjectPrinterErr) } data, err := yaml.Marshal(obj) if err != nil { diff --git a/tests/vendor/k8s.io/cli-runtime/pkg/resource/builder.go b/tests/vendor/k8s.io/cli-runtime/pkg/resource/builder.go index 47ec83bbb..5f8fdcd9b 100644 --- a/tests/vendor/k8s.io/cli-runtime/pkg/resource/builder.go +++ b/tests/vendor/k8s.io/cli-runtime/pkg/resource/builder.go @@ -1030,7 +1030,7 @@ func (b *Builder) visitByResource() *Result { if b.allNamespace { errMsg = "a resource cannot be retrieved by name across all namespaces" } - return result.withError(fmt.Errorf(errMsg)) + return result.withError(errors.New(errMsg)) } } @@ -1093,7 +1093,7 @@ func (b *Builder) visitByName() *Result { if b.allNamespace { errMsg = "a resource cannot be retrieved by name across all namespaces" } - return result.withError(fmt.Errorf(errMsg)) + return result.withError(errors.New(errMsg)) } } diff --git a/tests/vendor/k8s.io/cli-runtime/pkg/resource/query_param_verifier.go b/tests/vendor/k8s.io/cli-runtime/pkg/resource/query_param_verifier.go index b9000a08a..15db8e43d 100644 --- a/tests/vendor/k8s.io/cli-runtime/pkg/resource/query_param_verifier.go +++ b/tests/vendor/k8s.io/cli-runtime/pkg/resource/query_param_verifier.go @@ -21,11 +21,11 @@ import ( "fmt" openapi_v2 "github.com/google/gnostic-models/openapiv2" - yaml "gopkg.in/yaml.v2" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" + yaml "sigs.k8s.io/yaml/goyaml.v2" ) func NewQueryParamVerifier(dynamicClient dynamic.Interface, openAPIGetter discovery.OpenAPISchemaInterface, queryParam VerifiableQueryParam) *QueryParamVerifier { diff --git a/tests/vendor/k8s.io/kubectl/pkg/cmd/util/helpers.go b/tests/vendor/k8s.io/kubectl/pkg/cmd/util/helpers.go index 2218b9f5b..653aa7840 100644 --- a/tests/vendor/k8s.io/kubectl/pkg/cmd/util/helpers.go +++ b/tests/vendor/k8s.io/kubectl/pkg/cmd/util/helpers.go @@ -27,9 +27,9 @@ import ( "strings" "time" - jsonpatch "github.com/evanphx/json-patch" "github.com/spf13/cobra" "github.com/spf13/pflag" + jsonpatch "gopkg.in/evanphx/json-patch.v4" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -243,7 +243,7 @@ func statusCausesToAggrError(scs []metav1.StatusCause) utilerrors.Aggregate { // commands. func StandardErrorMessage(err error) (string, bool) { if debugErr, ok := err.(debugError); ok { - klog.V(4).Infof(debugErr.DebugError()) + klog.V(4).Info(debugErr.DebugError()) } status, isStatus := err.(apierrors.APIStatus) switch { @@ -430,7 +430,8 @@ const ( OpenAPIV3Patch FeatureGate = "KUBECTL_OPENAPIV3_PATCH" RemoteCommandWebsockets FeatureGate = "KUBECTL_REMOTE_COMMAND_WEBSOCKETS" PortForwardWebsockets FeatureGate = "KUBECTL_PORT_FORWARD_WEBSOCKETS" - DebugCustomProfile FeatureGate = "KUBECTL_DEBUG_CUSTOM_PROFILE" + // DebugCustomProfile should be dropped in 1.34 + DebugCustomProfile FeatureGate = "KUBECTL_DEBUG_CUSTOM_PROFILE" ) // IsEnabled returns true iff environment variable is set to true. @@ -451,10 +452,7 @@ func AddValidateFlags(cmd *cobra.Command) { cmd.Flags().String( "validate", "strict", - `Must be one of: strict (or true), warn, ignore (or false). - "true" or "strict" will use a schema to validate the input and fail the request if invalid. It will perform server side validation if ServerSideFieldValidation is enabled on the api-server, but will fall back to less reliable client-side validation if not. - "warn" will warn about unknown or duplicate fields without blocking the request if server-side field validation is enabled on the API server, and behave as "ignore" otherwise. - "false" or "ignore" will not perform any schema validation, silently dropping any unknown or duplicate fields.`, + `Must be one of: strict (or true), warn, ignore (or false). "true" or "strict" will use a schema to validate the input and fail the request if invalid. It will perform server side validation if ServerSideFieldValidation is enabled on the api-server, but will fall back to less reliable client-side validation if not. "warn" will warn about unknown or duplicate fields without blocking the request if server-side field validation is enabled on the API server, and behave as "ignore" otherwise. "false" or "ignore" will not perform any schema validation, silently dropping any unknown or duplicate fields.`, ) cmd.Flags().Lookup("validate").NoOptDefVal = "strict" @@ -539,10 +537,11 @@ func AddPruningFlags(cmd *cobra.Command, prune *bool, pruneAllowlist *[]string, } } -func AddSubresourceFlags(cmd *cobra.Command, subresource *string, usage string, allowedSubresources ...string) { - cmd.Flags().StringVar(subresource, "subresource", "", fmt.Sprintf("%s Must be one of %v. This flag is beta and may change in the future.", usage, allowedSubresources)) +func AddSubresourceFlags(cmd *cobra.Command, subresource *string, usage string) { + cmd.Flags().StringVar(subresource, "subresource", "", fmt.Sprintf("%s This flag is beta and may change in the future.", usage)) CheckErr(cmd.RegisterFlagCompletionFunc("subresource", func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) { - return allowedSubresources, cobra.ShellCompDirectiveNoFileComp + var commonSubresources = []string{"status", "scale", "resize"} + return commonSubresources, cobra.ShellCompDirectiveNoFileComp })) } diff --git a/tests/vendor/k8s.io/kubectl/pkg/util/i18n/translations/README.md b/tests/vendor/k8s.io/kubectl/pkg/util/i18n/translations/README.md index 6318ffe62..a97180466 100644 --- a/tests/vendor/k8s.io/kubectl/pkg/util/i18n/translations/README.md +++ b/tests/vendor/k8s.io/kubectl/pkg/util/i18n/translations/README.md @@ -72,7 +72,7 @@ import pkg/i18n translated := i18n.T("Your message in english here") // Get a translated plural string -translated := i18n.T("You had % items", items) +translated := i18n.T("You had %d items", items) // Translated error return i18n.Error("Something bad happened") diff --git a/tests/vendor/k8s.io/kubectl/pkg/util/i18n/translations/kubectl/ja_JP/LC_MESSAGES/k8s.po b/tests/vendor/k8s.io/kubectl/pkg/util/i18n/translations/kubectl/ja_JP/LC_MESSAGES/k8s.po index 7036ad59a..f7280b4fe 100644 --- a/tests/vendor/k8s.io/kubectl/pkg/util/i18n/translations/kubectl/ja_JP/LC_MESSAGES/k8s.po +++ b/tests/vendor/k8s.io/kubectl/pkg/util/i18n/translations/kubectl/ja_JP/LC_MESSAGES/k8s.po @@ -432,7 +432,7 @@ msgstr "Create a service account with the specified name" # https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/config/delete_cluster.go#L38 #: staging/src/k8s.io/kubectl/pkg/cmd/config/delete_cluster.go:42 msgid "Delete the specified cluster from the kubeconfig" -msgstr "指定したコンテキストをkubeconfigから削除する" +msgstr "指定したクラスターをkubeconfigから削除する" # https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/config/delete_context.go#L38 #: staging/src/k8s.io/kubectl/pkg/cmd/config/delete_context.go:42 diff --git a/tests/vendor/k8s.io/kubectl/pkg/util/templates/help_flags_printer.go b/tests/vendor/k8s.io/kubectl/pkg/util/templates/help_flags_printer.go index fdfdf08ee..b7e1bf00f 100644 --- a/tests/vendor/k8s.io/kubectl/pkg/util/templates/help_flags_printer.go +++ b/tests/vendor/k8s.io/kubectl/pkg/util/templates/help_flags_printer.go @@ -62,7 +62,7 @@ func (p *HelpFlagPrinter) PrintHelpFlag(flag *flag.Flag) { } appendTabStr := strings.ReplaceAll(wrappedStr, "\n", "\n\t") - fmt.Fprintf(p.out, appendTabStr+"\n\n") + fmt.Fprint(p.out, appendTabStr+"\n\n") } // writeFlag will output the help flag based diff --git a/tests/vendor/modules.txt b/tests/vendor/modules.txt index 730d1e9ba..f8cc68ca2 100644 --- a/tests/vendor/modules.txt +++ b/tests/vendor/modules.txt @@ -104,6 +104,9 @@ github.com/aws/aws-sdk-go/service/sts/stsiface # github.com/beorn7/perks v1.0.1 ## explicit; go 1.11 github.com/beorn7/perks/quantile +# github.com/blang/semver/v4 v4.0.0 +## explicit; go 1.14 +github.com/blang/semver/v4 # github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc ## explicit github.com/boombuler/barcode @@ -145,13 +148,13 @@ github.com/containerd/log # github.com/cpuguy83/go-md2man/v2 v2.0.4 ## explicit; go 1.11 github.com/cpuguy83/go-md2man/v2/md2man -# github.com/cyphar/filepath-securejoin v0.2.4 -## explicit; go 1.13 +# github.com/cyphar/filepath-securejoin v0.3.5 +## explicit; go 1.21 github.com/cyphar/filepath-securejoin # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew -# github.com/distribution/reference v0.5.0 +# github.com/distribution/reference v0.6.0 ## explicit; go 1.20 github.com/distribution/reference # github.com/docker/cli v25.0.1+incompatible @@ -507,7 +510,7 @@ github.com/onsi/gomega/types # github.com/opencontainers/go-digest v1.0.0 ## explicit; go 1.13 github.com/opencontainers/go-digest -# github.com/opencontainers/image-spec v1.1.0-rc6 +# github.com/opencontainers/image-spec v1.1.0 ## explicit; go 1.18 github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 @@ -604,8 +607,8 @@ github.com/xlab/treeprint go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconv go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/semconvutil -# go.opentelemetry.io/otel v1.28.0 -## explicit; go 1.21 +# go.opentelemetry.io/otel v1.31.0 +## explicit; go 1.22 go.opentelemetry.io/otel go.opentelemetry.io/otel/attribute go.opentelemetry.io/otel/baggage @@ -618,22 +621,14 @@ go.opentelemetry.io/otel/propagation go.opentelemetry.io/otel/semconv/v1.20.0 go.opentelemetry.io/otel/semconv/v1.21.0 go.opentelemetry.io/otel/semconv/v1.24.0 -# go.opentelemetry.io/otel/metric v1.28.0 -## explicit; go 1.21 +# go.opentelemetry.io/otel/metric v1.31.0 +## explicit; go 1.22 go.opentelemetry.io/otel/metric go.opentelemetry.io/otel/metric/embedded -# go.opentelemetry.io/otel/trace v1.28.0 -## explicit; go 1.21 +# go.opentelemetry.io/otel/trace v1.31.0 +## explicit; go 1.22 go.opentelemetry.io/otel/trace go.opentelemetry.io/otel/trace/embedded -# go.starlark.net v0.0.0-20231121155337-90ade8b19d09 -## explicit; go 1.18 -go.starlark.net/internal/compile -go.starlark.net/internal/spell -go.starlark.net/resolve -go.starlark.net/starlark -go.starlark.net/starlarkstruct -go.starlark.net/syntax # golang.org/x/crypto v0.31.0 ## explicit; go 1.20 golang.org/x/crypto/bcrypt @@ -712,23 +707,23 @@ golang.org/x/text/secure/bidirule golang.org/x/text/transform golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm -# golang.org/x/time v0.7.0 +# golang.org/x/time v0.8.0 ## explicit; go 1.18 golang.org/x/time/rate # golang.org/x/tools v0.28.0 ## explicit; go 1.22.0 golang.org/x/tools/cover golang.org/x/tools/go/ast/inspector -# google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 +# google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 ## explicit; go 1.21 google.golang.org/genproto/googleapis/rpc/status -# google.golang.org/grpc v1.65.0 -## explicit; go 1.21 +# google.golang.org/grpc v1.69.0 +## explicit; go 1.22 google.golang.org/grpc/codes google.golang.org/grpc/connectivity google.golang.org/grpc/grpclog +google.golang.org/grpc/grpclog/internal google.golang.org/grpc/internal -google.golang.org/grpc/internal/grpclog google.golang.org/grpc/internal/status google.golang.org/grpc/serviceconfig google.golang.org/grpc/status @@ -773,9 +768,6 @@ google.golang.org/protobuf/types/known/timestamppb # gopkg.in/evanphx/json-patch.v4 v4.12.0 ## explicit gopkg.in/evanphx/json-patch.v4 -# gopkg.in/evanphx/json-patch.v5 v5.7.0 -## explicit -gopkg.in/evanphx/json-patch.v5 # gopkg.in/inf.v0 v0.9.1 ## explicit gopkg.in/inf.v0 @@ -825,7 +817,7 @@ helm.sh/helm/v3/pkg/strvals helm.sh/helm/v3/pkg/time helm.sh/helm/v3/pkg/time/ctime helm.sh/helm/v3/pkg/uploader -# k8s.io/api v0.32.1 +# k8s.io/api v0.32.2 ## explicit; go 1.23.0 k8s.io/api/admission/v1 k8s.io/api/admission/v1beta1 @@ -886,7 +878,7 @@ k8s.io/api/storage/v1 k8s.io/api/storage/v1alpha1 k8s.io/api/storage/v1beta1 k8s.io/api/storagemigration/v1alpha1 -# k8s.io/apiextensions-apiserver v0.32.1 +# k8s.io/apiextensions-apiserver v0.32.2 ## explicit; go 1.23.0 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 @@ -897,7 +889,7 @@ k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1 k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1 -# k8s.io/apimachinery v0.32.1 +# k8s.io/apimachinery v0.32.2 ## explicit; go 1.23.0 k8s.io/apimachinery/pkg/api/equality k8s.io/apimachinery/pkg/api/errors @@ -964,16 +956,16 @@ k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/third_party/forked/golang/json k8s.io/apimachinery/third_party/forked/golang/netutil k8s.io/apimachinery/third_party/forked/golang/reflect -# k8s.io/apiserver v0.32.1 +# k8s.io/apiserver v0.32.2 ## explicit; go 1.23.0 k8s.io/apiserver/pkg/endpoints/deprecation -# k8s.io/cli-runtime v0.30.3 -## explicit; go 1.22.0 +# k8s.io/cli-runtime v0.32.2 +## explicit; go 1.23.0 k8s.io/cli-runtime/pkg/genericclioptions k8s.io/cli-runtime/pkg/genericiooptions k8s.io/cli-runtime/pkg/printers k8s.io/cli-runtime/pkg/resource -# k8s.io/client-go v0.32.1 +# k8s.io/client-go v0.32.2 ## explicit; go 1.23.0 k8s.io/client-go/applyconfigurations/admissionregistration/v1 k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1 @@ -1138,7 +1130,7 @@ k8s.io/client-go/util/jsonpath k8s.io/client-go/util/keyutil k8s.io/client-go/util/watchlist k8s.io/client-go/util/workqueue -# k8s.io/component-base v0.32.1 +# k8s.io/component-base v0.32.2 ## explicit; go 1.23.0 k8s.io/component-base/version # k8s.io/klog/v2 v2.130.1 @@ -1162,8 +1154,8 @@ k8s.io/kube-openapi/pkg/spec3 k8s.io/kube-openapi/pkg/util/proto k8s.io/kube-openapi/pkg/util/proto/validation k8s.io/kube-openapi/pkg/validation/spec -# k8s.io/kubectl v0.30.3 -## explicit; go 1.22.0 +# k8s.io/kubectl v0.32.2 +## explicit; go 1.23.0 k8s.io/kubectl/pkg/cmd/util k8s.io/kubectl/pkg/scheme k8s.io/kubectl/pkg/util/i18n @@ -1201,8 +1193,8 @@ oras.land/oras-go/pkg/target ## explicit; go 1.21 sigs.k8s.io/json sigs.k8s.io/json/internal/golang/encoding/json -# sigs.k8s.io/kustomize/api v0.16.0 -## explicit; go 1.20 +# sigs.k8s.io/kustomize/api v0.18.0 +## explicit; go 1.22.7 sigs.k8s.io/kustomize/api/filters/annotations sigs.k8s.io/kustomize/api/filters/fieldspec sigs.k8s.io/kustomize/api/filters/filtersutil @@ -1247,8 +1239,8 @@ sigs.k8s.io/kustomize/api/provider sigs.k8s.io/kustomize/api/resmap sigs.k8s.io/kustomize/api/resource sigs.k8s.io/kustomize/api/types -# sigs.k8s.io/kustomize/kyaml v0.16.0 -## explicit; go 1.20 +# sigs.k8s.io/kustomize/kyaml v0.18.1 +## explicit; go 1.22.7 sigs.k8s.io/kustomize/kyaml/comments sigs.k8s.io/kustomize/kyaml/errors sigs.k8s.io/kustomize/kyaml/ext @@ -1257,10 +1249,7 @@ sigs.k8s.io/kustomize/kyaml/filesys sigs.k8s.io/kustomize/kyaml/fn/runtime/container sigs.k8s.io/kustomize/kyaml/fn/runtime/exec sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil -sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark -sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util sigs.k8s.io/kustomize/kyaml/kio -sigs.k8s.io/kustomize/kyaml/kio/filters sigs.k8s.io/kustomize/kyaml/kio/kioutil sigs.k8s.io/kustomize/kyaml/openapi sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi @@ -1280,11 +1269,10 @@ sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/sets sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/pkg/util/validation/field sigs.k8s.io/kustomize/kyaml/yaml/merge2 -sigs.k8s.io/kustomize/kyaml/yaml/merge3 sigs.k8s.io/kustomize/kyaml/yaml/schema sigs.k8s.io/kustomize/kyaml/yaml/walk -# sigs.k8s.io/node-feature-discovery v0.16.6 -## explicit; go 1.22.2 +# sigs.k8s.io/node-feature-discovery v0.17.2 +## explicit; go 1.23.0 sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/scheme sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1 diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go b/tests/vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go index 4815f10a2..ff83420cb 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go @@ -284,9 +284,9 @@ func (f Filter) roleRefFilter() sieveFunc { return previousIdSelectedByGvk(roleRefGvk) } -func prefixSuffixEquals(other resource.ResCtx) sieveFunc { +func prefixSuffixEquals(other resource.ResCtx, allowEmpty bool) sieveFunc { return func(r *resource.Resource) bool { - return r.PrefixesSuffixesEquals(other) + return r.PrefixesSuffixesEquals(other, allowEmpty) } } @@ -325,7 +325,10 @@ func (f Filter) selectReferral( if len(candidates) == 1 { return candidates[0], nil } - candidates = doSieve(candidates, prefixSuffixEquals(f.Referrer)) + candidates = doSieve(candidates, prefixSuffixEquals(f.Referrer, true)) + if len(candidates) > 1 { + candidates = doSieve(candidates, prefixSuffixEquals(f.Referrer, false)) + } if len(candidates) == 1 { return candidates[0], nil } diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/filters/patchjson6902/patchjson6902.go b/tests/vendor/sigs.k8s.io/kustomize/api/filters/patchjson6902/patchjson6902.go index d41859465..671567d9a 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/filters/patchjson6902/patchjson6902.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/filters/patchjson6902/patchjson6902.go @@ -6,7 +6,7 @@ package patchjson6902 import ( "strings" - jsonpatch "gopkg.in/evanphx/json-patch.v5" + jsonpatch "gopkg.in/evanphx/json-patch.v4" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/yaml" k8syaml "sigs.k8s.io/yaml" diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go index afe6da2e7..f60c517b7 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go @@ -144,7 +144,7 @@ func loadCrdIntoConfig( } _, label := property.Extensions.GetString(xLabelSelector) if label { - err = theConfig.AddLabelFieldSpec( + err = theConfig.AddCommonLabelsFieldSpec( makeFs(theGvk, append(path, propName))) if err != nil { return diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/HelmChartInflationGenerator.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/HelmChartInflationGenerator.go index d0380f0c5..06d13b526 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/HelmChartInflationGenerator.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/HelmChartInflationGenerator.go @@ -10,13 +10,15 @@ import ( "os/exec" "path/filepath" "regexp" + "slices" "strings" - "github.com/imdario/mergo" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/kio" + kyaml "sigs.k8s.io/kustomize/kyaml/yaml" + "sigs.k8s.io/kustomize/kyaml/yaml/merge2" "sigs.k8s.io/yaml" ) @@ -61,6 +63,9 @@ func (p *HelmChartInflationGeneratorPlugin) Config( if len(h.GeneralConfig().HelmConfig.ApiVersions) != 0 { p.HelmChart.ApiVersions = h.GeneralConfig().HelmConfig.ApiVersions } + if h.GeneralConfig().HelmConfig.Debug { + p.HelmChart.Debug = h.GeneralConfig().HelmConfig.Debug + } p.h = h if err = yaml.Unmarshal(config, p); err != nil { @@ -167,13 +172,17 @@ func (p *HelmChartInflationGeneratorPlugin) runHelmCommand( fmt.Sprintf("HELM_DATA_HOME=%s/.data", p.ConfigHome)} cmd.Env = append(os.Environ(), env...) err := cmd.Run() + errorOutput := stderr.String() + if slices.Contains(args, "--debug") { + errorOutput = " Helm stack trace:\n" + errorOutput + "\nHelm template:\n" + stdout.String() + "\n" + } if err != nil { helm := p.h.GeneralConfig().HelmConfig.Command err = errors.WrapPrefixf( fmt.Errorf( "unable to run: '%s %s' with env=%s (is '%s' installed?): %w", helm, strings.Join(args, " "), env, helm, err), - stderr.String(), + errorOutput, ) } return stdout.Bytes(), err @@ -201,18 +210,33 @@ func (p *HelmChartInflationGeneratorPlugin) replaceValuesInline() error { if err != nil { return err } - chValues := make(map[string]interface{}) - if err = yaml.Unmarshal(pValues, &chValues); err != nil { - return err + chValues, err := kyaml.Parse(string(pValues)) + if err != nil { + return errors.WrapPrefixf(err, "could not parse values file into rnode") + } + inlineValues, err := kyaml.FromMap(p.ValuesInline) + if err != nil { + return errors.WrapPrefixf(err, "could not parse values inline into rnode") } + var outValues *kyaml.RNode switch p.ValuesMerge { + // Function `merge2.Merge` overrides values in dest with values from src. + // To achieve override or merge behavior, we pass parameters in different order. + // Object passed as dest will be modified, so we copy it just in case someone + // decides to use it after this is called. case valuesMergeOptionOverride: - err = mergo.Merge( - &chValues, p.ValuesInline, mergo.WithOverride) + outValues, err = merge2.Merge(inlineValues, chValues.Copy(), kyaml.MergeOptions{}) case valuesMergeOptionMerge: - err = mergo.Merge(&chValues, p.ValuesInline) + outValues, err = merge2.Merge(chValues, inlineValues.Copy(), kyaml.MergeOptions{}) + } + if err != nil { + return errors.WrapPrefixf(err, "could not merge values") + } + mapValues, err := outValues.Map() + if err != nil { + return errors.WrapPrefixf(err, "could not parse merged values into map") } - p.ValuesInline = chValues + p.ValuesInline = mapValues return err } diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchJson6902Transformer.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchJson6902Transformer.go index d704dff0f..04625e510 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchJson6902Transformer.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchJson6902Transformer.go @@ -6,7 +6,7 @@ package builtins import ( "fmt" - jsonpatch "gopkg.in/evanphx/json-patch.v5" + jsonpatch "gopkg.in/evanphx/json-patch.v4" "sigs.k8s.io/kustomize/api/filters/patchjson6902" "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/resmap" diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchTransformer.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchTransformer.go index 86ee28728..8e6eb4112 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchTransformer.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchTransformer.go @@ -7,7 +7,7 @@ import ( "fmt" "strings" - jsonpatch "gopkg.in/evanphx/json-patch.v5" + jsonpatch "gopkg.in/evanphx/json-patch.v4" "sigs.k8s.io/kustomize/api/filters/patchjson6902" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resource" diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/SortOrderTransformer.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/SortOrderTransformer.go index 687f21a60..90e290719 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/SortOrderTransformer.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/builtins/SortOrderTransformer.go @@ -74,34 +74,16 @@ func (p *SortOrderTransformerPlugin) Transform(m resmap.ResMap) (err error) { // Sort if p.SortOptions.Order == types.LegacySortOrder { - s := newLegacyIDSorter(m.AllIds(), p.SortOptions.LegacySortOptions) + s := newLegacyIDSorter(m.Resources(), p.SortOptions.LegacySortOptions) sort.Sort(s) - err = applyOrdering(m, s.resids) - if err != nil { - return err - } - } - return nil -} -// applyOrdering takes resources (given in ResMap) and a desired ordering given -// as a sequence of ResIds, and updates the ResMap's resources to match the -// ordering. -func applyOrdering(m resmap.ResMap, ordering []resid.ResId) error { - var err error - resources := make([]*resource.Resource, m.Size()) - // Clear and refill with the correct order - for i, id := range ordering { - resources[i], err = m.GetByCurrentId(id) - if err != nil { - return errors.WrapPrefixf(err, "expected match for sorting") - } - } - m.Clear() - for _, r := range resources { - err = m.Append(r) - if err != nil { - return errors.WrapPrefixf(err, "SortOrderTransformer: Failed to append to resources") + // Clear the map and re-add the resources in the sorted order. + m.Clear() + for _, r := range s.resources { + err := m.Append(r) + if err != nil { + return errors.WrapPrefixf(err, "SortOrderTransformer: Failed to append to resources") + } } } return nil @@ -117,12 +99,17 @@ func applyOrdering(m resmap.ResMap, ordering []resid.ResId) error { type legacyIDSorter struct { // resids only stores the metadata of the object. This is an optimization as // it's expensive to compute these again and again during ordering. - resids []resid.ResId + resids []resid.ResId + // Initially, we sorted the metadata (ResId) of each object and then called GetByCurrentId on each to construct the final list. + // The problem is that GetByCurrentId is inefficient and does a linear scan in a list every time we do that. + // So instead, we sort resources alongside the ResIds. + resources []*resource.Resource + typeOrders map[string]int } func newLegacyIDSorter( - resids []resid.ResId, + resources []*resource.Resource, options *types.LegacySortOptions) *legacyIDSorter { // Precalculate a resource ranking based on the priority lists. var typeOrders = func() map[string]int { @@ -135,10 +122,13 @@ func newLegacyIDSorter( } return m }() - return &legacyIDSorter{ - resids: resids, - typeOrders: typeOrders, + + ret := &legacyIDSorter{typeOrders: typeOrders} + for _, res := range resources { + ret.resids = append(ret.resids, res.CurId()) + ret.resources = append(ret.resources, res) } + return ret } var _ sort.Interface = legacyIDSorter{} @@ -146,6 +136,7 @@ var _ sort.Interface = legacyIDSorter{} func (a legacyIDSorter) Len() int { return len(a.resids) } func (a legacyIDSorter) Swap(i, j int) { a.resids[i], a.resids[j] = a.resids[j], a.resids[i] + a.resources[i], a.resources[j] = a.resources[j], a.resources[i] } func (a legacyIDSorter) Less(i, j int) bool { if !a.resids[i].Gvk.Equals(a.resids[j].Gvk) { @@ -160,6 +151,9 @@ func gvkLessThan(gvk1, gvk2 resid.Gvk, typeOrders map[string]int) bool { if index1 != index2 { return index1 < index2 } + if (gvk1.Kind == types.NamespaceKind && gvk2.Kind == types.NamespaceKind) && (gvk1.Group == "" || gvk2.Group == "") { + return legacyGVKSortString(gvk1) > legacyGVKSortString(gvk2) + } return legacyGVKSortString(gvk1) < legacyGVKSortString(gvk2) } diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/konfig/builtinpluginconsts/namereference.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/konfig/builtinpluginconsts/namereference.go index 658b0c34b..383dcf83e 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/konfig/builtinpluginconsts/namereference.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/konfig/builtinpluginconsts/namereference.go @@ -421,6 +421,13 @@ nameReference: fieldSpecs: - path: spec/ingressClassName kind: Ingress + +- kind: ValidatingAdmissionPolicy + group: admissionregistration.k8s.io + fieldSpecs: + - path: spec/policyName + kind: ValidatingAdmissionPolicyBinding + group: admissionregistration.k8s.io ` ) diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/loaddefaultconfig.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/loaddefaultconfig.go index bf5e3f8a3..434941b6e 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/loaddefaultconfig.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/loaddefaultconfig.go @@ -33,7 +33,7 @@ func loadDefaultConfig( // makeTransformerConfigFromBytes returns a TransformerConfig object from bytes func makeTransformerConfigFromBytes(data []byte) (*TransformerConfig, error) { var t TransformerConfig - err := yaml.Unmarshal(data, &t) + err := yaml.UnmarshalStrict(data, &t) if err != nil { return nil, err } diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/transformerconfig.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/transformerconfig.go index ab847eb6e..c539c290d 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/transformerconfig.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig/transformerconfig.go @@ -21,6 +21,7 @@ type TransformerConfig struct { NameSuffix types.FsSlice `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"` NameSpace types.FsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"` CommonLabels types.FsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"` + Labels types.FsSlice `json:"labels,omitempty" yaml:"labels,omitempty"` TemplateLabels types.FsSlice `json:"templateLabels,omitempty" yaml:"templateLabels,omitempty"` CommonAnnotations types.FsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"` NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"` @@ -41,6 +42,7 @@ func (t *TransformerConfig) DeepCopy() *TransformerConfig { NameSuffix: t.NameSuffix.DeepCopy(), NameSpace: t.NameSpace.DeepCopy(), CommonLabels: t.CommonLabels.DeepCopy(), + Labels: t.Labels.DeepCopy(), TemplateLabels: t.TemplateLabels.DeepCopy(), CommonAnnotations: t.CommonAnnotations.DeepCopy(), NameReference: t.NameReference.DeepCopy(), @@ -94,6 +96,7 @@ func (t *TransformerConfig) sortFields() { sort.Sort(t.NameSuffix) sort.Sort(t.NameSpace) sort.Sort(t.CommonLabels) + sort.Sort(t.Labels) sort.Sort(t.TemplateLabels) sort.Sort(t.CommonAnnotations) sort.Sort(t.NameReference) @@ -114,12 +117,18 @@ func (t *TransformerConfig) AddSuffixFieldSpec(fs types.FieldSpec) (err error) { return err } -// AddLabelFieldSpec adds a FieldSpec to CommonLabels -func (t *TransformerConfig) AddLabelFieldSpec(fs types.FieldSpec) (err error) { +// AddCommonLabelsFieldSpec adds a FieldSpec to CommonLabels +func (t *TransformerConfig) AddCommonLabelsFieldSpec(fs types.FieldSpec) (err error) { t.CommonLabels, err = t.CommonLabels.MergeOne(fs) return err } +// AddLabelsFieldSpec adds a FieldSpec to Labels +func (t *TransformerConfig) AddLabelsFieldSpec(fs types.FieldSpec) (err error) { + t.Labels, err = t.Labels.MergeOne(fs) + return err //nolint:wrapcheck +} + // AddAnnotationFieldSpec adds a FieldSpec to CommonAnnotations func (t *TransformerConfig) AddAnnotationFieldSpec(fs types.FieldSpec) (err error) { t.CommonAnnotations, err = t.CommonAnnotations.MergeOne(fs) @@ -162,6 +171,10 @@ func (t *TransformerConfig) Merge(input *TransformerConfig) ( if err != nil { return nil, errors.WrapPrefixf(err, "failed to merge CommonLabels fieldSpec") } + merged.Labels, err = t.Labels.MergeAll(input.Labels) + if err != nil { + return nil, errors.WrapPrefixf(err, "failed to merge Labels fieldSpec") + } merged.TemplateLabels, err = t.TemplateLabels.MergeAll(input.TemplateLabels) if err != nil { return nil, errors.WrapPrefixf(err, "failed to merge TemplateLabels fieldSpec") diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/execplugin/execplugin.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/execplugin/execplugin.go index 001731f78..71c52884f 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/execplugin/execplugin.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/execplugin/execplugin.go @@ -6,6 +6,7 @@ package execplugin import ( "bytes" "fmt" + "log" "os" "os/exec" "runtime" @@ -21,6 +22,7 @@ import ( const ( tmpConfigFilePrefix = "kust-plugin-config-" + maxArgStringLength = 131071 ) // ExecPlugin record the name and args of an executable @@ -169,23 +171,35 @@ func (p *ExecPlugin) invokePlugin(input []byte) ([]byte, error) { p.path, append([]string{f.Name()}, p.args...)...) cmd.Env = p.getEnv() cmd.Stdin = bytes.NewReader(input) - cmd.Stderr = os.Stderr + var stdErr bytes.Buffer + cmd.Stderr = &stdErr if _, err := os.Stat(p.h.Loader().Root()); err == nil { cmd.Dir = p.h.Loader().Root() } result, err := cmd.Output() if err != nil { return nil, errors.WrapPrefixf( - err, "failure in plugin configured via %s; %v", - f.Name(), err.Error()) + fmt.Errorf("failure in plugin configured via %s; %w", + f.Name(), err), stdErr.String()) } return result, os.Remove(f.Name()) } func (p *ExecPlugin) getEnv() []string { env := os.Environ() - env = append(env, - "KUSTOMIZE_PLUGIN_CONFIG_STRING="+string(p.cfg), - "KUSTOMIZE_PLUGIN_CONFIG_ROOT="+p.h.Loader().Root()) + pluginConfigString := "KUSTOMIZE_PLUGIN_CONFIG_STRING=" + string(p.cfg) + if len(pluginConfigString) <= maxArgStringLength { + env = append(env, pluginConfigString) + } else { + log.Printf("KUSTOMIZE_PLUGIN_CONFIG_STRING exceeds hard limit of %d characters, the environment variable "+ + "will be omitted", maxArgStringLength) + } + pluginConfigRoot := "KUSTOMIZE_PLUGIN_CONFIG_ROOT=" + p.h.Loader().Root() + if len(pluginConfigRoot) <= maxArgStringLength { + env = append(env, pluginConfigRoot) + } else { + log.Printf("KUSTOMIZE_PLUGIN_CONFIG_ROOT exceeds hard limit of %d characters, the environment variable "+ + "will be omitted", maxArgStringLength) + } return env } diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/fnplugin/fnplugin.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/fnplugin/fnplugin.go index 3a033d727..0ec067562 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/fnplugin/fnplugin.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/fnplugin/fnplugin.go @@ -77,7 +77,6 @@ func NewFnPlugin(o *types.FnPluginLoadingOptions) *FnPlugin { runFns: runfn.RunFns{ Functions: []*yaml.RNode{}, Network: o.Network, - EnableStarlark: o.EnableStar, EnableExec: o.EnableExec, StorageMounts: toStorageMounts(o.Mounts), Env: o.Env, diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin.go new file mode 100644 index 000000000..3757cfc64 --- /dev/null +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin.go @@ -0,0 +1,62 @@ +// Copyright 2024 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 +//go:build !kustomize_disable_go_plugin_support + +package loader + +import ( + "fmt" + "log" + "plugin" + "reflect" + + "sigs.k8s.io/kustomize/api/internal/plugins/utils" + "sigs.k8s.io/kustomize/api/konfig" + "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/resid" +) + +// registry is a means to avoid trying to load the same .so file +// into memory more than once, which results in an error. +// Each test makes its own loader, and tries to load its own plugins, +// but the loaded .so files are in shared memory, so one will get +// "this plugin already loaded" errors if the registry is maintained +// as a Loader instance variable. So make it a package variable. +var registry = make(map[string]resmap.Configurable) //nolint:gochecknoglobals + +func copyPlugin(c resmap.Configurable) resmap.Configurable { + indirect := reflect.Indirect(reflect.ValueOf(c)) + newIndirect := reflect.New(indirect.Type()) + newIndirect.Elem().Set(reflect.ValueOf(indirect.Interface())) + newNamed := newIndirect.Interface() + return newNamed.(resmap.Configurable) //nolint:forcetypeassert +} + +func (l *Loader) loadGoPlugin(id resid.ResId, absPath string) (resmap.Configurable, error) { + regId := relativePluginPath(id) + if c, ok := registry[regId]; ok { + return copyPlugin(c), nil + } + if !utils.FileExists(absPath) { + return nil, fmt.Errorf( + "expected file with Go object code at: %s", absPath) + } + log.Printf("Attempting plugin load from %q", absPath) + p, err := plugin.Open(absPath) + if err != nil { + return nil, errors.WrapPrefixf(err, "plugin %s fails to load", absPath) + } + symbol, err := p.Lookup(konfig.PluginSymbol) + if err != nil { + return nil, errors.WrapPrefixf( + err, "plugin %s doesn't have symbol %s", + regId, konfig.PluginSymbol) + } + c, ok := symbol.(resmap.Configurable) + if !ok { + return nil, fmt.Errorf("plugin %q not configurable", regId) + } + registry[regId] = c + return copyPlugin(c), nil +} diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin_disabled.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin_disabled.go new file mode 100644 index 000000000..5531b7967 --- /dev/null +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/load_go_plugin_disabled.go @@ -0,0 +1,25 @@ +// Copyright 2024 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// The build tag "kustomize_disable_go_plugin_support" is used to deactivate the +// kustomize API's dependency on the "plugins" package. This is beneficial for +// applications that need to embed it but do not have requirements for dynamic +// Go plugins. +// Including plugins as a dependency can lead to an increase in binary size due +// to the population of ELF's sections such as .dynsym and .dynstr. +// By utilizing this flag, applications have the flexibility to exclude the +// import if they do not require support for dynamic Go plugins. +//go:build kustomize_disable_go_plugin_support + +package loader + +import ( + "fmt" + + "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/kyaml/resid" +) + +func (l *Loader) loadGoPlugin(_ resid.ResId, _ string) (resmap.Configurable, error) { + return nil, fmt.Errorf("plugin load is disabled") +} diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/loader.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/loader.go index 1758e5cf6..e494df767 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/loader.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/plugins/loader/loader.go @@ -5,18 +5,14 @@ package loader import ( "fmt" - "log" "os" "path/filepath" - "plugin" - "reflect" "strings" "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers" "sigs.k8s.io/kustomize/api/internal/plugins/execplugin" "sigs.k8s.io/kustomize/api/internal/plugins/fnplugin" - "sigs.k8s.io/kustomize/api/internal/plugins/utils" "sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resource" @@ -287,46 +283,3 @@ func (l *Loader) loadExecOrGoPlugin(resId resid.ResId) (resmap.Configurable, err return c, nil } -// registry is a means to avoid trying to load the same .so file -// into memory more than once, which results in an error. -// Each test makes its own loader, and tries to load its own plugins, -// but the loaded .so files are in shared memory, so one will get -// "this plugin already loaded" errors if the registry is maintained -// as a Loader instance variable. So make it a package variable. -var registry = make(map[string]resmap.Configurable) - -func (l *Loader) loadGoPlugin(id resid.ResId, absPath string) (resmap.Configurable, error) { - regId := relativePluginPath(id) - if c, ok := registry[regId]; ok { - return copyPlugin(c), nil - } - if !utils.FileExists(absPath) { - return nil, fmt.Errorf( - "expected file with Go object code at: %s", absPath) - } - log.Printf("Attempting plugin load from '%s'", absPath) - p, err := plugin.Open(absPath) - if err != nil { - return nil, errors.WrapPrefixf(err, "plugin %s fails to load", absPath) - } - symbol, err := p.Lookup(konfig.PluginSymbol) - if err != nil { - return nil, errors.WrapPrefixf( - err, "plugin %s doesn't have symbol %s", - regId, konfig.PluginSymbol) - } - c, ok := symbol.(resmap.Configurable) - if !ok { - return nil, fmt.Errorf("plugin '%s' not configurable", regId) - } - registry[regId] = c - return copyPlugin(c), nil -} - -func copyPlugin(c resmap.Configurable) resmap.Configurable { - indirect := reflect.Indirect(reflect.ValueOf(c)) - newIndirect := reflect.New(indirect.Type()) - newIndirect.Elem().Set(reflect.ValueOf(indirect.Interface())) - newNamed := newIndirect.Interface() - return newNamed.(resmap.Configurable) -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget.go index eefa1ac63..5f1d1095a 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget.go @@ -425,7 +425,14 @@ func (kt *KustTarget) accumulateResources( } ldr, err := kt.ldr.New(path) if err != nil { - if kusterr.IsMalformedYAMLError(errF) { // Some error occurred while tyring to decode YAML file + // If accumulateFile found malformed YAML and there was a failure + // loading the resource as a base, then the resource is likely a + // file. The loader failure message is unnecessary, and could be + // confusing. Report only the file load error. + // + // However, a loader timeout implies there is a git repo at the + // path. In that case, both errors could be important. + if kusterr.IsMalformedYAMLError(errF) && !utils.IsErrTimeout(err) { return nil, errF } return nil, errors.WrapPrefixf( @@ -442,9 +449,6 @@ func (kt *KustTarget) accumulateResources( ra, err = kt.accumulateDirectory(ra, ldr, false) } if err != nil { - if kusterr.IsMalformedYAMLError(errF) { // Some error occurred while tyring to decode YAML file - return nil, errF - } return nil, errors.WrapPrefixf( err, "accumulation err='%s'", errF.Error()) } @@ -453,7 +457,7 @@ func (kt *KustTarget) accumulateResources( return ra, nil } -// accumulateResources fills the given resourceAccumulator +// accumulateComponents fills the given resourceAccumulator // with resources read from the given list of paths. func (kt *KustTarget) accumulateComponents( ra *accumulator.ResAccumulator, paths []string) (*accumulator.ResAccumulator, error) { diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget_configplugin.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget_configplugin.go index b589961e5..1ba028a36 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget_configplugin.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/target/kusttarget_configplugin.go @@ -275,13 +275,25 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func( if len(kt.kustomization.Labels) == 0 && len(kt.kustomization.CommonLabels) == 0 { return } + + type labelStruct struct { + Labels map[string]string + FieldSpecs []types.FieldSpec + } + for _, label := range kt.kustomization.Labels { - var c struct { - Labels map[string]string - FieldSpecs []types.FieldSpec - } + var c labelStruct + c.Labels = label.Pairs fss := types.FsSlice(label.FieldSpecs) + + // merge labels specified in the label section of transformer configs + // these apply to selectors and templates + fss, err := fss.MergeAll(tc.Labels) + if err != nil { + return nil, fmt.Errorf("failed to merge labels: %w", err) + } + // merge the custom fieldSpecs with the default if label.IncludeSelectors { fss, err = fss.MergeAll(tc.CommonLabels) @@ -297,7 +309,7 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func( fss, err = fss.MergeOne(types.FieldSpec{Path: "metadata/labels", CreateIfNotPresent: true}) } if err != nil { - return nil, err + return nil, fmt.Errorf("failed to merge labels: %w", err) } c.FieldSpecs = fss p := f() @@ -307,10 +319,9 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func( } result = append(result, p) } - var c struct { - Labels map[string]string - FieldSpecs []types.FieldSpec - } + + var c labelStruct + c.Labels = kt.kustomization.CommonLabels c.FieldSpecs = tc.CommonLabels p := f() diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/internal/utils/errtimeout.go b/tests/vendor/sigs.k8s.io/kustomize/api/internal/utils/errtimeout.go index c1761d2c6..a0d861c7b 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/internal/utils/errtimeout.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/internal/utils/errtimeout.go @@ -15,11 +15,11 @@ type errTimeOut struct { cmd string } -func NewErrTimeOut(d time.Duration, c string) errTimeOut { - return errTimeOut{duration: d, cmd: c} +func NewErrTimeOut(d time.Duration, c string) *errTimeOut { + return &errTimeOut{duration: d, cmd: c} } -func (e errTimeOut) Error() string { +func (e *errTimeOut) Error() string { return fmt.Sprintf("hit %s timeout running '%s'", e.duration, e.cmd) } diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/provenance/provenance.go b/tests/vendor/sigs.k8s.io/kustomize/api/provenance/provenance.go index 0e24fc36c..c637ac2e1 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/provenance/provenance.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/provenance/provenance.go @@ -8,6 +8,8 @@ import ( "runtime" "runtime/debug" "strings" + + "github.com/blang/semver/v4" ) // These variables are set at build time using ldflags. @@ -62,9 +64,42 @@ func GetProvenance() Provenance { p.GitCommit = setting.Value } } + + for _, dep := range info.Deps { + if dep != nil && dep.Path == "sigs.k8s.io/kustomize/kustomize/v5" { + if dep.Version != "devel" { + continue + } + v, err := GetMostRecentTag(*dep) + if err != nil { + fmt.Printf("failed to get most recent tag for %s: %v\n", dep.Path, err) + continue + } + p.Version = v + } + } + return p } +func GetMostRecentTag(m debug.Module) (string, error) { + for m.Replace != nil { + m = *m.Replace + } + + split := strings.Split(m.Version, "-") + sv, err := semver.Parse(strings.TrimPrefix(split[0], "v")) + + if err != nil { + return "", fmt.Errorf("failed to parse version %s: %w", m.Version, err) + } + + if len(split) > 1 && sv.Patch > 0 { + sv.Patch -= 1 + } + return fmt.Sprintf("v%s", sv.FinalizeVersion()), nil +} + // Short returns the shortened provenance stamp. func (v Provenance) Short() string { return fmt.Sprintf( diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/resource/factory.go b/tests/vendor/sigs.k8s.io/kustomize/api/resource/factory.go index f67fbf360..a42f93bb8 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/resource/factory.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/resource/factory.go @@ -41,28 +41,26 @@ func (rf *Factory) Hasher() ifc.KustHasher { } // FromMap returns a new instance of Resource. -func (rf *Factory) FromMap(m map[string]interface{}) *Resource { +func (rf *Factory) FromMap(m map[string]interface{}) (*Resource, error) { res, err := rf.FromMapAndOption(m, nil) if err != nil { - // TODO: return err instead of log. - log.Fatalf("failed to create resource from map: %v", err) + return nil, fmt.Errorf("failed to create resource from map: %w", err) } - return res + return res, nil } // FromMapWithName returns a new instance with the given "original" name. -func (rf *Factory) FromMapWithName(n string, m map[string]interface{}) *Resource { +func (rf *Factory) FromMapWithName(n string, m map[string]interface{}) (*Resource, error) { return rf.FromMapWithNamespaceAndName(resid.DefaultNamespace, n, m) } // FromMapWithNamespaceAndName returns a new instance with the given "original" namespace. -func (rf *Factory) FromMapWithNamespaceAndName(ns string, n string, m map[string]interface{}) *Resource { +func (rf *Factory) FromMapWithNamespaceAndName(ns string, n string, m map[string]interface{}) (*Resource, error) { r, err := rf.FromMapAndOption(m, nil) if err != nil { - // TODO: return err instead of log. - log.Fatalf("failed to create resource from map: %v", err) + return nil, fmt.Errorf("failed to create resource from map: %w", err) } - return r.setPreviousId(ns, n, r.GetKind()) + return r.setPreviousId(ns, n, r.GetKind()), nil } // FromMapAndOption returns a new instance of Resource with given options. @@ -204,7 +202,10 @@ func (rf *Factory) inlineAnyEmbeddedLists( } items, ok := m["items"] if !ok { - // treat as an empty list + // Items field is not present. + // This is not a collections resource. + // read more https://kubernetes.io/docs/reference/using-api/api-concepts/#collections + result = append(result, n0) continue } slice, ok := items.([]interface{}) diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/resource/resource.go b/tests/vendor/sigs.k8s.io/kustomize/api/resource/resource.go index ae1a98be0..9884a672c 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/resource/resource.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/resource/resource.go @@ -287,12 +287,25 @@ func (r *Resource) getCsvAnnotation(name string) []string { return strings.Split(annotations[name], ",") } -// PrefixesSuffixesEquals is conceptually doing the same task -// as OutermostPrefixSuffix but performs a deeper comparison -// of the suffix and prefix slices. -func (r *Resource) PrefixesSuffixesEquals(o ResCtx) bool { - return utils.SameEndingSubSlice(r.GetNamePrefixes(), o.GetNamePrefixes()) && - utils.SameEndingSubSlice(r.GetNameSuffixes(), o.GetNameSuffixes()) +// PrefixesSuffixesEquals is conceptually doing the same task as +// OutermostPrefixSuffix but performs a deeper comparison of the suffix and +// prefix slices. +// The allowEmpty flag determines whether an empty prefix/suffix +// should be considered a match on anything. +// This is used when filtering, starting with a coarser pass allowing empty +// matches, before requiring exact matches if there are multiple +// remaining candidates. +func (r *Resource) PrefixesSuffixesEquals(o ResCtx, allowEmpty bool) bool { + if allowEmpty { + eitherPrefixEmpty := len(r.GetNamePrefixes()) == 0 || len(o.GetNamePrefixes()) == 0 + eitherSuffixEmpty := len(r.GetNameSuffixes()) == 0 || len(o.GetNameSuffixes()) == 0 + + return (eitherPrefixEmpty || utils.SameEndingSubSlice(r.GetNamePrefixes(), o.GetNamePrefixes())) && + (eitherSuffixEmpty || utils.SameEndingSubSlice(r.GetNameSuffixes(), o.GetNameSuffixes())) + } else { + return utils.SameEndingSubSlice(r.GetNamePrefixes(), o.GetNamePrefixes()) && + utils.SameEndingSubSlice(r.GetNameSuffixes(), o.GetNameSuffixes()) + } } // RemoveBuildAnnotations removes annotations created by the build process. diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go b/tests/vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go index 1ed89c01c..b96fbfb16 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/types/helmchartargs.go @@ -96,6 +96,9 @@ type HelmChart struct { // SkipTests skips tests from templated output. SkipTests bool `json:"skipTests,omitempty" yaml:"skipTests,omitempty"` + + // debug enables debug output from the Helm chart inflator generator. + Debug bool `json:"debug,omitempty" yaml:"debug,omitempty"` } // HelmChartArgs contains arguments to helm. @@ -188,5 +191,8 @@ func (h HelmChart) AsHelmArgs(absChartHome string) []string { if h.SkipHooks { args = append(args, "--no-hooks") } + if h.Debug { + args = append(args, "--debug") + } return args } diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/types/kustomization.go b/tests/vendor/sigs.k8s.io/kustomize/api/types/kustomization.go index f86ec0b9e..6caa29664 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/types/kustomization.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/types/kustomization.go @@ -22,6 +22,7 @@ const ( MetadataNamespacePath = "metadata/namespace" MetadataNamespaceApiVersion = "v1" MetadataNamePath = "metadata/name" + NamespaceKind = "Namespace" OriginAnnotations = "originAnnotations" TransformerAnnotations = "transformerAnnotations" @@ -55,6 +56,7 @@ type Kustomization struct { // Namespace to add to all objects. Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + // Deprecated: Use the Labels field instead, which provides a superset of the functionality of CommonLabels. // CommonLabels to add to all objects and selectors. CommonLabels map[string]string `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"` diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/types/labels.go b/tests/vendor/sigs.k8s.io/kustomize/api/types/labels.go index 05ba890f9..35f7fb2a5 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/types/labels.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/types/labels.go @@ -6,12 +6,12 @@ package types type Label struct { // Pairs contains the key-value pairs for labels to add Pairs map[string]string `json:"pairs,omitempty" yaml:"pairs,omitempty"` - // IncludeSelectors inidicates should transformer include the + // IncludeSelectors indicates whether the transformer should include the // fieldSpecs for selectors. Custom fieldSpecs specified by // FieldSpecs will be merged with builtin fieldSpecs if this // is true. IncludeSelectors bool `json:"includeSelectors,omitempty" yaml:"includeSelectors,omitempty"` - // IncludeTemplates inidicates should transformer include the + // IncludeTemplates indicates whether the transformer should include the // spec/template/metadata fieldSpec. Custom fieldSpecs specified by // FieldSpecs will be merged with spec/template/metadata fieldSpec if this // is true. If IncludeSelectors is true, IncludeTemplates is not needed. diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go b/tests/vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go index aa511ae79..9721eb724 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/types/pluginconfig.go @@ -8,6 +8,7 @@ type HelmConfig struct { Command string ApiVersions []string KubeVersion string + Debug bool } // PluginConfig holds plugin configuration. @@ -27,7 +28,6 @@ type PluginConfig struct { func EnabledPluginConfig(b BuiltinPluginLoadingOptions) (pc *PluginConfig) { pc = MakePluginConfig(PluginRestrictionsNone, b) - pc.FnpLoadingOptions.EnableStar = true pc.HelmConfig.Enabled = true // If this command is not on PATH, tests needing it should skip. pc.HelmConfig.Command = "helmV3" diff --git a/tests/vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go b/tests/vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go index 88b03b3f5..0e4ee42e4 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go +++ b/tests/vendor/sigs.k8s.io/kustomize/api/types/pluginrestrictions.go @@ -46,8 +46,6 @@ const ( type FnPluginLoadingOptions struct { // Allow to run executables EnableExec bool - // Allow to run starlark - EnableStar bool // Allow container access to network Network bool NetworkName string diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/container/container.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/container/container.go index 76b51a8c5..62aa76f53 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/container/container.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/container/container.go @@ -167,7 +167,7 @@ func (c *Filter) setupExec() error { return nil } -// getArgs returns the command + args to run to spawn the container +// getCommand returns the command + args to run to spawn the container func (c *Filter) getCommand() (string, []string) { network := runtimeutil.NetworkNameNone if c.ContainerSpec.Network { diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil/functiontypes.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil/functiontypes.go index f0448ea28..f56962c14 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil/functiontypes.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil/functiontypes.go @@ -132,9 +132,6 @@ type FunctionSpec struct { // Container is the spec for running a function as a container Container ContainerSpec `json:"container,omitempty" yaml:"container,omitempty"` - // Starlark is the spec for running a function as a starlark script - Starlark StarlarkSpec `json:"starlark,omitempty" yaml:"starlark,omitempty"` - // ExecSpec is the spec for running a function as an executable Exec ExecSpec `json:"exec,omitempty" yaml:"exec,omitempty"` } @@ -158,17 +155,6 @@ type ContainerSpec struct { Env []string `json:"envs,omitempty" yaml:"envs,omitempty"` } -// StarlarkSpec defines how to run a function as a starlark program -type StarlarkSpec struct { - Name string `json:"name,omitempty" yaml:"name,omitempty"` - - // Path specifies a path to a starlark script - Path string `json:"path,omitempty" yaml:"path,omitempty"` - - // URL specifies a url containing a starlark script - URL string `json:"url,omitempty" yaml:"url,omitempty"` -} - // StorageMount represents a container's mounted storage option(s) type StorageMount struct { // Type of mount e.g. bind mount, local volume, etc. diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/context.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/context.go deleted file mode 100644 index bbf07f66c..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/context.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package starlark - -import ( - "encoding/json" - "os" - "strings" - - "go.starlark.net/starlark" - "go.starlark.net/starlarkstruct" - "sigs.k8s.io/kustomize/kyaml/errors" - "sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util" - "sigs.k8s.io/kustomize/kyaml/openapi" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -type Context struct { - resourceList starlark.Value -} - -func (c *Context) predeclared() (starlark.StringDict, error) { - e, err := env() - if err != nil { - return nil, err - } - oa, err := oa() - if err != nil { - return nil, err - } - dict := starlark.StringDict{ - "resource_list": c.resourceList, - "open_api": oa, - "environment": e, - } - - return starlark.StringDict{ - "ctx": starlarkstruct.FromStringDict(starlarkstruct.Default, dict), - }, nil -} - -func oa() (starlark.Value, error) { - return interfaceToValue(openapi.Schema()) -} - -func env() (starlark.Value, error) { - env := map[string]interface{}{} - for _, e := range os.Environ() { - pair := strings.SplitN(e, "=", 2) - if len(pair) < 2 { - continue - } - env[pair[0]] = pair[1] - } - value, err := util.Marshal(env) - if err != nil { - return nil, errors.Wrap(err) - } - return value, nil -} - -func interfaceToValue(i interface{}) (starlark.Value, error) { - b, err := json.Marshal(i) - if err != nil { - return nil, err - } - - var in map[string]interface{} - if err := yaml.Unmarshal(b, &in); err != nil { - return nil, errors.Wrap(err) - } - - value, err := util.Marshal(in) - if err != nil { - return nil, errors.Wrap(err) - } - return value, nil -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/doc.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/doc.go deleted file mode 100644 index 70f0a2c7b..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/doc.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -// Package starlark contains a kio.Filter which can be applied to resources to transform -// them through starlark program. -// -// Starlark has become a popular runtime embedding in go programs, especially for Kubernetes -// and data processing. -// Examples: https://github.com/cruise-automation/isopod, https://qri.io/docs/starlark/starlib, -// https://github.com/stripe/skycfg, https://github.com/k14s/ytt -// -// The resources are provided to the starlark program through the global variable "resourceList". -// "resourceList" is a dictionary containing an "items" field with a list of resources. -// The starlark modified "resourceList" is the Filter output. -// -// After being run through the starlark program, the filter will copy the comments from the input -// resources to restore them -- due to them being dropped as a result of serializing the resources -// as starlark values. -// -// "resourceList" may also contain a "functionConfig" entry to configure the starlark script itself. -// Changes made by the starlark program to the "functionConfig" will be reflected in the -// Filter.FunctionConfig value. -// -// The Filter will also format the output so that output has the preferred field ordering -// rather than an alphabetical field ordering. -// -// The resourceList variable adheres to the kustomize function spec as specified by: -// https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/functions-spec.md -// -// All items in the resourceList are resources represented as starlark dictionaries/ -// The items in the resourceList respect the io spec specified by: -// https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/config-io.md -// -// The starlark language spec can be found here: -// https://github.com/google/starlark-go/blob/master/doc/spec.md -package starlark diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/starlark.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/starlark.go deleted file mode 100644 index aeeeb81ed..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/starlark.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package starlark - -import ( - "bytes" - "fmt" - "io" - "net/http" - "os" - - "go.starlark.net/starlark" - "sigs.k8s.io/kustomize/kyaml/errors" - "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil" - "sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util" - "sigs.k8s.io/kustomize/kyaml/kio/filters" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -// Filter transforms a set of resources through the provided program -type Filter struct { - Name string - - // Program is a starlark script which will be run against the resources - Program string - - // URL is the url of a starlark program to fetch and run - URL string - - // Path is the path to a starlark program to read and run - Path string - - runtimeutil.FunctionFilter -} - -func (sf *Filter) String() string { - return fmt.Sprintf( - "name: %v path: %v url: %v program: %v", sf.Name, sf.Path, sf.URL, sf.Program) -} - -func (sf *Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { - if err := sf.setup(); err != nil { - return nil, err - } - sf.FunctionFilter.Run = sf.Run - - return sf.FunctionFilter.Filter(nodes) -} - -func (sf *Filter) setup() error { - if (sf.URL != "" && sf.Path != "") || - (sf.URL != "" && sf.Program != "") || - (sf.Path != "" && sf.Program != "") { - return errors.Errorf("Filter Path, Program and URL are mutually exclusive") - } - - // read the program from a file - if sf.Path != "" { - b, err := os.ReadFile(sf.Path) - if err != nil { - return err - } - sf.Program = string(b) - } - - // read the program from a URL - if sf.URL != "" { - err := func() error { - resp, err := http.Get(sf.URL) - if err != nil { - return err - } - defer resp.Body.Close() - b, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - sf.Program = string(b) - return nil - }() - if err != nil { - return err - } - } - - return nil -} - -func (sf *Filter) Run(reader io.Reader, writer io.Writer) error { - // retain map of inputs to outputs by id so if the name is changed by the - // starlark program, we are able to match the same resources - value, err := sf.readResourceList(reader) - if err != nil { - return errors.Wrap(err) - } - - // run the starlark as program as transformation function - thread := &starlark.Thread{Name: sf.Name} - - ctx := &Context{resourceList: value} - pd, err := ctx.predeclared() - if err != nil { - return errors.Wrap(err) - } - _, err = starlark.ExecFile(thread, sf.Name, sf.Program, pd) - if err != nil { - return errors.Wrap(err) - } - - return sf.writeResourceList(value, writer) -} - -// inputToResourceList transforms input into a starlark.Value -func (sf *Filter) readResourceList(reader io.Reader) (starlark.Value, error) { - // read and parse the inputs - rl := bytes.Buffer{} - _, err := rl.ReadFrom(reader) - if err != nil { - return nil, errors.Wrap(err) - } - rn, err := yaml.Parse(rl.String()) - if err != nil { - return nil, errors.Wrap(err) - } - - // convert to a starlark value - b, err := yaml.Marshal(rn.Document()) // convert to bytes - if err != nil { - return nil, errors.Wrap(err) - } - var in map[string]interface{} - err = yaml.Unmarshal(b, &in) // convert to map[string]interface{} - if err != nil { - return nil, errors.Wrap(err) - } - return util.Marshal(in) // convert to starlark value -} - -// resourceListToOutput converts the output of the starlark program to the filter output -func (sf *Filter) writeResourceList(value starlark.Value, writer io.Writer) error { - // convert the modified resourceList back into a slice of RNodes - // by first converting to a map[string]interface{} - out, err := util.Unmarshal(value) - if err != nil { - return errors.Wrap(err) - } - b, err := yaml.Marshal(out) - if err != nil { - return errors.Wrap(err) - } - - rl, err := yaml.Parse(string(b)) - if err != nil { - return errors.Wrap(err) - } - - // preserve the comments from the input - items, err := rl.Pipe(yaml.Lookup("items")) - if err != nil { - return errors.Wrap(err) - } - err = items.VisitElements(func(node *yaml.RNode) error { - // starlark will serialize the resources sorting the fields alphabetically, - // format them to have a better ordering - _, err := filters.FormatFilter{}.Filter([]*yaml.RNode{node}) - return err - }) - if err != nil { - return errors.Wrap(err) - } - - s, err := rl.String() - if err != nil { - return errors.Wrap(err) - } - - _, err = writer.Write([]byte(s)) - return err -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/doc.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/doc.go deleted file mode 100644 index 035b47921..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/doc.go +++ /dev/null @@ -1,25 +0,0 @@ -// The MIT License (MIT) - -// Copyright (c) 2018 QRI, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Package util is forked from https://github.com/qri-io/starlib in order to prune -// excessive transitive dependencies from pulling in that library. -package util diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/util.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/util.go deleted file mode 100644 index 6bc4fba0f..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util/util.go +++ /dev/null @@ -1,275 +0,0 @@ -// The MIT License (MIT) - -// Copyright (c) 2018 QRI, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package util - -import ( - "fmt" - - "go.starlark.net/starlark" - "go.starlark.net/starlarkstruct" - "sigs.k8s.io/kustomize/kyaml/errors" -) - -// // asString unquotes a starlark string value -// func asString(x starlark.Value) (string, error) { -// return strconv.Unquote(x.String()) -// } - -// IsEmptyString checks is a starlark string is empty ("" for a go string) -// starlark.String.String performs repr-style quotation, which is necessary -// for the starlark.Value contract but a frequent source of errors in API -// clients. This helper method makes sure it'll work properly -func IsEmptyString(s starlark.String) bool { - return s.String() == `""` -} - -// Unmarshal decodes a starlark.Value into it's golang counterpart -// -//nolint:nakedret -func Unmarshal(x starlark.Value) (val interface{}, err error) { - switch v := x.(type) { - case starlark.NoneType: - val = nil - case starlark.Bool: - val = v.Truth() == starlark.True - case starlark.Int: - val, err = starlark.AsInt32(x) - case starlark.Float: - if f, ok := starlark.AsFloat(x); !ok { - err = fmt.Errorf("couldn't parse float") - } else { - val = f - } - case starlark.String: - val = v.GoString() - // case starlibtime.Time: - // val = time.Time(v) - case *starlark.Dict: - var ( - dictVal starlark.Value - pval interface{} - kval interface{} - keys []interface{} - vals []interface{} - // key as interface if found one key is not a string - ki bool - ) - - for _, k := range v.Keys() { - dictVal, _, err = v.Get(k) - if err != nil { - return - } - - pval, err = Unmarshal(dictVal) - if err != nil { - err = fmt.Errorf("unmarshaling starlark value: %w", err) - return - } - - kval, err = Unmarshal(k) - if err != nil { - err = fmt.Errorf("unmarshaling starlark key: %w", err) - return - } - - if _, ok := kval.(string); !ok { - // found key as not a string - ki = true - } - - keys = append(keys, kval) - vals = append(vals, pval) - } - - // prepare result - - rs := map[string]interface{}{} - ri := map[interface{}]interface{}{} - - for i, key := range keys { - // key as interface - if ki { - ri[key] = vals[i] - } else { - rs[key.(string)] = vals[i] - } - } - - if ki { - val = ri // map[interface{}]interface{} - } else { - val = rs // map[string]interface{} - } - case *starlark.List: - var ( - i int - listVal starlark.Value - iter = v.Iterate() - value = make([]interface{}, v.Len()) - ) - - defer iter.Done() - for iter.Next(&listVal) { - value[i], err = Unmarshal(listVal) - if err != nil { - return - } - i++ - } - val = value - case starlark.Tuple: - var ( - i int - tupleVal starlark.Value - iter = v.Iterate() - value = make([]interface{}, v.Len()) - ) - - defer iter.Done() - for iter.Next(&tupleVal) { - value[i], err = Unmarshal(tupleVal) - if err != nil { - return - } - i++ - } - val = value - case *starlark.Set: - fmt.Println("errnotdone: SET") - err = fmt.Errorf("sets aren't yet supported") - case *starlarkstruct.Struct: - if _var, ok := v.Constructor().(Unmarshaler); ok { - err = _var.UnmarshalStarlark(x) - if err != nil { - err = errors.WrapPrefixf(err, "failed marshal %q to Starlark object", v.Constructor().Type()) - return - } - val = _var - } else { - err = fmt.Errorf("constructor object from *starlarkstruct.Struct not supported Marshaler to starlark object: %s", v.Constructor().Type()) - } - default: - fmt.Println("errbadtype:", x.Type()) - err = fmt.Errorf("unrecognized starlark type: %s", x.Type()) - } - return -} - -// Marshal turns go values into starlark types -// -//nolint:nakedret -func Marshal(data interface{}) (v starlark.Value, err error) { - switch x := data.(type) { - case nil: - v = starlark.None - case bool: - v = starlark.Bool(x) - case string: - v = starlark.String(x) - case int: - v = starlark.MakeInt(x) - case int8: - v = starlark.MakeInt(int(x)) - case int16: - v = starlark.MakeInt(int(x)) - case int32: - v = starlark.MakeInt(int(x)) - case int64: - v = starlark.MakeInt64(x) - case uint: - v = starlark.MakeUint(x) - case uint8: - v = starlark.MakeUint(uint(x)) - case uint16: - v = starlark.MakeUint(uint(x)) - case uint32: - v = starlark.MakeUint(uint(x)) - case uint64: - v = starlark.MakeUint64(x) - case float32: - v = starlark.Float(float64(x)) - case float64: - v = starlark.Float(x) - // case time.Time: - // v = starlibtime.Time(x) - case []interface{}: - var elems = make([]starlark.Value, len(x)) - for i, val := range x { - elems[i], err = Marshal(val) - if err != nil { - return - } - } - v = starlark.NewList(elems) - case map[interface{}]interface{}: - dict := &starlark.Dict{} - var elem starlark.Value - for ki, val := range x { - var key starlark.Value - key, err = Marshal(ki) - if err != nil { - return - } - - elem, err = Marshal(val) - if err != nil { - return - } - if err = dict.SetKey(key, elem); err != nil { - return - } - } - v = dict - case map[string]interface{}: - dict := &starlark.Dict{} - var elem starlark.Value - for key, val := range x { - elem, err = Marshal(val) - if err != nil { - return - } - if err = dict.SetKey(starlark.String(key), elem); err != nil { - return - } - } - v = dict - case Marshaler: - v, err = x.MarshalStarlark() - default: - return starlark.None, fmt.Errorf("unrecognized type: %#v", x) - } - return -} - -// Unmarshaler is the interface use to unmarshal starlark custom types. -type Unmarshaler interface { - // UnmarshalStarlark unmarshal a starlark object to custom type. - UnmarshalStarlark(starlark.Value) error -} - -// Marshaler is the interface use to marshal starlark custom types. -type Marshaler interface { - // MarshalStarlark marshal a custom type to starlark object. - MarshalStarlark() (starlark.Value, error) -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/filters.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/filters.go deleted file mode 100644 index 8d7968b3c..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/filters.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package filters - -import ( - "fmt" - "sort" - "strings" - - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/kio/kioutil" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -// Filters are the list of known filters for unmarshalling a filter into a concrete -// implementation. -var Filters = map[string]func() kio.Filter{ - "FileSetter": func() kio.Filter { return &FileSetter{} }, - "FormatFilter": func() kio.Filter { return &FormatFilter{} }, - "GrepFilter": func() kio.Filter { return GrepFilter{} }, - "MatchModifier": func() kio.Filter { return &MatchModifyFilter{} }, - "Modifier": func() kio.Filter { return &Modifier{} }, -} - -// filter wraps a kio.filter so that it can be unmarshalled from yaml. -type KFilter struct { - kio.Filter -} - -func (t KFilter) MarshalYAML() (interface{}, error) { - return t.Filter, nil -} - -func (t *KFilter) UnmarshalYAML(unmarshal func(interface{}) error) error { - i := map[string]interface{}{} - if err := unmarshal(i); err != nil { - return err - } - meta := &yaml.ResourceMeta{} - if err := unmarshal(meta); err != nil { - return err - } - filter, found := Filters[meta.Kind] - if !found { - var knownFilters []string - for k := range Filters { - knownFilters = append(knownFilters, k) - } - sort.Strings(knownFilters) - return fmt.Errorf("unsupported filter Kind %v: may be one of: [%s]", - meta, strings.Join(knownFilters, ",")) - } - t.Filter = filter() - - return unmarshal(t.Filter) -} - -// Modifier modifies the input Resources by invoking the provided pipeline. -// Modifier will return any Resources for which the pipeline does not return an error. -type Modifier struct { - Kind string `yaml:"kind,omitempty"` - - Filters yaml.YFilters `yaml:"pipeline,omitempty"` -} - -var _ kio.Filter = &Modifier{} - -func (f Modifier) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { - for i := range input { - if _, err := input[i].Pipe(f.Filters.Filters()...); err != nil { - return nil, err - } - } - return input, nil -} - -type MatchModifyFilter struct { - Kind string `yaml:"kind,omitempty"` - - MatchFilters []yaml.YFilters `yaml:"match,omitempty"` - - ModifyFilters yaml.YFilters `yaml:"modify,omitempty"` -} - -var _ kio.Filter = &MatchModifyFilter{} - -func (f MatchModifyFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { - var matches = input - var err error - for _, filter := range f.MatchFilters { - matches, err = MatchFilter{Filters: filter}.Filter(matches) - if err != nil { - return nil, err - } - } - _, err = Modifier{Filters: f.ModifyFilters}.Filter(matches) - if err != nil { - return nil, err - } - return input, nil -} - -type MatchFilter struct { - Kind string `yaml:"kind,omitempty"` - - Filters yaml.YFilters `yaml:"pipeline,omitempty"` -} - -var _ kio.Filter = &MatchFilter{} - -func (f MatchFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { - var output []*yaml.RNode - for i := range input { - if v, err := input[i].Pipe(f.Filters.Filters()...); err != nil { - return nil, err - } else if v == nil { - continue - } - output = append(output, input[i]) - } - return output, nil -} - -type FilenameFmtVerb string - -const ( - // KindFmt substitutes kind - KindFmt FilenameFmtVerb = "%k" - - // NameFmt substitutes metadata.name - NameFmt FilenameFmtVerb = "%n" - - // NamespaceFmt substitutes metdata.namespace - NamespaceFmt FilenameFmtVerb = "%s" -) - -// FileSetter sets the file name and mode annotations on Resources. -type FileSetter struct { - Kind string `yaml:"kind,omitempty"` - - // FilenamePattern is the pattern to use for generating filenames. FilenameFmtVerb - // FielnameFmtVerbs may be specified to substitute Resource metadata into the filename. - FilenamePattern string `yaml:"filenamePattern,omitempty"` - - // Mode is the filemode to write. - Mode string `yaml:"mode,omitempty"` - - // Override will override the existing filename if it is set on the pattern. - // Otherwise the existing filename is kept. - Override bool `yaml:"override,omitempty"` -} - -var _ kio.Filter = &FileSetter{} - -const DefaultFilenamePattern = "%n_%k.yaml" - -func (f *FileSetter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { - if f.Mode == "" { - f.Mode = fmt.Sprintf("%d", 0600) - } - if f.FilenamePattern == "" { - f.FilenamePattern = DefaultFilenamePattern - } - - resources := map[string][]*yaml.RNode{} - for i := range input { - if err := kioutil.CopyLegacyAnnotations(input[i]); err != nil { - return nil, err - } - - m, err := input[i].GetMeta() - if err != nil { - return nil, err - } - file := f.FilenamePattern - file = strings.ReplaceAll(file, string(KindFmt), strings.ToLower(m.Kind)) - file = strings.ReplaceAll(file, string(NameFmt), strings.ToLower(m.Name)) - file = strings.ReplaceAll(file, string(NamespaceFmt), strings.ToLower(m.Namespace)) - - if _, found := m.Annotations[kioutil.PathAnnotation]; !found || f.Override { - if _, err := input[i].Pipe(yaml.SetAnnotation(kioutil.PathAnnotation, file)); err != nil { - return nil, err - } - if _, err := input[i].Pipe(yaml.SetAnnotation(kioutil.LegacyPathAnnotation, file)); err != nil { - return nil, err - } - } - resources[file] = append(resources[file], input[i]) - } - - var output []*yaml.RNode - for i := range resources { - if err := kioutil.SortNodes(resources[i]); err != nil { - return nil, err - } - for j := range resources[i] { - if _, err := resources[i][j].Pipe( - yaml.SetAnnotation(kioutil.IndexAnnotation, fmt.Sprintf("%d", j))); err != nil { - return nil, err - } - if _, err := resources[i][j].Pipe( - yaml.SetAnnotation(kioutil.LegacyIndexAnnotation, fmt.Sprintf("%d", j))); err != nil { - return nil, err - } - output = append(output, resources[i][j]) - } - } - return output, nil -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/fmtr.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/fmtr.go deleted file mode 100644 index 7f2acbda4..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/fmtr.go +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -// Package yamlfmt contains libraries for formatting yaml files containing -// Kubernetes Resource configuration. -// -// Yaml files are formatted by: -// - Sorting fields and map values -// - Sorting unordered lists for whitelisted types -// - Applying a canonical yaml Style -// -// Fields are ordered using a relative ordering applied to commonly -// encountered Resource fields. All Resources, including non-builtin -// Resources such as CRDs, share the same field precedence. -// -// Fields that do not appear in the explicit ordering are ordered -// lexicographically. -// -// A subset of well known known unordered lists are sorted by element field -// values. -package filters - -import ( - "bytes" - "fmt" - "io" - "sort" - - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/openapi" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -type FormattingStrategy = string - -const ( - // NoFmtAnnotation determines if the resource should be formatted. - FmtAnnotation string = "config.kubernetes.io/formatting" - - // FmtStrategyStandard means the resource will be formatted according - // to the default rules. - FmtStrategyStandard FormattingStrategy = "standard" - - // FmtStrategyNone means the resource will not be formatted. - FmtStrategyNone FormattingStrategy = "none" -) - -// FormatInput returns the formatted input. -func FormatInput(input io.Reader) (*bytes.Buffer, error) { - buff := &bytes.Buffer{} - err := kio.Pipeline{ - Inputs: []kio.Reader{&kio.ByteReader{Reader: input}}, - Filters: []kio.Filter{FormatFilter{}}, - Outputs: []kio.Writer{kio.ByteWriter{Writer: buff}}, - }.Execute() - - return buff, err -} - -// FormatFileOrDirectory reads the file or directory and formats each file's -// contents by writing it back to the file. -func FormatFileOrDirectory(path string) error { - return kio.Pipeline{ - Inputs: []kio.Reader{kio.LocalPackageReader{ - PackagePath: path, - }}, - Filters: []kio.Filter{FormatFilter{}}, - Outputs: []kio.Writer{kio.LocalPackageWriter{PackagePath: path}}, - }.Execute() -} - -type FormatFilter struct { - Process func(n *yaml.Node) error - UseSchema bool -} - -var _ kio.Filter = FormatFilter{} - -func (f FormatFilter) Filter(slice []*yaml.RNode) ([]*yaml.RNode, error) { - for i := range slice { - fmtStrategy, err := getFormattingStrategy(slice[i]) - if err != nil { - return nil, err - } - - if fmtStrategy == FmtStrategyNone { - continue - } - - kindNode, err := slice[i].Pipe(yaml.Get("kind")) - if err != nil { - return nil, err - } - if kindNode == nil { - continue - } - apiVersionNode, err := slice[i].Pipe(yaml.Get("apiVersion")) - if err != nil { - return nil, err - } - if apiVersionNode == nil { - continue - } - kind, apiVersion := kindNode.YNode().Value, apiVersionNode.YNode().Value - var s *openapi.ResourceSchema - if f.UseSchema { - s = openapi.SchemaForResourceType(yaml.TypeMeta{APIVersion: apiVersion, Kind: kind}) - } else { - s = nil - } - err = (&formatter{apiVersion: apiVersion, kind: kind, process: f.Process}). - fmtNode(slice[i].YNode(), "", s) - if err != nil { - return nil, err - } - } - return slice, nil -} - -// getFormattingStrategy looks for the formatting annotation to determine -// which strategy should be used for formatting. The default is standard -// if no annotation is found. -func getFormattingStrategy(node *yaml.RNode) (FormattingStrategy, error) { - value, err := node.Pipe(yaml.GetAnnotation(FmtAnnotation)) - if err != nil || value == nil { - return FmtStrategyStandard, err - } - - fmtStrategy := value.YNode().Value - - switch fmtStrategy { - case FmtStrategyStandard: - return FmtStrategyStandard, nil - case FmtStrategyNone: - return FmtStrategyNone, nil - default: - return "", fmt.Errorf( - "formatting annotation has illegal value %s", fmtStrategy) - } -} - -type formatter struct { - apiVersion string - kind string - process func(n *yaml.Node) error -} - -// fmtNode recursively formats the Document Contents. -// See: https://godoc.org/gopkg.in/yaml.v3#Node -func (f *formatter) fmtNode(n *yaml.Node, path string, schema *openapi.ResourceSchema) error { - if n.Kind == yaml.ScalarNode && schema != nil && schema.Schema != nil { - // ensure values that are interpreted as non-string values (e.g. "true") - // are properly quoted - yaml.FormatNonStringStyle(n, *schema.Schema) - } - - // sort the order of mapping fields - if n.Kind == yaml.MappingNode { - sort.Sort(sortedMapContents(*n)) - } - - // sort the order of sequence elements if it is whitelisted - if n.Kind == yaml.SequenceNode { - if yaml.WhitelistedListSortKinds.Has(f.kind) && - yaml.WhitelistedListSortApis.Has(f.apiVersion) { - if sortField, found := yaml.WhitelistedListSortFields[path]; found { - sort.Sort(sortedSeqContents{Node: *n, sortField: sortField}) - } - } - } - - // format the Content - for i := range n.Content { - // MappingNode are structured as having their fields as Content, - // with the field-key and field-value alternating. e.g. Even elements - // are the keys and odd elements are the values - isFieldKey := n.Kind == yaml.MappingNode && i%2 == 0 - isFieldValue := n.Kind == yaml.MappingNode && i%2 == 1 - isElement := n.Kind == yaml.SequenceNode - - // run the process callback on the node if it has been set - // don't process keys: their format should be fixed - if f.process != nil && !isFieldKey { - if err := f.process(n.Content[i]); err != nil { - return err - } - } - - // get the schema for this Node - p := path - var s *openapi.ResourceSchema - switch { - case isFieldValue: - // if the node is a field, lookup the schema using the field name - p = fmt.Sprintf("%s.%s", path, n.Content[i-1].Value) - if schema != nil { - s = schema.Field(n.Content[i-1].Value) - } - case isElement: - // if the node is a list element, lookup the schema for the array items - if schema != nil { - s = schema.Elements() - } - } - // format the node using the schema - err := f.fmtNode(n.Content[i], p, s) - if err != nil { - return err - } - } - return nil -} - -// sortedMapContents sorts the Contents field of a MappingNode by the field names using a statically -// defined field precedence, and falling back on lexicographical sorting -type sortedMapContents yaml.Node - -func (s sortedMapContents) Len() int { - return len(s.Content) / 2 -} -func (s sortedMapContents) Swap(i, j int) { - // yaml MappingNode Contents are a list of field names followed by - // field values, rather than a list of field pairs. - // increment. - // - // e.g. ["field1Name", "field1Value", "field2Name", "field2Value"] - iFieldNameIndex := i * 2 - jFieldNameIndex := j * 2 - iFieldValueIndex := iFieldNameIndex + 1 - jFieldValueIndex := jFieldNameIndex + 1 - - // swap field names - s.Content[iFieldNameIndex], s.Content[jFieldNameIndex] = - s.Content[jFieldNameIndex], s.Content[iFieldNameIndex] - - // swap field values - s.Content[iFieldValueIndex], s.Content[jFieldValueIndex] = s. - Content[jFieldValueIndex], s.Content[iFieldValueIndex] -} - -func (s sortedMapContents) Less(i, j int) bool { - iFieldNameIndex := i * 2 - jFieldNameIndex := j * 2 - iFieldName := s.Content[iFieldNameIndex].Value - jFieldName := s.Content[jFieldNameIndex].Value - - // order by their precedence values looked up from the index - iOrder, foundI := yaml.FieldOrder[iFieldName] - jOrder, foundJ := yaml.FieldOrder[jFieldName] - if foundI && foundJ { - return iOrder < jOrder - } - - // known fields come before unknown fields - if foundI { - return true - } - if foundJ { - return false - } - - // neither field is known, sort them lexicographically - return iFieldName < jFieldName -} - -// sortedSeqContents sorts the Contents field of a SequenceNode by the value of -// the elements sortField. -// e.g. it will sort spec.template.spec.containers by the value of the container `name` field -type sortedSeqContents struct { - yaml.Node - sortField string -} - -func (s sortedSeqContents) Len() int { - return len(s.Content) -} -func (s sortedSeqContents) Swap(i, j int) { - s.Content[i], s.Content[j] = s.Content[j], s.Content[i] -} -func (s sortedSeqContents) Less(i, j int) bool { - // primitive lists -- sort by the element's primitive values - if s.sortField == "" { - iValue := s.Content[i].Value - jValue := s.Content[j].Value - return iValue < jValue - } - - // map lists -- sort by the element's sortField values - var iValue, jValue string - for a := range s.Content[i].Content { - if a%2 != 0 { - continue // not a fieldNameIndex - } - // locate the index of the sortField field - if s.Content[i].Content[a].Value == s.sortField { - // a is the yaml node for the field key, a+1 is the node for the field value - iValue = s.Content[i].Content[a+1].Value - } - } - for a := range s.Content[j].Content { - if a%2 != 0 { - continue // not a fieldNameIndex - } - - // locate the index of the sortField field - if s.Content[j].Content[a].Value == s.sortField { - // a is the yaml node for the field key, a+1 is the node for the field value - jValue = s.Content[j].Content[a+1].Value - } - } - - // compare the field values - return iValue < jValue -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/grep.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/grep.go deleted file mode 100644 index 2eb8a8886..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/grep.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package filters - -import ( - "regexp" - "strings" - - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -type GrepType int - -const ( - Regexp GrepType = 1 << iota - GreaterThanEq - GreaterThan - LessThan - LessThanEq -) - -// GrepFilter filters RNodes with a matching field -type GrepFilter struct { - Path []string `yaml:"path,omitempty"` - Value string `yaml:"value,omitempty"` - MatchType GrepType `yaml:"matchType,omitempty"` - InvertMatch bool `yaml:"invertMatch,omitempty"` - Compare func(a, b string) (int, error) -} - -var _ kio.Filter = GrepFilter{} - -func (f GrepFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { - // compile the regular expression 1 time if we are matching using regex - var reg *regexp.Regexp - var err error - if f.MatchType == Regexp || f.MatchType == 0 { - reg, err = regexp.Compile(f.Value) - if err != nil { - return nil, err - } - } - - var output kio.ResourceNodeSlice - for i := range input { - node := input[i] - val, err := node.Pipe(&yaml.PathMatcher{Path: f.Path}) - if err != nil { - return nil, err - } - if val == nil || len(val.Content()) == 0 { - if f.InvertMatch { - output = append(output, input[i]) - } - continue - } - found := false - err = val.VisitElements(func(elem *yaml.RNode) error { - // get the value - var str string - if f.MatchType == Regexp { - style := elem.YNode().Style - defer func() { elem.YNode().Style = style }() - elem.YNode().Style = yaml.FlowStyle - str, err = elem.String() - if err != nil { - return err - } - str = strings.TrimSpace(strings.ReplaceAll(str, `"`, "")) - } else { - // if not regexp, then it needs to parse into a quantity and comments will - // break that - str = elem.YNode().Value - if str == "" { - return nil - } - } - - if f.MatchType == Regexp || f.MatchType == 0 { - if reg.MatchString(str) { - found = true - } - return nil - } - - comp, err := f.Compare(str, f.Value) - if err != nil { - return err - } - - if f.MatchType == GreaterThan && comp > 0 { - found = true - } - if f.MatchType == GreaterThanEq && comp >= 0 { - found = true - } - if f.MatchType == LessThan && comp < 0 { - found = true - } - if f.MatchType == LessThanEq && comp <= 0 { - found = true - } - return nil - }) - if err != nil { - return nil, err - } - if found == f.InvertMatch { - continue - } - - output = append(output, input[i]) - } - return output, nil -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/local.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/local.go deleted file mode 100644 index bdac1a28f..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/local.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package filters - -import ( - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -const LocalConfigAnnotation = "config.kubernetes.io/local-config" - -// IsLocalConfig filters Resources using the config.kubernetes.io/local-config annotation -type IsLocalConfig struct { - // IncludeLocalConfig will include local-config if set to true - IncludeLocalConfig bool `yaml:"includeLocalConfig,omitempty"` - - // ExcludeNonLocalConfig will exclude non local-config if set to true - ExcludeNonLocalConfig bool `yaml:"excludeNonLocalConfig,omitempty"` -} - -// Filter implements kio.Filter -func (c *IsLocalConfig) Filter(inputs []*yaml.RNode) ([]*yaml.RNode, error) { - var out []*yaml.RNode - for i := range inputs { - meta, err := inputs[i].GetMeta() - if err != nil { - return nil, err - } - _, local := meta.Annotations[LocalConfigAnnotation] - - if local && c.IncludeLocalConfig { - out = append(out, inputs[i]) - } else if !local && !c.ExcludeNonLocalConfig { - out = append(out, inputs[i]) - } - } - return out, nil -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge.go deleted file mode 100644 index 5159052cc..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -// Package merge contains libraries for merging Resources and Patches -package filters - -import ( - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" - "sigs.k8s.io/kustomize/kyaml/yaml/merge2" -) - -// MergeFilter merges Resources with the Group/Version/Kind/Namespace/Name together using -// a 2-way merge strategy. -// -// - Fields set to null in the source will be cleared from the destination -// - Fields with matching keys will be merged recursively -// - Lists with an associative key (e.g. name) will have their elements merged using the key -// - List without an associative key will have the dest list replaced by the source list -type MergeFilter struct { - Reverse bool -} - -var _ kio.Filter = MergeFilter{} - -type mergeKey struct { - apiVersion string - kind string - namespace string - name string -} - -// MergeFilter implements kio.Filter by merging Resources with the same G/V/K/NS/N -func (c MergeFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { - // invert the merge precedence - if c.Reverse { - for i, j := 0, len(input)-1; i < j; i, j = i+1, j-1 { - input[i], input[j] = input[j], input[i] - } - } - - // index the Resources by G/V/K/NS/N - index := map[mergeKey][]*yaml.RNode{} - // retain the original ordering - var order []mergeKey - for i := range input { - meta, err := input[i].GetMeta() - if err != nil { - return nil, err - } - key := mergeKey{ - apiVersion: meta.APIVersion, - kind: meta.Kind, - namespace: meta.Namespace, - name: meta.Name, - } - if _, found := index[key]; !found { - order = append(order, key) - } - index[key] = append(index[key], input[i]) - } - - // merge each of the G/V/K/NS/N lists - var output []*yaml.RNode - var err error - for _, k := range order { - var merged *yaml.RNode - resources := index[k] - for i := range resources { - patch := resources[i] - if merged == nil { - // first resources, don't merge it - merged = resources[i] - } else { - merged, err = merge2.Merge(patch, merged, yaml.MergeOptions{ - ListIncreaseDirection: yaml.MergeOptionsListPrepend, - }) - if err != nil { - return nil, err - } - } - } - output = append(output, merged) - } - return output, nil -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge3.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge3.go deleted file mode 100644 index de8bf6f67..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/merge3.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package filters - -import ( - "fmt" - - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/kio/kioutil" - "sigs.k8s.io/kustomize/kyaml/yaml" - "sigs.k8s.io/kustomize/kyaml/yaml/merge3" -) - -const ( - mergeSourceAnnotation = "config.kubernetes.io/merge-source" - mergeSourceOriginal = "original" - mergeSourceUpdated = "updated" - mergeSourceDest = "dest" -) - -// ResourceMatcher interface is used to match two resources based on IsSameResource implementation -// This is the way to group same logical resources in upstream, local and origin for merge -// The default way to group them is using GVKNN similar to how kubernetes server identifies resources -// Users of this library might have their own interpretation of grouping similar resources -// for e.g. if consumer adds a name-prefix to local resource, it should not be treated as new resource -// for updates etc. -// Hence, the callers of this library may pass different implementation for IsSameResource -type ResourceMatcher interface { - IsSameResource(node1, node2 *yaml.RNode) bool -} - -// ResourceMergeStrategy is the return type from the Handle function in the -// ResourceHandler interface. It determines which version of a resource should -// be included in the output (if any). -type ResourceMergeStrategy int - -const ( - // Merge means the output to dest should be the 3-way merge of original, - // updated and dest. - Merge ResourceMergeStrategy = iota - // KeepDest means the version of the resource in dest should be the output. - KeepDest - // KeepUpdated means the version of the resource in updated should be the - // output. - KeepUpdated - // KeepOriginal means the version of the resource in original should be the - // output. - KeepOriginal - // Skip means the resource should not be included in the output. - Skip -) - -// ResourceHandler interface is used to determine what should be done for a -// resource once the versions in original, updated and dest has been -// identified based on the ResourceMatcher. This allows users to customize -// what should be the result in dest if a resource has been deleted from -// upstream. -type ResourceHandler interface { - Handle(original, updated, dest *yaml.RNode) (ResourceMergeStrategy, error) -} - -// Merge3 performs a 3-way merge on the original, updated, and destination packages. -type Merge3 struct { - OriginalPath string - UpdatedPath string - DestPath string - MatchFilesGlob []string - Matcher ResourceMatcher - Handler ResourceHandler -} - -func (m Merge3) Merge() error { - // Read the destination package. The ReadWriter will take take of deleting files - // for removed resources. - var inputs []kio.Reader - dest := &kio.LocalPackageReadWriter{ - PackagePath: m.DestPath, - MatchFilesGlob: m.MatchFilesGlob, - SetAnnotations: map[string]string{mergeSourceAnnotation: mergeSourceDest}, - } - inputs = append(inputs, dest) - - // Read the original package - inputs = append(inputs, kio.LocalPackageReader{ - PackagePath: m.OriginalPath, - MatchFilesGlob: m.MatchFilesGlob, - SetAnnotations: map[string]string{mergeSourceAnnotation: mergeSourceOriginal}, - }) - - // Read the updated package - inputs = append(inputs, kio.LocalPackageReader{ - PackagePath: m.UpdatedPath, - MatchFilesGlob: m.MatchFilesGlob, - SetAnnotations: map[string]string{mergeSourceAnnotation: mergeSourceUpdated}, - }) - - return kio.Pipeline{ - Inputs: inputs, - Filters: []kio.Filter{m}, - Outputs: []kio.Writer{dest}, - }.Execute() -} - -// Filter combines Resources with the same GVK + N + NS into tuples, and then merges them -func (m Merge3) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { - // index the nodes by their identity - matcher := m.Matcher - if matcher == nil { - matcher = &DefaultGVKNNMatcher{MergeOnPath: true} - } - handler := m.Handler - if handler == nil { - handler = &DefaultResourceHandler{} - } - - tl := tuples{matcher: matcher} - for i := range nodes { - if err := tl.add(nodes[i]); err != nil { - return nil, err - } - } - - // iterate over the inputs, merging as needed - var output []*yaml.RNode - for i := range tl.list { - t := tl.list[i] - strategy, err := handler.Handle(t.original, t.updated, t.dest) - if err != nil { - return nil, err - } - switch strategy { - case Merge: - node, err := t.merge() - if err != nil { - return nil, err - } - if node != nil { - output = append(output, node) - } - case KeepDest: - output = append(output, t.dest) - case KeepUpdated: - output = append(output, t.updated) - case KeepOriginal: - output = append(output, t.original) - case Skip: - // do nothing - } - } - return output, nil -} - -// tuples combines nodes with the same GVK + N + NS -type tuples struct { - list []*tuple - - // matcher matches the resources for merge - matcher ResourceMatcher -} - -// DefaultGVKNNMatcher holds the default matching of resources implementation based on -// Group, Version, Kind, Name and Namespace of the resource -type DefaultGVKNNMatcher struct { - // MergeOnPath will use the relative filepath as part of the merge key. - // This may be necessary if the directory contains multiple copies of - // the same resource, or resources patches. - MergeOnPath bool -} - -// IsSameResource returns true if metadata of node1 and metadata of node2 belongs to same logical resource -func (dm *DefaultGVKNNMatcher) IsSameResource(node1, node2 *yaml.RNode) bool { - if node1 == nil || node2 == nil { - return false - } - if err := kioutil.CopyLegacyAnnotations(node1); err != nil { - return false - } - if err := kioutil.CopyLegacyAnnotations(node2); err != nil { - return false - } - - meta1, err := node1.GetMeta() - if err != nil { - return false - } - - meta2, err := node2.GetMeta() - if err != nil { - return false - } - - if meta1.Name != meta2.Name { - return false - } - if meta1.Namespace != meta2.Namespace { - return false - } - if meta1.APIVersion != meta2.APIVersion { - return false - } - if meta1.Kind != meta2.Kind { - return false - } - if dm.MergeOnPath { - // directories may contain multiple copies of a resource with the same - // name, namespace, apiVersion and kind -- e.g. kustomize patches, or - // multiple environments - // mergeOnPath configures the merge logic to use the path as part of the - // resource key - if meta1.Annotations[kioutil.PathAnnotation] != meta2.Annotations[kioutil.PathAnnotation] { - return false - } - } - return true -} - -// add adds a node to the list, combining it with an existing matching Resource if found -func (ts *tuples) add(node *yaml.RNode) error { - for i := range ts.list { - t := ts.list[i] - if ts.matcher.IsSameResource(addedNode(t), node) { - return t.add(node) - } - } - t := &tuple{} - if err := t.add(node); err != nil { - return err - } - ts.list = append(ts.list, t) - return nil -} - -// addedNode returns one on the existing added nodes in the tuple -func addedNode(t *tuple) *yaml.RNode { - if t.updated != nil { - return t.updated - } - if t.original != nil { - return t.original - } - return t.dest -} - -// tuple wraps an original, updated, and dest tuple for a given Resource -type tuple struct { - original *yaml.RNode - updated *yaml.RNode - dest *yaml.RNode -} - -// add sets the corresponding tuple field for the node -func (t *tuple) add(node *yaml.RNode) error { - meta, err := node.GetMeta() - if err != nil { - return err - } - switch meta.Annotations[mergeSourceAnnotation] { - case mergeSourceDest: - if t.dest != nil { - return duplicateError("local", meta.Annotations[kioutil.PathAnnotation]) - } - t.dest = node - case mergeSourceOriginal: - if t.original != nil { - return duplicateError("original upstream", meta.Annotations[kioutil.PathAnnotation]) - } - t.original = node - case mergeSourceUpdated: - if t.updated != nil { - return duplicateError("updated upstream", meta.Annotations[kioutil.PathAnnotation]) - } - t.updated = node - default: - return fmt.Errorf("no source annotation for Resource") - } - return nil -} - -// merge performs a 3-way merge on the tuple -func (t *tuple) merge() (*yaml.RNode, error) { - return merge3.Merge(t.dest, t.original, t.updated) -} - -// duplicateError returns duplicate resources error -func duplicateError(source, filePath string) error { - return fmt.Errorf(`found duplicate %q resources in file %q, please refer to "update" documentation for the fix`, source, filePath) -} - -// DefaultResourceHandler is the default implementation of the ResourceHandler -// interface. It uses the following rules: -// * Keep dest if resource only exists in dest. -// * Keep updated if resource added in updated. -// * Delete dest if updated has been deleted. -// * Don't add the resource back if removed from dest. -// * Otherwise merge. -type DefaultResourceHandler struct{} - -func (*DefaultResourceHandler) Handle(original, updated, dest *yaml.RNode) (ResourceMergeStrategy, error) { - switch { - case original == nil && updated == nil && dest != nil: - // added locally -- keep dest - return KeepDest, nil - case updated != nil && dest == nil: - // added in the update -- add update - return KeepUpdated, nil - case original != nil && updated == nil: - // deleted in the update - return Skip, nil - case original != nil && dest == nil: - // deleted locally - return Skip, nil - default: - // dest and updated are non-nil -- merge them - return Merge, nil - } -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/modify.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/modify.go deleted file mode 100644 index b1090302a..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/modify.go +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package filters diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/stripcomments.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/stripcomments.go deleted file mode 100644 index 8e9ecb3f2..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/filters/stripcomments.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package filters - -import ( - "sigs.k8s.io/kustomize/kyaml/kio" - "sigs.k8s.io/kustomize/kyaml/yaml" -) - -type StripCommentsFilter struct{} - -var _ kio.Filter = StripCommentsFilter{} - -func (f StripCommentsFilter) Filter(slice []*yaml.RNode) ([]*yaml.RNode, error) { - for i := range slice { - stripComments(slice[i].YNode()) - } - return slice, nil -} - -func stripComments(node *yaml.Node) { - if node == nil { - return - } - node.HeadComment = "" - node.LineComment = "" - node.FootComment = "" - for i := range node.Content { - stripComments(node.Content[i]) - } -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/ignorefilesmatcher.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/ignorefilesmatcher.go index 0ba3d8382..5ef48d7e3 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/ignorefilesmatcher.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/kio/ignorefilesmatcher.go @@ -86,7 +86,7 @@ func (i *ignoreFilesMatcher) matchFile(path string) bool { return i.matchers[len(i.matchers)-1].matcher.Match(path, false) } -// matchFile checks whether the directory given by the provided path matches +// matchDir checks whether the directory given by the provided path matches // any of the patterns in the .krmignore file for the package. func (i *ignoreFilesMatcher) matchDir(path string) bool { if len(i.matchers) == 0 { diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.go index 49647be4b..421f70f7c 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/openapi/kustomizationapi/swagger.go @@ -64,7 +64,7 @@ func (fi bindataFileInfo) Mode() os.FileMode { return fi.mode } -// Mode return file modify time +// ModTime return file modify time func (fi bindataFileInfo) ModTime() time.Time { return fi.modTime } diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go index 41ee0afc5..aa1c8d4a8 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/openapi/openapi.go @@ -182,7 +182,7 @@ type ResourceSchema struct { Schema *spec.Schema } -// IsEmpty returns true if the ResourceSchema is empty +// IsMissingOrNull returns true if the ResourceSchema is missing or null func (rs *ResourceSchema) IsMissingOrNull() bool { if rs == nil || rs.Schema == nil { return true diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/runfn/runfn.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/runfn/runfn.go index 6b36d7d3a..777d3f87c 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/runfn/runfn.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/runfn/runfn.go @@ -19,7 +19,6 @@ import ( "sigs.k8s.io/kustomize/kyaml/fn/runtime/container" "sigs.k8s.io/kustomize/kyaml/fn/runtime/exec" "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil" - "sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/kio/kioutil" "sigs.k8s.io/kustomize/kyaml/yaml" @@ -61,9 +60,6 @@ type RunFns struct { // and only use explicit sources NoFunctionsFromInput *bool - // EnableStarlark will enable functions run as starlark scripts - EnableStarlark bool - // EnableExec will enable exec functions EnableExec bool @@ -209,8 +205,6 @@ func (r RunFns) runFunctions( identifier = filter.Image case *exec.Filter: identifier = filter.Path - case *starlark.Filter: - identifier = filter.String() default: identifier = "unknown-type function" } @@ -496,41 +490,6 @@ func (r *RunFns) ffp(spec runtimeutil.FunctionSpec, api *yaml.RNode, currentUser cf.Exec.DeferFailure = spec.DeferFailure return cf, nil } - if r.EnableStarlark && (spec.Starlark.Path != "" || spec.Starlark.URL != "") { - // the script path is relative to the function config file - m, err := api.GetMeta() - if err != nil { - return nil, errors.Wrap(err) - } - - var p string - if spec.Starlark.Path != "" { - pathAnno := m.Annotations[kioutil.PathAnnotation] - if pathAnno == "" { - pathAnno = m.Annotations[kioutil.LegacyPathAnnotation] - } - p = filepath.ToSlash(path.Clean(pathAnno)) - - spec.Starlark.Path = filepath.ToSlash(path.Clean(spec.Starlark.Path)) - if filepath.IsAbs(spec.Starlark.Path) || path.IsAbs(spec.Starlark.Path) { - return nil, errors.Errorf( - "absolute function path %s not allowed", spec.Starlark.Path) - } - if strings.HasPrefix(spec.Starlark.Path, "..") { - return nil, errors.Errorf( - "function path %s not allowed to start with ../", spec.Starlark.Path) - } - p = filepath.ToSlash(filepath.Join(r.Path, filepath.Dir(p), spec.Starlark.Path)) - } - - sf := &starlark.Filter{Name: spec.Starlark.Name, Path: p, URL: spec.Starlark.URL} - - sf.FunctionConfig = api - sf.GlobalScope = r.GlobalScope - sf.ResultsFile = resultsFile - sf.DeferFailure = spec.DeferFailure - return sf, nil - } if r.EnableExec && spec.Exec.Path != "" { ef := &exec.Filter{ diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go index 12c72ae83..5908cd7bd 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/alias.go @@ -20,7 +20,7 @@ const ( BareSeqNodeWrappingKey = "bareSeqNodeWrappingKey" ) -// SeqIndentType holds the indentation style for sequence nodes +// SequenceIndentStyle holds the indentation style for sequence nodes type SequenceIndentStyle string // EncoderOptions are options that can be used to configure the encoder, diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go index e80eb48bf..e0802a897 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/fns.go @@ -724,8 +724,14 @@ func (s FieldSetter) Filter(rn *RNode) (*RNode, error) { return rn, nil } - // Clear the field if it is empty, or explicitly null - if s.Value == nil || s.Value.IsTaggedNull() { + // Clearing nil fields: + // 1. Clear any fields with no value + // 2. Clear any "null" YAML fields unless we explicitly want to keep them + // This is to balance + // 1. Persisting 'null' values passed by the user (see issue #4628) + // 2. Avoiding producing noisy documents that add any field defaulting to + // 'nil' even if they weren't present in the source document + if s.Value == nil || (s.Value.IsTaggedNull() && !s.Value.ShouldKeep) { return rn.Pipe(Clear(s.Name)) } diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge2/merge2.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge2/merge2.go index 8b328ab9d..3b23019e1 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge2/merge2.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge2/merge2.go @@ -45,9 +45,9 @@ func MergeStrings(srcStr, destStr string, infer bool, mergeOptions yaml.MergeOpt } type Merger struct { - // for forwards compatibility when new functions are added to the interface } +// for forwards compatibility when new functions are added to the interface var _ walk.Visitor = Merger{} func (m Merger) VisitMap(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.RNode, error) { @@ -66,8 +66,7 @@ func (m Merger) VisitMap(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.R // If Origin is missing, preserve explicitly set null in Dest ("null", "~", etc) if nodes.Origin().IsNil() && !nodes.Dest().IsNil() && len(nodes.Dest().YNode().Value) > 0 { - // Return a new node so that it won't have a "!!null" tag and therefore won't be cleared. - return yaml.NewScalarRNode(nodes.Dest().YNode().Value), nil + return yaml.MakePersistentNullNode(nodes.Dest().YNode().Value), nil } return nodes.Origin(), nil diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge3/merge3.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge3/merge3.go deleted file mode 100644 index 664270e5b..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge3/merge3.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -// Package merge contains libraries for merging fields from one RNode to another -// RNode -package merge3 - -import ( - "sigs.k8s.io/kustomize/kyaml/yaml" - "sigs.k8s.io/kustomize/kyaml/yaml/walk" -) - -func Merge(dest, original, update *yaml.RNode) (*yaml.RNode, error) { - // if update == nil && original != nil => declarative deletion - - return walk.Walker{ - Visitor: Visitor{}, - VisitKeysAsScalars: true, - Sources: []*yaml.RNode{dest, original, update}}.Walk() -} - -func MergeStrings(dest, original, update string, infer bool) (string, error) { - srcOriginal, err := yaml.Parse(original) - if err != nil { - return "", err - } - srcUpdated, err := yaml.Parse(update) - if err != nil { - return "", err - } - d, err := yaml.Parse(dest) - if err != nil { - return "", err - } - - result, err := walk.Walker{ - InferAssociativeLists: infer, - Visitor: Visitor{}, - VisitKeysAsScalars: true, - Sources: []*yaml.RNode{d, srcOriginal, srcUpdated}}.Walk() - if err != nil { - return "", err - } - return result.String() -} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge3/visitor.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge3/visitor.go deleted file mode 100644 index 978deff0c..000000000 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/merge3/visitor.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package merge3 - -import ( - "sigs.k8s.io/kustomize/kyaml/openapi" - "sigs.k8s.io/kustomize/kyaml/yaml" - "sigs.k8s.io/kustomize/kyaml/yaml/walk" -) - -type ConflictStrategy uint - -const ( - // TODO: Support more strategies - TakeUpdate ConflictStrategy = 1 + iota -) - -type Visitor struct{} - -func (m Visitor) VisitMap(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.RNode, error) { - if nodes.Updated().IsTaggedNull() || nodes.Dest().IsTaggedNull() { - // explicitly cleared from either dest or update - return walk.ClearNode, nil - } - if nodes.Dest() == nil && nodes.Updated() == nil { - // implicitly cleared missing from both dest and update - return walk.ClearNode, nil - } - - if nodes.Dest() == nil { - // not cleared, but missing from the dest - // initialize a new value that can be recursively merged - return yaml.NewRNode(&yaml.Node{Kind: yaml.MappingNode}), nil - } - - // recursively merge the dest with the original and updated - return nodes.Dest(), nil -} - -func (m Visitor) visitAList(nodes walk.Sources, _ *openapi.ResourceSchema) (*yaml.RNode, error) { - if yaml.IsMissingOrNull(nodes.Updated()) && !yaml.IsMissingOrNull(nodes.Origin()) { - // implicitly cleared from update -- element was deleted - return walk.ClearNode, nil - } - if yaml.IsMissingOrNull(nodes.Dest()) { - // not cleared, but missing from the dest - // initialize a new value that can be recursively merged - return yaml.NewRNode(&yaml.Node{Kind: yaml.SequenceNode}), nil - } - - // recursively merge the dest with the original and updated - return nodes.Dest(), nil -} - -func (m Visitor) VisitScalar(nodes walk.Sources, s *openapi.ResourceSchema) (*yaml.RNode, error) { - if nodes.Updated().IsTaggedNull() || nodes.Dest().IsTaggedNull() { - // explicitly cleared from either dest or update - return nil, nil - } - if yaml.IsMissingOrNull(nodes.Updated()) != yaml.IsMissingOrNull(nodes.Origin()) { - // value added or removed in update - return nodes.Updated(), nil - } - if yaml.IsMissingOrNull(nodes.Updated()) && yaml.IsMissingOrNull(nodes.Origin()) { - // value added or removed in update - return nodes.Dest(), nil - } - - values, err := m.getStrValues(nodes) - if err != nil { - return nil, err - } - - if (values.Dest == "" || values.Dest == values.Origin) && values.Origin != values.Update { - // if local is nil or is unchanged but there is new update - return nodes.Updated(), nil - } - - if nodes.Updated().YNode().Value != nodes.Origin().YNode().Value { - // value changed in update - return nodes.Updated(), nil - } - - // unchanged between origin and update, keep the dest - return nodes.Dest(), nil -} - -func (m Visitor) visitNAList(nodes walk.Sources) (*yaml.RNode, error) { - if nodes.Updated().IsTaggedNull() || nodes.Dest().IsTaggedNull() { - // explicitly cleared from either dest or update - return walk.ClearNode, nil - } - - if yaml.IsMissingOrNull(nodes.Updated()) != yaml.IsMissingOrNull(nodes.Origin()) { - // value added or removed in update - return nodes.Updated(), nil - } - if yaml.IsMissingOrNull(nodes.Updated()) && yaml.IsMissingOrNull(nodes.Origin()) { - // value not present in source or dest - return nodes.Dest(), nil - } - - // compare origin and update values to see if they have changed - values, err := m.getStrValues(nodes) - if err != nil { - return nil, err - } - if values.Update != values.Origin { - // value changed in update - return nodes.Updated(), nil - } - - // unchanged between origin and update, keep the dest - return nodes.Dest(), nil -} - -func (m Visitor) VisitList(nodes walk.Sources, s *openapi.ResourceSchema, kind walk.ListKind) (*yaml.RNode, error) { - if kind == walk.AssociativeList { - return m.visitAList(nodes, s) - } - // non-associative list - return m.visitNAList(nodes) -} - -func (m Visitor) getStrValues(nodes walk.Sources) (strValues, error) { - var uStr, oStr, dStr string - var err error - if nodes.Updated() != nil && nodes.Updated().YNode() != nil { - s := nodes.Updated().YNode().Style - defer func() { - nodes.Updated().YNode().Style = s - }() - nodes.Updated().YNode().Style = yaml.FlowStyle | yaml.SingleQuotedStyle - uStr, err = nodes.Updated().String() - if err != nil { - return strValues{}, err - } - } - if nodes.Origin() != nil && nodes.Origin().YNode() != nil { - s := nodes.Origin().YNode().Style - defer func() { - nodes.Origin().YNode().Style = s - }() - nodes.Origin().YNode().Style = yaml.FlowStyle | yaml.SingleQuotedStyle - oStr, err = nodes.Origin().String() - if err != nil { - return strValues{}, err - } - } - if nodes.Dest() != nil && nodes.Dest().YNode() != nil { - s := nodes.Dest().YNode().Style - defer func() { - nodes.Dest().YNode().Style = s - }() - nodes.Dest().YNode().Style = yaml.FlowStyle | yaml.SingleQuotedStyle - dStr, err = nodes.Dest().String() - if err != nil { - return strValues{}, err - } - } - - return strValues{Origin: oStr, Update: uStr, Dest: dStr}, nil -} - -type strValues struct { - Origin string - Update string - Dest string -} - -var _ walk.Visitor = Visitor{} diff --git a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go index bf3b5347f..07c782d73 100644 --- a/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go +++ b/tests/vendor/sigs.k8s.io/kustomize/kyaml/yaml/rnode.go @@ -24,6 +24,20 @@ func MakeNullNode() *RNode { return NewRNode(&Node{Tag: NodeTagNull}) } +// MakePersistentNullNode returns an RNode that should be persisted, +// even when merging +func MakePersistentNullNode(value string) *RNode { + n := NewRNode( + &Node{ + Tag: NodeTagNull, + Value: value, + Kind: yaml.ScalarNode, + }, + ) + n.ShouldKeep = true + return n +} + // IsMissingOrNull is true if the RNode is nil or explicitly tagged null. // TODO: make this a method on RNode. func IsMissingOrNull(node *RNode) bool { @@ -214,6 +228,9 @@ type RNode struct { // object root: object root value *yaml.Node + // Whether we should keep this node, even if otherwise we would clear it + ShouldKeep bool + Match []string } diff --git a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/clientset.go b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/clientset.go index 9891a3436..44f129201 100644 --- a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/clientset.go +++ b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/clientset.go @@ -19,8 +19,8 @@ limitations under the License. package versioned import ( - "fmt" - "net/http" + fmt "fmt" + http "net/http" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" diff --git a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go index 37a6f340a..4776a6c83 100644 --- a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go +++ b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go @@ -19,11 +19,11 @@ limitations under the License. package v1alpha1 import ( - "net/http" + http "net/http" rest "k8s.io/client-go/rest" - "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/scheme" - v1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1" + scheme "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/scheme" + nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1" ) type NfdV1alpha1Interface interface { @@ -95,10 +95,10 @@ func New(c rest.Interface) *NfdV1alpha1Client { } func setConfigDefaults(config *rest.Config) error { - gv := v1alpha1.SchemeGroupVersion + gv := nfdv1alpha1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" - config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion() if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() diff --git a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeature.go b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeature.go index f159be867..70b854046 100644 --- a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeature.go +++ b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeature.go @@ -19,15 +19,14 @@ limitations under the License. package v1alpha1 import ( - "context" - "time" + context "context" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" scheme "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/scheme" - v1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1" + nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1" ) // NodeFeaturesGetter has a method to return a NodeFeatureInterface. @@ -38,141 +37,32 @@ type NodeFeaturesGetter interface { // NodeFeatureInterface has methods to work with NodeFeature resources. type NodeFeatureInterface interface { - Create(ctx context.Context, nodeFeature *v1alpha1.NodeFeature, opts v1.CreateOptions) (*v1alpha1.NodeFeature, error) - Update(ctx context.Context, nodeFeature *v1alpha1.NodeFeature, opts v1.UpdateOptions) (*v1alpha1.NodeFeature, error) + Create(ctx context.Context, nodeFeature *nfdv1alpha1.NodeFeature, opts v1.CreateOptions) (*nfdv1alpha1.NodeFeature, error) + Update(ctx context.Context, nodeFeature *nfdv1alpha1.NodeFeature, opts v1.UpdateOptions) (*nfdv1alpha1.NodeFeature, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.NodeFeature, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.NodeFeatureList, error) + Get(ctx context.Context, name string, opts v1.GetOptions) (*nfdv1alpha1.NodeFeature, error) + List(ctx context.Context, opts v1.ListOptions) (*nfdv1alpha1.NodeFeatureList, error) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeature, err error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *nfdv1alpha1.NodeFeature, err error) NodeFeatureExpansion } // nodeFeatures implements NodeFeatureInterface type nodeFeatures struct { - client rest.Interface - ns string + *gentype.ClientWithList[*nfdv1alpha1.NodeFeature, *nfdv1alpha1.NodeFeatureList] } // newNodeFeatures returns a NodeFeatures func newNodeFeatures(c *NfdV1alpha1Client, namespace string) *nodeFeatures { return &nodeFeatures{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*nfdv1alpha1.NodeFeature, *nfdv1alpha1.NodeFeatureList]( + "nodefeatures", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *nfdv1alpha1.NodeFeature { return &nfdv1alpha1.NodeFeature{} }, + func() *nfdv1alpha1.NodeFeatureList { return &nfdv1alpha1.NodeFeatureList{} }, + ), } } - -// Get takes name of the nodeFeature, and returns the corresponding nodeFeature object, and an error if there is any. -func (c *nodeFeatures) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NodeFeature, err error) { - result = &v1alpha1.NodeFeature{} - err = c.client.Get(). - Namespace(c.ns). - Resource("nodefeatures"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of NodeFeatures that match those selectors. -func (c *nodeFeatures) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NodeFeatureList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.NodeFeatureList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("nodefeatures"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested nodeFeatures. -func (c *nodeFeatures) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("nodefeatures"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a nodeFeature and creates it. Returns the server's representation of the nodeFeature, and an error, if there is any. -func (c *nodeFeatures) Create(ctx context.Context, nodeFeature *v1alpha1.NodeFeature, opts v1.CreateOptions) (result *v1alpha1.NodeFeature, err error) { - result = &v1alpha1.NodeFeature{} - err = c.client.Post(). - Namespace(c.ns). - Resource("nodefeatures"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nodeFeature). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a nodeFeature and updates it. Returns the server's representation of the nodeFeature, and an error, if there is any. -func (c *nodeFeatures) Update(ctx context.Context, nodeFeature *v1alpha1.NodeFeature, opts v1.UpdateOptions) (result *v1alpha1.NodeFeature, err error) { - result = &v1alpha1.NodeFeature{} - err = c.client.Put(). - Namespace(c.ns). - Resource("nodefeatures"). - Name(nodeFeature.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nodeFeature). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the nodeFeature and deletes it. Returns an error if one occurs. -func (c *nodeFeatures) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("nodefeatures"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *nodeFeatures) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("nodefeatures"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched nodeFeature. -func (c *nodeFeatures) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeature, err error) { - result = &v1alpha1.NodeFeature{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("nodefeatures"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go index a988f3c8e..cdee1eb7b 100644 --- a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go +++ b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go @@ -19,15 +19,14 @@ limitations under the License. package v1alpha1 import ( - "context" - "time" + context "context" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" scheme "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/scheme" - v1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1" + nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1" ) // NodeFeatureGroupsGetter has a method to return a NodeFeatureGroupInterface. @@ -38,158 +37,34 @@ type NodeFeatureGroupsGetter interface { // NodeFeatureGroupInterface has methods to work with NodeFeatureGroup resources. type NodeFeatureGroupInterface interface { - Create(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.CreateOptions) (*v1alpha1.NodeFeatureGroup, error) - Update(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.UpdateOptions) (*v1alpha1.NodeFeatureGroup, error) - UpdateStatus(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.UpdateOptions) (*v1alpha1.NodeFeatureGroup, error) + Create(ctx context.Context, nodeFeatureGroup *nfdv1alpha1.NodeFeatureGroup, opts v1.CreateOptions) (*nfdv1alpha1.NodeFeatureGroup, error) + Update(ctx context.Context, nodeFeatureGroup *nfdv1alpha1.NodeFeatureGroup, opts v1.UpdateOptions) (*nfdv1alpha1.NodeFeatureGroup, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, nodeFeatureGroup *nfdv1alpha1.NodeFeatureGroup, opts v1.UpdateOptions) (*nfdv1alpha1.NodeFeatureGroup, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.NodeFeatureGroup, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.NodeFeatureGroupList, error) + Get(ctx context.Context, name string, opts v1.GetOptions) (*nfdv1alpha1.NodeFeatureGroup, error) + List(ctx context.Context, opts v1.ListOptions) (*nfdv1alpha1.NodeFeatureGroupList, error) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureGroup, err error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *nfdv1alpha1.NodeFeatureGroup, err error) NodeFeatureGroupExpansion } // nodeFeatureGroups implements NodeFeatureGroupInterface type nodeFeatureGroups struct { - client rest.Interface - ns string + *gentype.ClientWithList[*nfdv1alpha1.NodeFeatureGroup, *nfdv1alpha1.NodeFeatureGroupList] } // newNodeFeatureGroups returns a NodeFeatureGroups func newNodeFeatureGroups(c *NfdV1alpha1Client, namespace string) *nodeFeatureGroups { return &nodeFeatureGroups{ - client: c.RESTClient(), - ns: namespace, + gentype.NewClientWithList[*nfdv1alpha1.NodeFeatureGroup, *nfdv1alpha1.NodeFeatureGroupList]( + "nodefeaturegroups", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *nfdv1alpha1.NodeFeatureGroup { return &nfdv1alpha1.NodeFeatureGroup{} }, + func() *nfdv1alpha1.NodeFeatureGroupList { return &nfdv1alpha1.NodeFeatureGroupList{} }, + ), } } - -// Get takes name of the nodeFeatureGroup, and returns the corresponding nodeFeatureGroup object, and an error if there is any. -func (c *nodeFeatureGroups) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NodeFeatureGroup, err error) { - result = &v1alpha1.NodeFeatureGroup{} - err = c.client.Get(). - Namespace(c.ns). - Resource("nodefeaturegroups"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of NodeFeatureGroups that match those selectors. -func (c *nodeFeatureGroups) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NodeFeatureGroupList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.NodeFeatureGroupList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("nodefeaturegroups"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested nodeFeatureGroups. -func (c *nodeFeatureGroups) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("nodefeaturegroups"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a nodeFeatureGroup and creates it. Returns the server's representation of the nodeFeatureGroup, and an error, if there is any. -func (c *nodeFeatureGroups) Create(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.CreateOptions) (result *v1alpha1.NodeFeatureGroup, err error) { - result = &v1alpha1.NodeFeatureGroup{} - err = c.client.Post(). - Namespace(c.ns). - Resource("nodefeaturegroups"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nodeFeatureGroup). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a nodeFeatureGroup and updates it. Returns the server's representation of the nodeFeatureGroup, and an error, if there is any. -func (c *nodeFeatureGroups) Update(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.UpdateOptions) (result *v1alpha1.NodeFeatureGroup, err error) { - result = &v1alpha1.NodeFeatureGroup{} - err = c.client.Put(). - Namespace(c.ns). - Resource("nodefeaturegroups"). - Name(nodeFeatureGroup.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nodeFeatureGroup). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *nodeFeatureGroups) UpdateStatus(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.UpdateOptions) (result *v1alpha1.NodeFeatureGroup, err error) { - result = &v1alpha1.NodeFeatureGroup{} - err = c.client.Put(). - Namespace(c.ns). - Resource("nodefeaturegroups"). - Name(nodeFeatureGroup.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nodeFeatureGroup). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the nodeFeatureGroup and deletes it. Returns an error if one occurs. -func (c *nodeFeatureGroups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("nodefeaturegroups"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *nodeFeatureGroups) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("nodefeaturegroups"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched nodeFeatureGroup. -func (c *nodeFeatureGroups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureGroup, err error) { - result = &v1alpha1.NodeFeatureGroup{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("nodefeaturegroups"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturerule.go b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturerule.go index 843c13768..cf0719ad1 100644 --- a/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturerule.go +++ b/tests/vendor/sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturerule.go @@ -19,15 +19,14 @@ limitations under the License. package v1alpha1 import ( - "context" - "time" + context "context" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" + gentype "k8s.io/client-go/gentype" scheme "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/scheme" - v1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1" + nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1" ) // NodeFeatureRulesGetter has a method to return a NodeFeatureRuleInterface. @@ -38,131 +37,32 @@ type NodeFeatureRulesGetter interface { // NodeFeatureRuleInterface has methods to work with NodeFeatureRule resources. type NodeFeatureRuleInterface interface { - Create(ctx context.Context, nodeFeatureRule *v1alpha1.NodeFeatureRule, opts v1.CreateOptions) (*v1alpha1.NodeFeatureRule, error) - Update(ctx context.Context, nodeFeatureRule *v1alpha1.NodeFeatureRule, opts v1.UpdateOptions) (*v1alpha1.NodeFeatureRule, error) + Create(ctx context.Context, nodeFeatureRule *nfdv1alpha1.NodeFeatureRule, opts v1.CreateOptions) (*nfdv1alpha1.NodeFeatureRule, error) + Update(ctx context.Context, nodeFeatureRule *nfdv1alpha1.NodeFeatureRule, opts v1.UpdateOptions) (*nfdv1alpha1.NodeFeatureRule, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.NodeFeatureRule, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.NodeFeatureRuleList, error) + Get(ctx context.Context, name string, opts v1.GetOptions) (*nfdv1alpha1.NodeFeatureRule, error) + List(ctx context.Context, opts v1.ListOptions) (*nfdv1alpha1.NodeFeatureRuleList, error) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureRule, err error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *nfdv1alpha1.NodeFeatureRule, err error) NodeFeatureRuleExpansion } // nodeFeatureRules implements NodeFeatureRuleInterface type nodeFeatureRules struct { - client rest.Interface + *gentype.ClientWithList[*nfdv1alpha1.NodeFeatureRule, *nfdv1alpha1.NodeFeatureRuleList] } // newNodeFeatureRules returns a NodeFeatureRules func newNodeFeatureRules(c *NfdV1alpha1Client) *nodeFeatureRules { return &nodeFeatureRules{ - client: c.RESTClient(), + gentype.NewClientWithList[*nfdv1alpha1.NodeFeatureRule, *nfdv1alpha1.NodeFeatureRuleList]( + "nodefeaturerules", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *nfdv1alpha1.NodeFeatureRule { return &nfdv1alpha1.NodeFeatureRule{} }, + func() *nfdv1alpha1.NodeFeatureRuleList { return &nfdv1alpha1.NodeFeatureRuleList{} }, + ), } } - -// Get takes name of the nodeFeatureRule, and returns the corresponding nodeFeatureRule object, and an error if there is any. -func (c *nodeFeatureRules) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NodeFeatureRule, err error) { - result = &v1alpha1.NodeFeatureRule{} - err = c.client.Get(). - Resource("nodefeaturerules"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of NodeFeatureRules that match those selectors. -func (c *nodeFeatureRules) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NodeFeatureRuleList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.NodeFeatureRuleList{} - err = c.client.Get(). - Resource("nodefeaturerules"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested nodeFeatureRules. -func (c *nodeFeatureRules) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Resource("nodefeaturerules"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a nodeFeatureRule and creates it. Returns the server's representation of the nodeFeatureRule, and an error, if there is any. -func (c *nodeFeatureRules) Create(ctx context.Context, nodeFeatureRule *v1alpha1.NodeFeatureRule, opts v1.CreateOptions) (result *v1alpha1.NodeFeatureRule, err error) { - result = &v1alpha1.NodeFeatureRule{} - err = c.client.Post(). - Resource("nodefeaturerules"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nodeFeatureRule). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a nodeFeatureRule and updates it. Returns the server's representation of the nodeFeatureRule, and an error, if there is any. -func (c *nodeFeatureRules) Update(ctx context.Context, nodeFeatureRule *v1alpha1.NodeFeatureRule, opts v1.UpdateOptions) (result *v1alpha1.NodeFeatureRule, err error) { - result = &v1alpha1.NodeFeatureRule{} - err = c.client.Put(). - Resource("nodefeaturerules"). - Name(nodeFeatureRule.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(nodeFeatureRule). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the nodeFeatureRule and deletes it. Returns an error if one occurs. -func (c *nodeFeatureRules) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Resource("nodefeaturerules"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *nodeFeatureRules) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Resource("nodefeaturerules"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched nodeFeatureRule. -func (c *nodeFeatureRules) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureRule, err error) { - result = &v1alpha1.NodeFeatureRule{} - err = c.client.Patch(pt). - Resource("nodefeaturerules"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -}