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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ orchestrion
coverage/
venv/
.python-version
*.log
73 changes: 73 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

.PHONY: all test format lint build install dd-trace-go test-integration \
dd-trace-go-setup

# Allow overriding via env var `orchestrion_dir` or `ORCHESTRION_DIR`
ORCHESTRION_DIR ?= $(if $(orchestrion_dir),$(orchestrion_dir),$(CURDIR))
DD_TRACE_GO_DIR ?= $(CURDIR)/tmp/dd-trace-go
DDTRACE_INTEGRATION_DIR := $(DD_TRACE_GO_DIR)/internal/orchestrion/_integration

all: build format lint test

.ONESHELL:
test: gotestfmt
set -euo pipefail
go test -json -v ./... 2>&1 | tee ./gotest.log | gotestfmt

format:
golangci-lint fmt

lint:
golangci-lint run

build:
go build -o bin/orchestrion main.go

install:
go install .

dd-trace-go:
@mkdir -p ./tmp
@if [ ! -d "$(DD_TRACE_GO_DIR)/.git" ]; then \
echo "Cloning dd-trace-go (shallow) into $(DD_TRACE_GO_DIR)"; \
git clone --depth 1 --no-tags [email protected]:DataDog/dd-trace-go.git "$(DD_TRACE_GO_DIR)"; \
else \
echo "dd-trace-go already exists at $(DD_TRACE_GO_DIR)"; \
fi

.ONESHELL:
dd-trace-go-setup: dd-trace-go
@echo "Using orchestrion from: $(ORCHESTRION_DIR)"
@echo "Integration dir: $(DDTRACE_INTEGRATION_DIR)"
cd $(DDTRACE_INTEGRATION_DIR)
go mod edit -replace "github.com/DataDog/orchestrion=$(ORCHESTRION_DIR)"
go mod tidy

# Integration with dd-trace-go using orchestrion
#
# The following Make targets automate the manual steps below:
#
# console
# $ git clone github.com:DataDog/dd-trace-go # Clone the DataDog/dd-trace-go repository
# $ cd dd-trace-go/internal/orchestrion/_integration # Move into the integration tests directory
# $ go mod edit \ # Use the local copy of orchestrion
# -replace "github.com/DataDog/orchestrion=>${orchestrion_dir}"
# $ go mod tidy # Make sure go.mod & go.sum are up-to-date
# $ go run github.com/DataDog/orchestrion \ # Run integration test suite with orchestrion
# go test -shuffle=on ./...
#
# Usage examples:
# make test-integration # run tests (expects setup done)
# make dd-trace-go-setup # clone + set replace only


.ONESHELL:
test-integration: dd-trace-go-setup
cd $(DDTRACE_INTEGRATION_DIR)
go run github.com/DataDog/orchestrion go test -v -shuffle=on -failfast ./... | tee $(ORCHESTRION_DIR)/test-integration.log

gotestfmt:
@if ! command -v gotestfmt >/dev/null 2>&1; then \
echo "Installing gotestfmt..."; \
go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest; \
fi
26 changes: 13 additions & 13 deletions internal/injector/aspect/advice/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ import (
)

type appendArgs struct {
TypeName typed.TypeName
Type typed.Type
Templates []*code.Template
}

// AppendArgs appends arguments of a given type to the end of a function call. All arguments must be
// of the same type, as they may be appended at the tail end of a variadic call.
func AppendArgs(typeName typed.TypeName, templates ...*code.Template) *appendArgs {
return &appendArgs{typeName, templates}
func AppendArgs(typeExpr typed.Type, templates ...*code.Template) *appendArgs {
return &appendArgs{typeExpr, templates}
}

func (a *appendArgs) Apply(ctx context.AdviceContext) (bool, error) {
Expand Down Expand Up @@ -62,12 +62,12 @@ func (a *appendArgs) Apply(ctx context.AdviceContext) (bool, error) {
Params: &dst.FieldList{
List: []*dst.Field{{
Names: []*dst.Ident{dst.NewIdent("opts")},
Type: &dst.Ellipsis{Elt: a.TypeName.AsNode()},
Type: &dst.Ellipsis{Elt: a.Type.AsNode()},
}},
},
Results: &dst.FieldList{
List: []*dst.Field{{
Type: &dst.ArrayType{Elt: a.TypeName.AsNode()},
Type: &dst.ArrayType{Elt: a.Type.AsNode()},
}},
},
},
Expand All @@ -92,7 +92,7 @@ func (a *appendArgs) Apply(ctx context.AdviceContext) (bool, error) {
Ellipsis: true,
}

if importPath := a.TypeName.ImportPath; importPath != "" {
if importPath := a.Type.ImportPath(); importPath != "" {
ctx.AddImport(importPath, inferPkgName(importPath))
}

Expand All @@ -101,7 +101,7 @@ func (a *appendArgs) Apply(ctx context.AdviceContext) (bool, error) {

func (a *appendArgs) AddedImports() []string {
imports := make([]string, 0, len(a.Templates)+1)
if argTypeImportPath := a.TypeName.ImportPath; argTypeImportPath != "" {
if argTypeImportPath := a.Type.ImportPath(); argTypeImportPath != "" {
imports = append(imports, argTypeImportPath)
}
for _, t := range a.Templates {
Expand All @@ -111,7 +111,7 @@ func (a *appendArgs) AddedImports() []string {
}

func (a *appendArgs) Hash(h *fingerprint.Hasher) error {
return h.Named("append-args", a.TypeName, fingerprint.List[*code.Template](a.Templates))
return h.Named("append-args", a.Type, fingerprint.List[*code.Template](a.Templates))
}

type redirectCall struct {
Expand Down Expand Up @@ -160,20 +160,20 @@ func (r *redirectCall) AddedImports() []string {
func init() {
unmarshalers["append-args"] = func(ctx gocontext.Context, node ast.Node) (Advice, error) {
var args struct {
TypeName string `yaml:"type"`
Values []*code.Template `yaml:"values"`
Type string `yaml:"type"`
Values []*code.Template `yaml:"values"`
}

if err := yaml.NodeToValueContext(ctx, node, &args); err != nil {
return nil, err
}

tn, err := typed.NewTypeName(args.TypeName)
t, err := typed.NewType(args.Type)
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid type %q: %w", args.Type, err)
}

return AppendArgs(tn, args.Values...), nil
return AppendArgs(t, args.Values...), nil
}
unmarshalers["replace-function"] = func(ctx gocontext.Context, node ast.Node) (Advice, error) {
var (
Expand Down
4 changes: 2 additions & 2 deletions internal/injector/aspect/advice/call_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
func TestAppendArgs(t *testing.T) {
t.Run("AddedImports", func(t *testing.T) {
type testCase struct {
argType typed.TypeName
argType typed.Type
args []*code.Template
expectedImports []string
}
Expand All @@ -30,7 +30,7 @@ func TestAppendArgs(t *testing.T) {
args: []*code.Template{code.MustTemplate("true", nil, context.GoLangVersion{})},
},
"imports-from-arg-type": {
argType: typed.MustTypeName("*net/http.Request"),
argType: typed.MustType("*net/http.Request"),
args: []*code.Template{code.MustTemplate("true", nil, context.GoLangVersion{})},
expectedImports: []string{"net/http"},
},
Expand Down
14 changes: 7 additions & 7 deletions internal/injector/aspect/advice/code/dot_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func (s signature) LastResultThatImplements(name string) (string, error) {

// Optimization: First, check for an exact match using TypeName parsing, finding the last one.
lastMatchIndex := -1
if tn, err := typed.NewTypeName(name); err == nil {
if tn, err := typed.NewType(name); err == nil {
currentIndex := 0
for _, field := range s.Results.List {
if tn.Matches(field.Type) {
Expand Down Expand Up @@ -274,7 +274,7 @@ func fieldAt(fields *dst.FieldList, index int, use string) (string, error) {
}

func fieldOfType(fields *dst.FieldList, typeName string, use string) (string, error) {
tn, err := typed.NewTypeName(typeName)
t, err := typed.NewType(typeName)
if err != nil {
return "", err
}
Expand All @@ -286,7 +286,7 @@ func fieldOfType(fields *dst.FieldList, typeName string, use string) (string, er

index := 0
for _, field := range fields.List {
if tn.Matches(field.Type) {
if t.Matches(field.Type) {
return fieldAt(fields, index, use)
}

Expand All @@ -310,9 +310,9 @@ func (s signature) FinalResultImplements(interfaceName string) (bool, error) {
lastField := s.Results.List[len(s.Results.List)-1]

// Optimization: First, check for an exact match using TypeName parsing.
// Note: Not using FindMatchingTypeName as we only need to check the last field.
if tn, err := typed.NewTypeName(interfaceName); err == nil {
if tn.Matches(lastField.Type) {
// Note: Not using FindMatchingType as we only need to check the last field.
if t, err := typed.NewType(interfaceName); err == nil {
if t.Matches(lastField.Type) {
return true, nil
}
} // If parsing failed or no match, fall through to type resolution.
Expand All @@ -334,7 +334,7 @@ func findImplementingField(ctx context.AdviceContext, fields *dst.FieldList, int
}

// 1. Check for exact type name match first.
if index, found := typed.FindMatchingTypeName(fields, interfaceName); found {
if index, found := typed.FindMatchingType(fields, interfaceName); found {
return fieldAt(fields, index, fieldKind)
}

Expand Down
19 changes: 10 additions & 9 deletions internal/injector/aspect/advice/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import (

type addStructField struct {
Name string
TypeName typed.TypeName
TypeExpr typed.Type
}

// AddStructField adds a new synthetic field at the tail end of a struct declaration.
func AddStructField(fieldName string, fieldType typed.TypeName) *addStructField {
func AddStructField(fieldName string, fieldType typed.Type) *addStructField {
return &addStructField{fieldName, fieldType}
}

Expand All @@ -44,10 +44,10 @@ func (a *addStructField) Apply(ctx context.AdviceContext) (bool, error) {

typeDef.Fields.List = append(typeDef.Fields.List, &dst.Field{
Names: []*dst.Ident{dst.NewIdent(a.Name)},
Type: a.TypeName.AsNode(),
Type: a.TypeExpr.AsNode(),
})

if importPath := a.TypeName.ImportPath; importPath != "" {
if importPath := a.TypeExpr.ImportPath(); importPath != "" {
// If the type name is qualified, we may need to import the package, too.
_ = ctx.AddImport(importPath, inferPkgName(importPath))
}
Expand All @@ -56,11 +56,11 @@ func (a *addStructField) Apply(ctx context.AdviceContext) (bool, error) {
}

func (a *addStructField) Hash(h *fingerprint.Hasher) error {
return h.Named("add-struct-field", fingerprint.String(a.Name), a.TypeName)
return h.Named("add-struct-field", fingerprint.String(a.Name), a.TypeExpr)
}

func (a *addStructField) AddedImports() []string {
if path := a.TypeName.ImportPath; path != "" {
if path := a.TypeExpr.ImportPath(); path != "" {
return []string{path}
}
return nil
Expand All @@ -76,11 +76,12 @@ func init() {
if err := yaml.NodeToValueContext(ctx, node, &spec); err != nil {
return nil, err
}
tn, err := typed.NewTypeName(spec.Type)
// Use NewType instead of NewNamedType to preserve pointer information
typeExpr, err := typed.NewType(spec.Type)
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid type %q: %w", spec.Type, err)
}

return AddStructField(spec.Name, tn), nil
return AddStructField(spec.Name, typeExpr), nil
}
}
18 changes: 9 additions & 9 deletions internal/injector/aspect/join/declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ func (i *declarationOf) Hash(h *fingerprint.Hasher) error {
}

type valueDeclaration struct {
TypeName typed.TypeName
Type typed.Type
}

func ValueDeclaration(typeName typed.TypeName) *valueDeclaration {
return &valueDeclaration{typeName}
func ValueDeclaration(typeExpr typed.Type) *valueDeclaration {
return &valueDeclaration{Type: typeExpr}
}

func (i *valueDeclaration) PackageMayMatch(ctx *may.PackageContext) may.MatchType {
return ctx.PackageImports(i.TypeName.ImportPath)
return ctx.PackageImports(i.Type.ImportPath())
}

func (*valueDeclaration) FileMayMatch(_ *may.FileContext) may.MatchType {
Expand All @@ -103,18 +103,18 @@ func (i *valueDeclaration) Matches(ctx context.AspectContext) bool {
return false
}

return spec.Type == nil || i.TypeName.Matches(spec.Type)
return spec.Type == nil || i.Type.Matches(spec.Type)
}

func (i *valueDeclaration) ImpliesImported() []string {
if path := i.TypeName.ImportPath; path != "" {
if path := i.Type.ImportPath(); path != "" {
return []string{path}
}
return nil
}

func (i *valueDeclaration) Hash(h *fingerprint.Hasher) error {
return h.Named("value-declaration", i.TypeName)
return h.Named("value-declaration", i.Type)
}

// See: https://regex101.com/r/OXDfJ1/1
Expand All @@ -141,9 +141,9 @@ func init() {
return nil, err
}

tn, err := typed.NewTypeName(typeName)
tn, err := typed.NewType(typeName)
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid type %q: %w", typeName, err)
}

return ValueDeclaration(tn), nil
Expand Down
Loading
Loading