diff --git a/BUILD.bazel b/BUILD.bazel index 5899d050fb5704..0a9951fd05dc32 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -3,7 +3,7 @@ load("@bazel_lib//lib:write_source_files.bzl", "write_source_file") load("@bazel_skylib//rules:common_settings.bzl", "string_flag") load("@bazel_skylib//rules:run_binary.bzl", "run_binary") -load("@gazelle//:def.bzl", "gazelle") +load("@gazelle//:def.bzl", "gazelle", "gazelle_binary") package(default_visibility = ["//visibility:public"]) @@ -15,16 +15,86 @@ package(default_visibility = ["//visibility:public"]) # gazelle:exclude internal/tools/gotest-custom # gazelle:exclude internal/tools/independent-lint # gazelle:exclude internal/tools/modformatter -# gazelle:exclude pkg +# gazelle:exclude pkg/aggregator +# gazelle:exclude pkg/api +# gazelle:exclude pkg/cli +# gazelle:exclude pkg/cloudfoundry +# gazelle:exclude pkg/clusteragent +# gazelle:exclude pkg/collector +# gazelle:exclude pkg/commonchecks +# gazelle:exclude pkg/compliance +# gazelle:exclude pkg/config +# gazelle:exclude pkg/containerlifecycle +# gazelle:exclude pkg/databasemonitoring +# gazelle:exclude pkg/diagnose +# gazelle:exclude pkg/discovery +# gazelle:exclude pkg/dyninst +# gazelle:exclude pkg/ebpf +# gazelle:exclude pkg/errors +# gazelle:exclude pkg/eventmonitor +# gazelle:exclude pkg/fips +# gazelle:exclude pkg/flare +# gazelle:exclude pkg/fleet +# gazelle:exclude pkg/gohai +# gazelle:exclude pkg/gpu +# gazelle:exclude pkg/hosttags +# gazelle:exclude pkg/inventory +# gazelle:exclude pkg/jmxfetch +# gazelle:exclude pkg/kubestatemetrics +# gazelle:exclude pkg/languagedetection +# gazelle:exclude pkg/logs +# gazelle:exclude pkg/metrics +# gazelle:exclude pkg/network +# gazelle:exclude pkg/networkconfigmanagement +# gazelle:exclude pkg/networkdevice +# gazelle:exclude pkg/networkpath +# gazelle:exclude pkg/obfuscate +# gazelle:exclude pkg/opentelemetry-mapping-go +# gazelle:exclude pkg/orchestrator +# gazelle:exclude pkg/persistentcache +# gazelle:exclude pkg/pidfile +# gazelle:exclude pkg/privateactionrunner +# gazelle:exclude pkg/privileged-logs +# gazelle:exclude pkg/process +# gazelle:exclude pkg/procmgr +# gazelle:exclude pkg/proto +# gazelle:exclude pkg/redact +# gazelle:exclude pkg/remoteconfig +# gazelle:exclude pkg/runtime +# gazelle:exclude pkg/sbom +# gazelle:exclude pkg/security +# gazelle:exclude pkg/serializer +# gazelle:exclude pkg/serverless +# gazelle:exclude pkg/snmp +# gazelle:exclude pkg/ssi +# gazelle:exclude pkg/status +# gazelle:exclude pkg/system-probe +# gazelle:exclude pkg/tagger +# gazelle:exclude pkg/tagset +# gazelle:exclude pkg/telemetry +# gazelle:exclude pkg/trace +# gazelle:exclude pkg/util +# gazelle:exclude pkg/version +# gazelle:exclude pkg/windowsdriver # gazelle:exclude rtloader # gazelle:exclude tasks # gazelle:exclude test # gazelle:exclude tools # gazelle:exclude .gitlab # gazelle:prefix github.com/DataDog/datadog-agent +gazelle_binary( + name = "gazelle_bin", + languages = [ + "@gazelle//language/go", + "@gazelle//language/proto", + "//bazel/rules/go_stringer:gazelle", + ], +) + gazelle( name = "gazelle", args = ["-external=static"], # don't use the network: https://github.com/bazel-contrib/bazel-gazelle/issues/1385 + gazelle = ":gazelle_bin", ) # bazel run //:go -- ... diff --git a/bazel/rules/go_stringer/BUILD.bazel b/bazel/rules/go_stringer/BUILD.bazel new file mode 100644 index 00000000000000..b331ee659524da --- /dev/null +++ b/bazel/rules/go_stringer/BUILD.bazel @@ -0,0 +1,19 @@ +load("@rules_go//go:def.bzl", "go_library") +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") + +sh_binary( + name = "stringer_wrapper", + srcs = ["stringer_wrapper.sh"], + visibility = ["//visibility:public"], +) + +go_library( + name = "gazelle", + srcs = ["gazelle.go"], + importpath = "github.com/DataDog/datadog-agent/bazel/rules/go_stringer", + visibility = ["//visibility:public"], + deps = [ + "@gazelle//language", + "@gazelle//rule", + ], +) diff --git a/bazel/rules/go_stringer/defs.bzl b/bazel/rules/go_stringer/defs.bzl new file mode 100644 index 00000000000000..3005f9cb4d6f9c --- /dev/null +++ b/bazel/rules/go_stringer/defs.bzl @@ -0,0 +1,47 @@ +load("@bazel_lib//lib:run_binary.bzl", "run_binary") +load("@bazel_lib//lib:write_source_files.bzl", "write_source_file") + +_ENV = { + "GO_BIN": "$(execpath @rules_go//go)", + "STRINGER_BIN": "$(execpath @org_golang_x_tools//cmd/stringer)", +} + +def _impl(name, mod, output, src, type, go_tags, linecomment, trimprefix, visibility): + out_new = output + ".new" + args = ["-type", type] + if output != type.split(",")[0].lower() + "_string.go": + args += ["-output", output] + if go_tags: + args += ["-tags", go_tags] + if linecomment: + args.append("-linecomment") + if trimprefix: + args += ["-trimprefix", trimprefix] + run_binary( + name = name + "_gen", + tool = "//bazel/rules/go_stringer:stringer_wrapper", + srcs = [src, "@rules_go//go", "@org_golang_x_tools//cmd/stringer", mod], + outs = [out_new], + args = args, + env = dict( + _ENV, + PKG_SRC = "$(execpath " + str(src) + ")", + STRINGER_OUT = "$(execpath " + out_new + ")", + ), + visibility = ["//visibility:private"], + ) + native.exports_files([output]) + write_source_file(name = name, in_file = ":" + name + "_gen", out_file = output, check_that_out_file_exists = False, visibility = visibility) + +go_stringer = macro( + implementation = _impl, + attrs = { + "mod": attr.label(mandatory = True, configurable = False), + "output": attr.string(mandatory = True, configurable = False), + "src": attr.label(mandatory = True, configurable = False), + "type": attr.string(mandatory = True, configurable = False), + "go_tags": attr.string(configurable = False), + "linecomment": attr.bool(default = False, configurable = False), + "trimprefix": attr.string(configurable = False), + }, +) diff --git a/bazel/rules/go_stringer/gazelle.go b/bazel/rules/go_stringer/gazelle.go new file mode 100644 index 00000000000000..32baa6e737916c --- /dev/null +++ b/bazel/rules/go_stringer/gazelle.go @@ -0,0 +1,172 @@ +// Package stringer is a Gazelle extension that generates go_stringer rules +// from //go:generate stringer directives in Go source files. +package stringer + +import ( + "bufio" + "flag" + "io" + "os" + "path/filepath" + "strings" + + "github.com/bazelbuild/bazel-gazelle/language" + "github.com/bazelbuild/bazel-gazelle/rule" +) + +// NewLanguage is called by Gazelle to instantiate this extension. +func NewLanguage() language.Language { + return &lang{} +} + +type lang struct { + language.BaseLang +} + +func (*lang) Name() string { return "stringer" } + +func (*lang) Kinds() map[string]rule.KindInfo { + return map[string]rule.KindInfo{ + "go_stringer": { + MatchAttrs: []string{"output"}, + NonEmptyAttrs: map[string]bool{"src": true, "type": true, "mod": true, "output": true}, + MergeableAttrs: map[string]bool{}, + }, + } +} + +func (*lang) Loads() []rule.LoadInfo { + return []rule.LoadInfo{{ + Name: "//bazel/rules/go_stringer:defs.bzl", + Symbols: []string{"go_stringer"}, + }} +} + +func (*lang) GenerateRules(args language.GenerateArgs) language.GenerateResult { + mod := findGomod(args.Config.RepoRoot, args.Dir) + var rules []*rule.Rule + + for _, f := range args.RegularFiles { + if !strings.HasSuffix(f, ".go") { + continue + } + directives, err := parseFile(filepath.Join(args.Dir, f)) + if err != nil { + continue + } + for _, d := range directives { + out := d.output + if out == "" { + out = strings.ToLower(strings.SplitN(d.typ, ",", 2)[0]) + "_string.go" + } + r := rule.NewRule("go_stringer", strings.TrimSuffix(out, ".go")) + r.SetAttr("src", f) + r.SetAttr("type", d.typ) + r.SetAttr("mod", mod) + r.SetAttr("output", out) + if d.trimprefix != "" { + r.SetAttr("trimprefix", d.trimprefix) + } + if d.linecomment { + r.SetAttr("linecomment", true) + } + if d.tags != "" { + r.SetAttr("go_tags", d.tags) + } + rules = append(rules, r) + } + } + if len(rules) == 0 { + return language.GenerateResult{} + } + return language.GenerateResult{ + Gen: rules, + Imports: make([]interface{}, len(rules)), + } +} + +type directive struct { + typ string + output string + trimprefix string + linecomment bool + tags string +} + +func parseFile(path string) ([]directive, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + var result []directive + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + if !strings.HasPrefix(line, "//go:generate ") { + continue + } + if d, ok := parseDirective(strings.TrimPrefix(line, "//go:generate ")); ok { + result = append(result, d) + } + } + return result, scanner.Err() +} + +func parseDirective(s string) (directive, bool) { + fields := strings.Fields(s) + if len(fields) == 0 { + return directive{}, false + } + var args []string + switch { + case isStringerCmd(fields[0]): + args = fields[1:] + case fields[0] == "go" && len(fields) >= 3 && fields[1] == "run" && isStringerCmd(fields[2]): + args = fields[3:] + default: + return directive{}, false + } + + fs := flag.NewFlagSet("stringer", flag.ContinueOnError) + fs.SetOutput(io.Discard) + typ := fs.String("type", "", "") + output := fs.String("output", "", "") + trimprefix := fs.String("trimprefix", "", "") + linecomment := fs.Bool("linecomment", false, "") + tags := fs.String("tags", "", "") + if err := fs.Parse(args); err != nil || *typ == "" { + return directive{}, false + } + return directive{ + typ: *typ, + output: *output, + trimprefix: *trimprefix, + linecomment: *linecomment, + tags: *tags, + }, true +} + +func isStringerCmd(s string) bool { + return s == "stringer" || + strings.HasSuffix(s, "/stringer") || + strings.HasSuffix(s, "/cmd/stringer") +} + +func findGomod(repoRoot, dir string) string { + for d := dir; ; { + if _, err := os.Stat(filepath.Join(d, "go.mod")); err == nil { + rel, err := filepath.Rel(repoRoot, d) + if err != nil || rel == "." { + return "//:go.mod" + } + return "//" + filepath.ToSlash(rel) + ":go.mod" + } + parent := filepath.Dir(d) + if parent == d { + return "//:go.mod" + } + d = parent + } +} diff --git a/bazel/rules/go_stringer/stringer_wrapper.sh b/bazel/rules/go_stringer/stringer_wrapper.sh new file mode 100755 index 00000000000000..76bb28e4610d5f --- /dev/null +++ b/bazel/rules/go_stringer/stringer_wrapper.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +EXECROOT="$PWD" +export PATH="$EXECROOT/$(dirname "$GO_BIN"):$PATH" +export GOWORK=off +export HOME=/tmp + +cd "$EXECROOT/$(dirname "$PKG_SRC")" +"$EXECROOT/$STRINGER_BIN" "$@" +mv "$(basename "$STRINGER_OUT" .new)" "$EXECROOT/$STRINGER_OUT" diff --git a/pkg/template/BUILD.bazel b/pkg/template/BUILD.bazel new file mode 100644 index 00000000000000..465a96f9d0213f --- /dev/null +++ b/pkg/template/BUILD.bazel @@ -0,0 +1,13 @@ +load("@rules_go//go:def.bzl", "go_library") + +exports_files( + ["go.mod"], + visibility = ["//pkg/template:__subpackages__"], +) + +go_library( + name = "template", + srcs = ["docs.go"], + importpath = "github.com/DataDog/datadog-agent/pkg/template", + visibility = ["//visibility:public"], +) diff --git a/pkg/template/html/BUILD.bazel b/pkg/template/html/BUILD.bazel new file mode 100644 index 00000000000000..50c683419f5917 --- /dev/null +++ b/pkg/template/html/BUILD.bazel @@ -0,0 +1,77 @@ +load("@rules_go//go:def.bzl", "go_library") +load("//bazel/rules/go_stringer:defs.bzl", "go_stringer") + +go_stringer( + name = "state_string", + src = "context.go", + mod = "//pkg/template:go.mod", + output = "state_string.go", + type = "state", +) + +go_stringer( + name = "delim_string", + src = "context.go", + mod = "//pkg/template:go.mod", + output = "delim_string.go", + type = "delim", +) + +go_stringer( + name = "urlpart_string", + src = "context.go", + mod = "//pkg/template:go.mod", + output = "urlpart_string.go", + type = "urlPart", +) + +go_stringer( + name = "jsctx_string", + src = "context.go", + mod = "//pkg/template:go.mod", + output = "jsctx_string.go", + type = "jsCtx", +) + +go_stringer( + name = "element_string", + src = "context.go", + mod = "//pkg/template:go.mod", + output = "element_string.go", + type = "element", +) + +go_stringer( + name = "attr_string", + src = "context.go", + mod = "//pkg/template:go.mod", + output = "attr_string.go", + type = "attr", +) + +go_library( + name = "html", + srcs = [ + "attr.go", + "attr_string.go", + "content.go", + "context.go", + "css.go", + "delim_string.go", + "doc.go", + "element_string.go", + "error.go", + "escape.go", + "html.go", + "js.go", + "jsctx_string.go", + "state_string.go", + "template.go", + "transition.go", + "url.go", + "urlpart_string.go", + ], + importpath = "github.com/DataDog/datadog-agent/pkg/template/html", + visibility = ["//visibility:public"], + deps = ["//pkg/template/text"], +) diff --git a/pkg/template/html/attr_string.go b/pkg/template/html/attr_string.go index 51c3f262084c04..b1c77d7e26de93 100644 --- a/pkg/template/html/attr_string.go +++ b/pkg/template/html/attr_string.go @@ -21,8 +21,9 @@ const _attr_name = "attrNoneattrScriptattrScriptTypeattrStyleattrURLattrSrcset" var _attr_index = [...]uint8{0, 8, 18, 32, 41, 48, 58} func (i attr) String() string { - if i >= attr(len(_attr_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_attr_index)-1 { return "attr(" + strconv.FormatInt(int64(i), 10) + ")" } - return _attr_name[_attr_index[i]:_attr_index[i+1]] + return _attr_name[_attr_index[idx]:_attr_index[idx+1]] } diff --git a/pkg/template/html/delim_string.go b/pkg/template/html/delim_string.go index 8d82850223c920..eb0c3922e30129 100644 --- a/pkg/template/html/delim_string.go +++ b/pkg/template/html/delim_string.go @@ -19,8 +19,9 @@ const _delim_name = "delimNonedelimDoubleQuotedelimSingleQuotedelimSpaceOrTagEnd var _delim_index = [...]uint8{0, 9, 25, 41, 59} func (i delim) String() string { - if i >= delim(len(_delim_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_delim_index)-1 { return "delim(" + strconv.FormatInt(int64(i), 10) + ")" } - return _delim_name[_delim_index[i]:_delim_index[i+1]] + return _delim_name[_delim_index[idx]:_delim_index[idx+1]] } diff --git a/pkg/template/html/element_string.go b/pkg/template/html/element_string.go index db286655aa30aa..f381362dd7b0d0 100644 --- a/pkg/template/html/element_string.go +++ b/pkg/template/html/element_string.go @@ -20,8 +20,9 @@ const _element_name = "elementNoneelementScriptelementStyleelementTextareaelemen var _element_index = [...]uint8{0, 11, 24, 36, 51, 63} func (i element) String() string { - if i >= element(len(_element_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_element_index)-1 { return "element(" + strconv.FormatInt(int64(i), 10) + ")" } - return _element_name[_element_index[i]:_element_index[i+1]] + return _element_name[_element_index[idx]:_element_index[idx+1]] } diff --git a/pkg/template/html/jsctx_string.go b/pkg/template/html/jsctx_string.go index 23948934c950a1..103d5559f68ae9 100644 --- a/pkg/template/html/jsctx_string.go +++ b/pkg/template/html/jsctx_string.go @@ -18,8 +18,9 @@ const _jsCtx_name = "jsCtxRegexpjsCtxDivOpjsCtxUnknown" var _jsCtx_index = [...]uint8{0, 11, 21, 33} func (i jsCtx) String() string { - if i >= jsCtx(len(_jsCtx_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_jsCtx_index)-1 { return "jsCtx(" + strconv.FormatInt(int64(i), 10) + ")" } - return _jsCtx_name[_jsCtx_index[i]:_jsCtx_index[i+1]] + return _jsCtx_name[_jsCtx_index[idx]:_jsCtx_index[idx+1]] } diff --git a/pkg/template/html/state_string.go b/pkg/template/html/state_string.go index eed1e8bcc018c2..5488bb028a5e1f 100644 --- a/pkg/template/html/state_string.go +++ b/pkg/template/html/state_string.go @@ -44,8 +44,9 @@ const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValu var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 156, 169, 184, 198, 216, 235, 243, 256, 269, 282, 295, 306, 322, 337, 347, 356} func (i state) String() string { - if i >= state(len(_state_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_state_index)-1 { return "state(" + strconv.FormatInt(int64(i), 10) + ")" } - return _state_name[_state_index[i]:_state_index[i+1]] + return _state_name[_state_index[idx]:_state_index[idx+1]] } diff --git a/pkg/template/html/urlpart_string.go b/pkg/template/html/urlpart_string.go index 7bc957e81d5703..3fa17e7bd8a71d 100644 --- a/pkg/template/html/urlpart_string.go +++ b/pkg/template/html/urlpart_string.go @@ -19,8 +19,9 @@ const _urlPart_name = "urlPartNoneurlPartPreQueryurlPartQueryOrFragurlPartUnknow var _urlPart_index = [...]uint8{0, 11, 26, 44, 58} func (i urlPart) String() string { - if i >= urlPart(len(_urlPart_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_urlPart_index)-1 { return "urlPart(" + strconv.FormatInt(int64(i), 10) + ")" } - return _urlPart_name[_urlPart_index[i]:_urlPart_index[i+1]] + return _urlPart_name[_urlPart_index[idx]:_urlPart_index[idx+1]] } diff --git a/pkg/template/internal/fmtsort/BUILD.bazel b/pkg/template/internal/fmtsort/BUILD.bazel new file mode 100644 index 00000000000000..146fcca1a74cd1 --- /dev/null +++ b/pkg/template/internal/fmtsort/BUILD.bazel @@ -0,0 +1,8 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "fmtsort", + srcs = ["sort.go"], + importpath = "github.com/DataDog/datadog-agent/pkg/template/internal/fmtsort", + visibility = ["//pkg/template:__subpackages__"], +) diff --git a/pkg/template/text/BUILD.bazel b/pkg/template/text/BUILD.bazel new file mode 100644 index 00000000000000..3cc2aab8f892ae --- /dev/null +++ b/pkg/template/text/BUILD.bazel @@ -0,0 +1,16 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "text", + srcs = [ + "doc.go", + "exec.go", + "funcs.go", + "helper.go", + "option.go", + "template.go", + ], + importpath = "github.com/DataDog/datadog-agent/pkg/template/text", + visibility = ["//visibility:public"], + deps = ["//pkg/template/internal/fmtsort"], +)