Skip to content

Commit

Permalink
Merge pull request #97 from grafana/cgo-support
Browse files Browse the repository at this point in the history
Cgo support
  • Loading branch information
pablochacin authored Jan 16, 2025
2 parents 3818e82 + a755eae commit 245ffca
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 47 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,8 @@ For example
}
}

Note: The build server does not support CGO_ENABLE when building binaries
due to this issue: https://github.com/grafana/k6build/issues/37
use --enable-cgo=true to enable CGO support
Note: The build server disables CGO by default but enables it when a dependency requires it.
use --enable-cgo=true to enable CGO support by default.


```
Expand Down
5 changes: 2 additions & 3 deletions cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,8 @@ For example
}
}
Note: The build server does not support CGO_ENABLE when building binaries
due to this issue: https://github.com/grafana/k6build/issues/37
use --enable-cgo=true to enable CGO support
Note: The build server disables CGO by default but enables it when a dependency requires it.
use --enable-cgo=true to enable CGO support by default.
`

example = `
Expand Down
67 changes: 38 additions & 29 deletions pkg/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,14 @@ type Config struct {

// Builder implements the BuildService interface
type Builder struct {
allowBuildSemvers bool
catalog catalog.Catalog
builder k6foundry.Builder
store store.ObjectStore
mutexes sync.Map
opts Opts
catalog catalog.Catalog
store store.ObjectStore
mutexes sync.Map
}

// New returns a new instance of Builder given a BuilderConfig
func New(ctx context.Context, config Config) (*Builder, error) {
func New(_ context.Context, config Config) (*Builder, error) {
if config.Catalog == nil {
return nil, k6build.NewWrappedError(ErrInitializingBuilder, errors.New("catalog cannot be nil"))
}
Expand All @@ -76,27 +75,10 @@ func New(ctx context.Context, config Config) (*Builder, error) {
return nil, k6build.NewWrappedError(ErrInitializingBuilder, errors.New("store cannot be nil"))
}

builderOpts := k6foundry.NativeBuilderOpts{
GoOpts: k6foundry.GoOpts{
Env: config.Opts.Env,
CopyGoEnv: config.Opts.CopyGoEnv,
},
}
if config.Opts.Verbose {
builderOpts.Stdout = os.Stdout
builderOpts.Stderr = os.Stderr
}

builder, err := k6foundry.NewNativeBuilder(ctx, builderOpts)
if err != nil {
return nil, k6build.NewWrappedError(ErrInitializingBuilder, err)
}

return &Builder{
allowBuildSemvers: config.Opts.AllowBuildSemvers,
catalog: config.Catalog,
builder: builder,
store: config.Store,
catalog: config.Catalog,
opts: config.Opts,
store: config.Store,
}, nil
}

Expand Down Expand Up @@ -127,7 +109,7 @@ func (b *Builder) Build( //nolint:funlen
return k6build.Artifact{}, err
}
if buildMetadata != "" {
if !b.allowBuildSemvers {
if !b.opts.AllowBuildSemvers {
return k6build.Artifact{}, k6build.NewWrappedError(ErrInvalidParameters, ErrBuildSemverNotAllowed)
}
k6Mod = catalog.Module{Path: k6Path, Version: buildMetadata}
Expand All @@ -140,13 +122,15 @@ func (b *Builder) Build( //nolint:funlen
resolved[k6Dep] = k6Mod.Version

mods := []k6foundry.Module{}
cgoEnabled := false
for _, d := range deps {
m, modErr := b.catalog.Resolve(ctx, catalog.Dependency{Name: d.Name, Constrains: d.Constraints})
if modErr != nil {
return k6build.Artifact{}, k6build.NewWrappedError(ErrInvalidParameters, modErr)
}
mods = append(mods, k6foundry.Module{Path: m.Path, Version: m.Version})
resolved[d.Name] = m.Version
cgoEnabled = cgoEnabled || m.Cgo
}

// generate id form sorted list of dependencies
Expand Down Expand Up @@ -176,8 +160,33 @@ func (b *Builder) Build( //nolint:funlen
return k6build.Artifact{}, k6build.NewWrappedError(ErrAccessingArtifact, err)
}

// set CGO_ENABLED if any of the dependencies require it
env := b.opts.Env
if cgoEnabled {
if env == nil {
env = map[string]string{}
}
env["CGO_ENABLED"] = "1"
}

builderOpts := k6foundry.NativeBuilderOpts{
GoOpts: k6foundry.GoOpts{
Env: env,
CopyGoEnv: b.opts.CopyGoEnv,
},
}
if b.opts.Verbose {
builderOpts.Stdout = os.Stdout
builderOpts.Stderr = os.Stderr
}

builder, err := k6foundry.NewNativeBuilder(ctx, builderOpts)
if err != nil {
return k6build.Artifact{}, k6build.NewWrappedError(ErrInitializingBuilder, err)
}

artifactBuffer := &bytes.Buffer{}
buildInfo, err := b.builder.Build(ctx, buildPlatform, k6Mod.Version, mods, []string{}, artifactBuffer)
buildInfo, err := builder.Build(ctx, buildPlatform, k6Mod.Version, mods, []string{}, artifactBuffer)
if err != nil {
return k6build.Artifact{}, k6build.NewWrappedError(ErrAccessingArtifact, err)
}
Expand Down Expand Up @@ -205,7 +214,7 @@ func (b *Builder) Build( //nolint:funlen
// lockArtifact obtains a mutex used to prevent concurrent builds of the same artifact and
// returns a function that will unlock the mutex associated to the given id in the object store.
// The lock is also removed from the map. Subsequent calls will get another lock on the same
// id but this is safe as the object should already be in the object strore and no further
// id but this is safe as the object should already be in the object store and no further
// builds are needed.
func (b *Builder) lockArtifact(id string) func() {
value, _ := b.mutexes.LoadOrStore(id, &sync.Mutex{})
Expand Down
18 changes: 13 additions & 5 deletions pkg/catalog/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,27 @@
//
// The catalog is a json file with the following schema:
//
// {
// "<dependency>": {"module": "<go module path>", "versions": ["<version>", "<version>", ... "<version>"]}
// }
// {
// "<dependency>": {
// "module": "<module path>",
// "versions": ["<version>", "<version>", ... "<version>"],
// "cgo": <bool>
// },
// }
//
// where:
// <dependency>: is the import path for the dependency
// module: is the path to the go module that implements the dependency
// versions: is the list of supported versions
// cgo: is a boolean that indicates if the module requires cgo
//
// Example:
//
// {
// "k6": {"module": "go.k6.io/k6", "versions": ["v0.50.0", "v0.51.0"]},
// "k6/x/kubernetes": {"module": "github.com/grafana/xk6-kubernetes", "versions": ["v0.8.0","v0.9.0"]},
// "k6/x/output-kafka": {"module": "github.com/grafana/xk6-output-kafka", "versions": ["v0.7.0"]}
// "k6/x/output-kafka": {"module": "github.com/grafana/xk6-output-kafka", "versions": ["v0.7.0"]},
// "k6/x/xk6-sql-driver-sqlite3": {"module": "github.com/grafana/xk6-sql", "cgo": true, "versions": ["v0.1.0"]}
// }
package catalog

Expand Down Expand Up @@ -68,6 +74,7 @@ type Dependency struct {
type Module struct {
Path string `json:"path,omitempty"`
Version string `json:"version,omitempty"`
Cgo bool `json:"cgo,omitempty"`
}

// Catalog defines the interface of the extension catalog service
Expand All @@ -80,6 +87,7 @@ type Catalog interface {
type entry struct {
Module string `json:"module,omitempty"`
Versions []string `json:"versions,omitempty"`
Cgo bool `json:"cgo,omitempty"`
}

type catalog struct {
Expand Down Expand Up @@ -191,7 +199,7 @@ func (c catalog) Resolve(ctx context.Context, dep Dependency) (Module, error) {
sort.Sort(sort.Reverse(semver.Collection(versions)))
for _, v := range versions {
if constrain.Check(v) {
return Module{Path: entry.Module, Version: v.Original()}, nil
return Module{Path: entry.Module, Version: v.Original(), Cgo: entry.Cgo}, nil
}
}
}
Expand Down
19 changes: 12 additions & 7 deletions pkg/catalog/catalog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (
"testing"
)

const (
testCatalog = `{ "dep": {"Module": "github.com/dep", "Versions": ["v0.1.0", "v0.2.0"]}}`
invalidCatalog = `{ "dep": {}}`
)
const testCatalog = `{
"dep": {"Module": "github.com/dep", "Versions": ["v0.1.0", "v0.2.0"]},
"dep2": {"Module": "github.com/dep2", "Versions": ["v0.1.0"], "Cgo": true}
}`

func TestResolve(t *testing.T) {
t.Parallel()
Expand All @@ -28,17 +28,22 @@ func TestResolve(t *testing.T) {
{
title: "resolve exact version",
dep: Dependency{Name: "dep", Constrains: "v0.1.0"},
expect: Module{Path: "github.com/dep", Version: "v0.1.0"},
expect: Module{Path: "github.com/dep", Version: "v0.1.0", Cgo: false},
},
{
title: "resolve > constrain",
dep: Dependency{Name: "dep", Constrains: ">v0.1.0"},
expect: Module{Path: "github.com/dep", Version: "v0.2.0"},
expect: Module{Path: "github.com/dep", Version: "v0.2.0", Cgo: false},
},
{
title: "resolve latest version",
dep: Dependency{Name: "dep", Constrains: "*"},
expect: Module{Path: "github.com/dep", Version: "v0.2.0"},
expect: Module{Path: "github.com/dep", Version: "v0.2.0", Cgo: false},
},
{
title: "resolve cgo dependency",
dep: Dependency{Name: "dep2", Constrains: "=v0.1.0"},
expect: Module{Path: "github.com/dep2", Version: "v0.1.0", Cgo: true},
},
{
title: "unsatisfied > constrain",
Expand Down
5 changes: 5 additions & 0 deletions pkg/catalog/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
"type": "string",
"pattern": "^v(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$"
}
},
"cgo": {
"type": "boolean",
"description": "whether the dependency requires cgo"
}

},
"required": [
"module",
Expand Down

0 comments on commit 245ffca

Please sign in to comment.