Skip to content

Commit

Permalink
Install libevmone and make it possible to run execs using it on arm64…
Browse files Browse the repository at this point in the history
… darwin machines (#25)
  • Loading branch information
Wojciech Małota-Wójcik authored Aug 20, 2024
1 parent 44655db commit ae0ff9f
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 15 deletions.
4 changes: 4 additions & 0 deletions pkg/localnet/infra/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/samber/lo"
"go.uber.org/zap"

"github.com/sei-protocol/build/pkg/tools"
"github.com/sei-protocol/build/pkg/tools/docker"
)

Expand Down Expand Up @@ -175,6 +176,9 @@ func (d *Docker) prepareRunArgs(app *App) []string {
runArgs := []string{
"run", "--name", app.Name, "-d", "--label", labelEnv + "=" + envName, "--network", networkName,
}
if app.Platform != tools.PlatformEmpty {
runArgs = append(runArgs, "--platform", fmt.Sprintf("linux/%s", app.Platform.Arch))
}
if app.RunAsUser {
runArgs = append(runArgs, "--user", fmt.Sprintf("%d:%d", os.Getuid(), os.Getgid()))
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/localnet/infra/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/samber/lo"
"go.uber.org/zap"

"github.com/sei-protocol/build/pkg/tools"
"github.com/sei-protocol/build/pkg/tools/docker"
)

Expand Down Expand Up @@ -221,6 +222,9 @@ type App struct {
// Image is the url of the container image
Image string

// Platform is the platform used to download the image for
Platform tools.Platform

// EnvVarsFunc is a function defining environment variables for docker container
EnvVarsFunc func() []EnvVar

Expand Down
3 changes: 3 additions & 0 deletions pkg/tools/golang/Dockerfile.builder.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM --platform=linux/{{ .Arch }} golang:{{ .GOVersion }}-alpine{{ .AlpineVersion }}

RUN apk add --no-cache gcc libc-dev linux-headers
69 changes: 66 additions & 3 deletions pkg/tools/golang/golang.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package golang

import (
"bytes"
"context"
"crypto/sha256"
_ "embed"
"encoding/hex"
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"

"github.com/outofforest/build"
"github.com/outofforest/libexec"
Expand Down Expand Up @@ -147,6 +151,67 @@ func UnitTests(ctx context.Context, deps build.DepsFunc) error {
})
}

//go:embed Dockerfile.builder.tmpl
var dockerfileBuilderTemplate string

var dockerfileBuilderTemplateParsed = template.Must(template.New("").Parse(dockerfileBuilderTemplate))

// DockerBuilderImage creates the image used to build go binaries and returns it name.
func DockerBuilderImage(ctx context.Context, deps build.DepsFunc, platform tools.Platform) (string, error) {
if platform.OS != tools.OSDocker {
return "", errors.Errorf("docker platform must be specified, %s provided", platform)
}

deps(docker.EnsureDocker)

const imageName = "docker-go-builder"

goTool, err := tools.Get(Go)
if err != nil {
return "", err
}
dockerfileBuf := &bytes.Buffer{}
err = dockerfileBuilderTemplateParsed.Execute(dockerfileBuf, struct {
Arch string
GOVersion string
AlpineVersion string
}{
Arch: platform.Arch,
GOVersion: goTool.GetVersion(),
AlpineVersion: docker.AlpineVersion,
})
if err != nil {
return "", errors.Wrap(err, "executing Dockerfile template failed")
}

dockerfileChecksum := sha256.Sum256(dockerfileBuf.Bytes())
image := imageName + ":" + hex.EncodeToString(dockerfileChecksum[:4])

imageBuf := &bytes.Buffer{}
imageCmd := exec.Command("docker", "images", "-q", image)
imageCmd.Stdout = imageBuf
if err := libexec.Exec(ctx, imageCmd); err != nil {
return "", errors.Wrapf(err, "failed to list image '%s'", image)
}
if imageBuf.Len() > 0 {
return image, nil
}

buildCmd := exec.Command(
"docker",
"build",
"--label", docker.LabelKey+"="+docker.LabelValue,
"--tag", image,
"-",
)
buildCmd.Stdin = dockerfileBuf

if err := libexec.Exec(ctx, buildCmd); err != nil {
return "", errors.Wrapf(err, "failed to build image '%s'", image)
}
return image, nil
}

func buildLocally(ctx context.Context, deps build.DepsFunc, config BuildConfig) error {
deps(EnsureGo)

Expand Down Expand Up @@ -176,13 +241,11 @@ func buildLocally(ctx context.Context, deps build.DepsFunc, config BuildConfig)
func buildInDocker(ctx context.Context, deps build.DepsFunc, config BuildConfig) error {
deps(docker.EnsureDocker)

goTool, err := tools.Get(Go)
image, err := DockerBuilderImage(ctx, deps, config.Platform)
if err != nil {
return err
}

image := fmt.Sprintf("golang:%s-alpine%s", goTool.GetVersion(), docker.AlpineVersion)

srcDir := lo.Must(filepath.EvalSymlinks(lo.Must(filepath.Abs("."))))
envDir := tools.EnvDir(ctx)

Expand Down
25 changes: 23 additions & 2 deletions pkg/tools/golang/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import (

// Tool names.
const (
Go tools.Name = "go"
GolangCI tools.Name = "golangci"
Go tools.Name = "go"
GolangCI tools.Name = "golangci"
LibEVMOne tools.Name = "libevmone"
)

var t = []tools.Tool{
Expand Down Expand Up @@ -82,6 +83,21 @@ var t = []tools.Tool{
},
},
},

// https://github.com/ethereum/evmone/releases
tools.BinaryTool{
Name: LibEVMOne,
Version: "0.12.0",
Sources: tools.Sources{
tools.PlatformDockerAMD64: {
URL: "https://github.com/ethereum/evmone/releases/download/v0.12.0/evmone-0.12.0-linux-x86_64.tar.gz",
Hash: "sha256:1c7b5eba0c8c3b3b2a7a05101e2d01a13a2f84b323989a29be66285dba4136ce",
Links: map[string]string{
"lib/libevmone.so": "lib/libevmone.so",
},
},
},
},
}

// GoPackageTool is the tool installed using go install command.
Expand Down Expand Up @@ -183,6 +199,11 @@ func EnsureGolangCI(ctx context.Context, _ build.DepsFunc) error {
return tools.Ensure(ctx, GolangCI, tools.PlatformLocal)
}

// EnsureLibEVMOne ensures that libevmone is available.
func EnsureLibEVMOne(ctx context.Context, _ build.DepsFunc) error {
return tools.Ensure(ctx, LibEVMOne, tools.PlatformDockerAMD64)
}

func init() {
tools.Add(t...)
}
23 changes: 13 additions & 10 deletions pkg/tools/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (

// Platform definitions.
var (
PlatformEmpty = Platform{}
PlatformLocal = Platform{OS: runtime.GOOS, Arch: runtime.GOARCH}
PlatformLinuxAMD64 = Platform{OS: OSLinux, Arch: ArchAMD64}
PlatformDarwinAMD64 = Platform{OS: OSDarwin, Arch: ArchAMD64}
Expand Down Expand Up @@ -247,7 +248,7 @@ func Ensure(ctx context.Context, toolName Name, platform Platform) error {

// VersionDir returns path to the version directory.
func VersionDir(ctx context.Context, platform Platform) string {
return filepath.Join(platformDir(ctx, platform), envVersion())
return filepath.Join(PlatformDir(ctx, platform), EnvVersion())
}

// Bin returns path to the installed binary.
Expand All @@ -270,6 +271,11 @@ func EnvDir(ctx context.Context) string {
return filepath.Join(lo.Must(os.UserCacheDir()), build.GetName(ctx))
}

// PlatformDir returns the directory where platform-specific stuff is stored.
func PlatformDir(ctx context.Context, platform Platform) string {
return filepath.Join(EnvDir(ctx), platform.String())
}

// ToolDownloadDir returns directory where tool is downloaded.
func ToolDownloadDir(ctx context.Context, platform Platform, tool Tool) string {
return filepath.Join(downloadsDir(ctx, platform), string(tool.GetName())+"-"+tool.GetVersion())
Expand Down Expand Up @@ -389,15 +395,8 @@ func Checksum(file string) (string, error) {
return "sha256:" + hex.EncodeToString(hasher.Sum(nil)), nil
}

func platformDir(ctx context.Context, platform Platform) string {
return filepath.Join(EnvDir(ctx), platform.String())
}

func downloadsDir(ctx context.Context, platform Platform) string {
return filepath.Join(platformDir(ctx, platform), "downloads")
}

func envVersion() string {
// EnvVersion returns the version of the environment.
func EnvVersion() string {
module := module()

bi, ok := debug.ReadBuildInfo()
Expand All @@ -423,6 +422,10 @@ func envVersion() string {
panic("impossible condition: build module not found")
}

func downloadsDir(ctx context.Context, platform Platform) string {
return filepath.Join(PlatformDir(ctx, platform), "downloads")
}

func module() string {
_, file, _, _ := runtime.Caller(0)
module := strings.Join(strings.Split(file, "/")[:3], "/")
Expand Down

0 comments on commit ae0ff9f

Please sign in to comment.