mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-03-21 21:07:19 +02:00
229 lines
4.7 KiB
Go
229 lines
4.7 KiB
Go
|
package zig
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"os/exec"
|
||
|
"path/filepath"
|
||
|
"slices"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/caarlos0/log"
|
||
|
"github.com/goreleaser/goreleaser/v2/internal/artifact"
|
||
|
"github.com/goreleaser/goreleaser/v2/internal/gio"
|
||
|
"github.com/goreleaser/goreleaser/v2/internal/tmpl"
|
||
|
api "github.com/goreleaser/goreleaser/v2/pkg/build"
|
||
|
"github.com/goreleaser/goreleaser/v2/pkg/config"
|
||
|
"github.com/goreleaser/goreleaser/v2/pkg/context"
|
||
|
)
|
||
|
|
||
|
// Default builder instance.
|
||
|
//
|
||
|
//nolint:gochecknoglobals
|
||
|
var Default = &Builder{}
|
||
|
|
||
|
//nolint:gochecknoinits
|
||
|
func init() {
|
||
|
api.Register("zig", Default)
|
||
|
}
|
||
|
|
||
|
// Builder is golang builder.
|
||
|
type Builder struct{}
|
||
|
|
||
|
// Parse implements build.Builder.
|
||
|
func (b *Builder) Parse(target string) (api.Target, error) {
|
||
|
parts := strings.Split(target, "-")
|
||
|
if len(parts) < 2 {
|
||
|
return nil, fmt.Errorf("%s is not a valid build target", target)
|
||
|
}
|
||
|
|
||
|
t := Target{
|
||
|
Target: target,
|
||
|
Os: convertToGoos(parts[1]),
|
||
|
Arch: convertToGoarch(parts[0]),
|
||
|
}
|
||
|
|
||
|
if len(parts) > 2 {
|
||
|
t.Abi = parts[2]
|
||
|
}
|
||
|
|
||
|
return t, nil
|
||
|
}
|
||
|
|
||
|
// WithDefaults implements build.Builder.
|
||
|
func (b *Builder) WithDefaults(build config.Build) (config.Build, error) {
|
||
|
log.Warn("you are using the experimental Zig builder")
|
||
|
|
||
|
if len(build.Targets) == 0 {
|
||
|
build.Targets = defaultTargets()
|
||
|
}
|
||
|
|
||
|
if build.GoBinary == "" {
|
||
|
build.GoBinary = "zig"
|
||
|
}
|
||
|
|
||
|
if build.Command == "" {
|
||
|
build.Command = "build"
|
||
|
}
|
||
|
|
||
|
if build.Dir == "" {
|
||
|
build.Dir = "."
|
||
|
}
|
||
|
|
||
|
if build.Main != "" {
|
||
|
return build, errors.New("main is not used for zig")
|
||
|
}
|
||
|
|
||
|
if len(build.Ldflags) > 0 {
|
||
|
return build, errors.New("ldflags is not used for zig")
|
||
|
}
|
||
|
|
||
|
if len(slices.Concat(
|
||
|
build.Goos,
|
||
|
build.Goarch,
|
||
|
build.Goamd64,
|
||
|
build.Go386,
|
||
|
build.Goarm,
|
||
|
build.Goarm64,
|
||
|
build.Gomips,
|
||
|
build.Goppc64,
|
||
|
build.Goriscv64,
|
||
|
)) > 0 {
|
||
|
return build, errors.New("all go* fields are not used for zig, set targets instead")
|
||
|
}
|
||
|
|
||
|
if len(build.Ignore) > 0 {
|
||
|
return build, errors.New("ignore is not used for zig, set targets instead")
|
||
|
}
|
||
|
|
||
|
if build.Buildmode != "" {
|
||
|
return build, errors.New("buildmode is not used for zig")
|
||
|
}
|
||
|
|
||
|
if len(build.Tags) > 0 {
|
||
|
return build, errors.New("tags is not used for zig")
|
||
|
}
|
||
|
|
||
|
if len(build.Asmflags) > 0 {
|
||
|
return build, errors.New("asmtags is not used for zig")
|
||
|
}
|
||
|
|
||
|
if len(build.BuildDetailsOverrides) > 0 {
|
||
|
return build, errors.New("overrides is not used for zig")
|
||
|
}
|
||
|
|
||
|
for _, t := range build.Targets {
|
||
|
switch checkTarget(t) {
|
||
|
case targetValid:
|
||
|
// lfg
|
||
|
case targetBroken:
|
||
|
log.Warnf("target might not be supported: %s", t)
|
||
|
case targetInvalid:
|
||
|
return build, fmt.Errorf("invalid target: %s", t)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return build, nil
|
||
|
}
|
||
|
|
||
|
// Build implements build.Builder.
|
||
|
func (b *Builder) Build(ctx *context.Context, build config.Build, options api.Options) error {
|
||
|
prefix := filepath.Dir(options.Path)
|
||
|
options.Path = filepath.Join(prefix, "bin", options.Name)
|
||
|
|
||
|
t := options.Target.(Target)
|
||
|
a := &artifact.Artifact{
|
||
|
Type: artifact.Binary,
|
||
|
Path: options.Path,
|
||
|
Name: options.Name,
|
||
|
Goos: convertToGoos(t.Os),
|
||
|
Goarch: convertToGoarch(t.Arch),
|
||
|
Target: t.Target,
|
||
|
Extra: map[string]interface{}{
|
||
|
artifact.ExtraBinary: strings.TrimSuffix(filepath.Base(options.Path), options.Ext),
|
||
|
artifact.ExtraExt: options.Ext,
|
||
|
artifact.ExtraID: build.ID,
|
||
|
artifact.ExtraBuilder: "zig",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
env := []string{}
|
||
|
env = append(env, ctx.Env.Strings()...)
|
||
|
|
||
|
tpl := tmpl.New(ctx).
|
||
|
WithBuildOptions(options).
|
||
|
WithEnvS(env).
|
||
|
WithArtifact(a)
|
||
|
|
||
|
zigbin, err := tpl.Apply(build.GoBinary)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
command := []string{
|
||
|
zigbin,
|
||
|
build.Command,
|
||
|
"-Dtarget=" + t.Target,
|
||
|
"-p", prefix,
|
||
|
}
|
||
|
|
||
|
for _, e := range build.Env {
|
||
|
ee, err := tpl.Apply(e)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
log.Debugf("env %q evaluated to %q", e, ee)
|
||
|
if ee != "" {
|
||
|
env = append(env, ee)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tpl = tpl.WithEnvS(env)
|
||
|
|
||
|
flags, err := processFlags(tpl, build.Flags)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
command = append(command, flags...)
|
||
|
|
||
|
/* #nosec */
|
||
|
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
|
||
|
cmd.Env = env
|
||
|
cmd.Dir = build.Dir
|
||
|
log.Debug("running")
|
||
|
out, err := cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("%w: %s", err, string(out))
|
||
|
}
|
||
|
if s := string(out); s != "" {
|
||
|
log.WithField("cmd", command).Info(s)
|
||
|
}
|
||
|
|
||
|
// TODO: move this to outside builder for both go and zig
|
||
|
modTimestamp, err := tpl.Apply(build.ModTimestamp)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := gio.Chtimes(a.Path, modTimestamp); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
ctx.Artifacts.Add(a)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func processFlags(tpl *tmpl.Template, flags []string) ([]string, error) {
|
||
|
var processed []string
|
||
|
for _, rawFlag := range flags {
|
||
|
flag, err := tpl.Apply(rawFlag)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if flag == "" {
|
||
|
continue
|
||
|
}
|
||
|
processed = append(processed, flag)
|
||
|
}
|
||
|
return processed, nil
|
||
|
}
|