From 19261b4ffa8414887206e2381f3c6521e53553e7 Mon Sep 17 00:00:00 2001 From: Vasek - Tom C Date: Fri, 20 Dec 2024 16:51:30 +0100 Subject: [PATCH] feat: add basic go integration Signed-off-by: Vasek - Tom C --- magicsdk/magic_sdk/go.mod | 1 + magicsdk/magic_sdk/go.sum | 2 + magicsdk/magic_sdk/integration/go.go | 117 ++++++++++++++++++ magicsdk/magic_sdk/integration/integration.go | 6 + 4 files changed, 126 insertions(+) create mode 100644 magicsdk/magic_sdk/integration/go.go diff --git a/magicsdk/magic_sdk/go.mod b/magicsdk/magic_sdk/go.mod index 2601ec2..1ff42a6 100644 --- a/magicsdk/magic_sdk/go.mod +++ b/magicsdk/magic_sdk/go.mod @@ -34,6 +34,7 @@ require ( go.opentelemetry.io/otel/trace v1.27.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.20.0 golang.org/x/net v0.29.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/magicsdk/magic_sdk/go.sum b/magicsdk/magic_sdk/go.sum index 9b2010f..7317e13 100644 --- a/magicsdk/magic_sdk/go.sum +++ b/magicsdk/magic_sdk/go.sum @@ -71,6 +71,8 @@ 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/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= diff --git a/magicsdk/magic_sdk/integration/go.go b/magicsdk/magic_sdk/integration/go.go new file mode 100644 index 0000000..d788384 --- /dev/null +++ b/magicsdk/magic_sdk/integration/go.go @@ -0,0 +1,117 @@ +package integration + +import ( + "context" + "encoding/json" + "fmt" + + "dagger.io/dagger" + "dagger.io/dagger/dag" + "dagger.io/magicsdk/codebase" + "dagger.io/magicsdk/invocation" + "dagger.io/magicsdk/utils" + "golang.org/x/mod/modfile" +) + +type Go struct { + Dir *dagger.Directory + + version string + supported bool +} + +func GoIntegration(code *codebase.Codebase) (Integration, error) { + gomod, err, exist := code.LookupFile("go.mod") + if err != nil { + return nil, fmt.Errorf("failed to lookup go.mod: %w", err) + } + + if !exist { + return &Go{supported: false}, nil + } + + stat, err := gomod.Stat() + if err != nil { + return nil, fmt.Errorf("failed to get stat on go.mod file") + } + + gomodContent := make([]byte, stat.Size()) + _, err = gomod.Read(gomodContent) + if err != nil { + return nil, fmt.Errorf("failed to read go.mod: %w", err) + } + + modfile, err := modfile.Parse("go.mod", gomodContent, nil) + if err != nil { + return nil, fmt.Errorf("failed to parse go.mod: %w", err) + } + + return &Go{ + version: modfile.Go.Version, + supported: true, + }, nil +} + +func (g *Go) Description() string { + return fmt.Sprintf("Access function to manage your Go project (version %s)", g.version) +} + +func (g *Go) Exist() bool { + return g.supported +} + +func (g *Go) TypeDef() *dagger.TypeDef { + return dag. + TypeDef(). + WithObject("Go"). + WithFunction( + dag.Function("Container", dag.TypeDef().WithObject("Container")). + WithDescription("Create a Golang development container for your project"), + ) +} + +func (g *Go) New(invocation *invocation.Invocation) Integration { + // Workaround to parse argument since `UnmarshalJSON` isn't generated for Dagger type in + // the client library. + // This should be fixed later to integrate a real MagicSDK + var dir *dagger.Directory + + if invocation.InputArgs["dir"] != nil { + dir = utils.LoadDirectoryFromID([]byte(invocation.InputArgs["dir"])) + } + + return &Go{ + Dir: dir, + } +} + +func (g *Go) Container() (*dagger.Container, error) { + return dag. + Container(). + From(fmt.Sprintf("golang:%s-alpine", g.version)). + WithDirectory("/src", g.Dir). + WithWorkdir("/src"), nil +} + +func (g *Go) Invoke(ctx context.Context, invocation *invocation.Invocation) (_ any, err error) { + switch invocation.FnName { + case "Container": + // Workaround to parse argument since `UnmarshalJSON` isn't generated for Dagger type in + // the client library. + // This should be fixed later to integrate a real MagicSDK + var parentMap map[string]interface{} + err = json.Unmarshal(invocation.ParentJSON, &parentMap) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal parent object: %w", err) + } + + parent := Go{ + Dir: dag.LoadDirectoryFromID(dagger.DirectoryID(parentMap["Dir"].(string))), + version: g.version, + } + + return (*Go).Container(&parent) + default: + return nil, fmt.Errorf("unknown function %s", invocation.FnName) + } +} diff --git a/magicsdk/magic_sdk/integration/integration.go b/magicsdk/magic_sdk/integration/integration.go index f21ab0d..8d15c23 100644 --- a/magicsdk/magic_sdk/integration/integration.go +++ b/magicsdk/magic_sdk/integration/integration.go @@ -14,12 +14,17 @@ type Integrations map[string]Integration type Integration interface { Exist() bool + // Description of the integration. Description() string + // New creates a new instance of the integration based on the caller context. New(invocation *invocation.Invocation) Integration + // TypeDef returns the type definition for the integration with + // all functions and fields it provides. TypeDef() *dagger.TypeDef + // Invoke the function of the integration called by the caller. Invoke(ctx context.Context, invocation *invocation.Invocation) (_ any, err error) } @@ -27,6 +32,7 @@ type integrationFunc func(code *codebase.Codebase) (Integration, error) var integrationsFuncs = map[string]integrationFunc{ "Docker": DockerIntegration, + "Go": GoIntegration, } func LoadIntegrations(code *codebase.Codebase) (Integrations, error) {