diff --git a/README.md b/README.md index 49f9c37..a952d01 100644 --- a/README.md +++ b/README.md @@ -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. ``` diff --git a/cmd/server/server.go b/cmd/server/server.go index b0cdc6d..2f3fca9 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -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 = ` diff --git a/pkg/builder/builder.go b/pkg/builder/builder.go index dfd268f..f652a04 100644 --- a/pkg/builder/builder.go +++ b/pkg/builder/builder.go @@ -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")) } @@ -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 } @@ -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} @@ -140,6 +122,7 @@ 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 { @@ -147,6 +130,7 @@ func (b *Builder) Build( //nolint:funlen } 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 @@ -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) } @@ -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{}) diff --git a/pkg/catalog/catalog.go b/pkg/catalog/catalog.go index 8795e8b..4e90f1a 100644 --- a/pkg/catalog/catalog.go +++ b/pkg/catalog/catalog.go @@ -7,21 +7,27 @@ // // The catalog is a json file with the following schema: // -// { -// "": {"module": "", "versions": ["", "", ... ""]} -// } +// { +// "": { +// "module": "", +// "versions": ["", "", ... ""], +// "cgo": +// }, +// } // // where: // : 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 @@ -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 @@ -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 { @@ -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 } } } diff --git a/pkg/catalog/catalog_test.go b/pkg/catalog/catalog_test.go index 6e8110a..3a630fc 100644 --- a/pkg/catalog/catalog_test.go +++ b/pkg/catalog/catalog_test.go @@ -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() @@ -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", diff --git a/pkg/catalog/schema.json b/pkg/catalog/schema.json index e31977d..815999c 100644 --- a/pkg/catalog/schema.json +++ b/pkg/catalog/schema.json @@ -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",