Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 72 additions & 2 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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"])

Expand All @@ -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 -- ...
Expand Down
19 changes: 19 additions & 0 deletions bazel/rules/go_stringer/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -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",
],
)
47 changes: 47 additions & 0 deletions bazel/rules/go_stringer/defs.bzl
Original file line number Diff line number Diff line change
@@ -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),
},
)
172 changes: 172 additions & 0 deletions bazel/rules/go_stringer/gazelle.go
Original file line number Diff line number Diff line change
@@ -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
}
}
10 changes: 10 additions & 0 deletions bazel/rules/go_stringer/stringer_wrapper.sh
Original file line number Diff line number Diff line change
@@ -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"
13 changes: 13 additions & 0 deletions pkg/template/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -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"],
)
Loading
Loading