Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 27 additions & 27 deletions internal/workdir/runtimes/runtime-go/private.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"regexp"
"strings"

"github.com/kazhuravlev/toolset/internal/fsh"
"github.com/kazhuravlev/toolset/internal/prog"
"github.com/spf13/afero"
"golang.org/x/mod/modfile"
Expand All @@ -31,7 +30,7 @@ type moduleInfo struct {
}

// parse will parse source string and try to extract all details about mentioned golang program.
func parse(ctx context.Context, goBin, str string) (*moduleInfo, error) {
func (r *Runtime) parse(ctx context.Context, str string) (*moduleInfo, error) {
var mod, version, program string

{
Expand Down Expand Up @@ -64,8 +63,8 @@ func parse(ctx context.Context, goBin, str string) (*moduleInfo, error) {

buf := bytes.NewBuffer(nil)
{
cmd := exec.CommandContext(ctx, goBin, "env", "GOPRIVATE")
cmd.Env = envAllOverride([][2]string{{"GOTOOLCHAIN", "local"}})
cmd := exec.CommandContext(ctx, r.goBin, "env", "GOPRIVATE")
cmd.Env = r.goEnv()
cmd.Stdout = buf
cmd.Stderr = io.Discard
if err := cmd.Run(); err != nil {
Expand Down Expand Up @@ -97,19 +96,19 @@ type fetchedMod struct {
// @ => @latest
// @latest => @vX.X.X
// @vX.X.X => @vX.X.X
func fetchModule(ctx context.Context, fs fsh.FS, goBin, link string) (*moduleInfo, error) {
mod, err := parse(ctx, goBin, link)
func (r *Runtime) fetchModule(ctx context.Context, link string) (*moduleInfo, error) {
mod, err := r.parse(ctx, link)
if err != nil {
return nil, fmt.Errorf("parse module (%s) string: %w", link, err)
}

if mod.IsPrivate {
privateMod, err := fetchPrivate(ctx, fs, goBin, *mod)
privateMod, err := r.fetchPrivate(ctx, *mod)
if err != nil {
return nil, fmt.Errorf("fetch private module: %w", err)
}

return parse(ctx, goBin, mod.Mod.Name()+at+privateMod.Mod.Version())
return r.parse(ctx, mod.Mod.Name()+at+privateMod.Mod.Version())
}

link = mod.Mod.Name()
Expand Down Expand Up @@ -153,7 +152,7 @@ func fetchModule(ctx context.Context, fs fsh.FS, goBin, link string) (*moduleInf
return nil, fmt.Errorf("unable to decode module: %w", err)
}

mod2, err := parse(ctx, goBin, mod.Mod.Name()+at+fMod.Version)
mod2, err := r.parse(ctx, mod.Mod.Name()+at+fMod.Version)
if err != nil {
return nil, fmt.Errorf("parse fetched module: %w", err)
}
Expand All @@ -170,16 +169,16 @@ func fetchModule(ctx context.Context, fs fsh.FS, goBin, link string) (*moduleInf
// - Add dependency
// - Get dep info
// - Remove temp dir
func fetchPrivate(ctx context.Context, fSys fsh.FS, goBin string, mod moduleInfo) (*moduleInfo, error) {
tmpDir, err := afero.TempDir(fSys, "", "gomodtemp")
func (r *Runtime) fetchPrivate(ctx context.Context, mod moduleInfo) (*moduleInfo, error) {
tmpDir, err := afero.TempDir(r.fs, "", "gomodtemp")
if err != nil {
return nil, fmt.Errorf("failed to create temp directory: %v", err)
}
defer fSys.RemoveAll(tmpDir) //nolint:errcheck
defer r.fs.RemoveAll(tmpDir) //nolint:errcheck

{
cmd := exec.CommandContext(ctx, goBin, "mod", "init", "sample")
cmd.Env = envAllOverride([][2]string{{"GOTOOLCHAIN", "local"}})
cmd := exec.CommandContext(ctx, r.goBin, "mod", "init", "sample")
cmd.Env = r.goEnv()
cmd.Dir = tmpDir
cmd.Stdout = io.Discard
cmd.Stderr = io.Discard
Expand All @@ -189,8 +188,8 @@ func fetchPrivate(ctx context.Context, fSys fsh.FS, goBin string, mod moduleInfo
}

{
cmd := exec.CommandContext(ctx, goBin, "get", mod.Mod.S())
cmd.Env = envAllOverride([][2]string{{"GOTOOLCHAIN", "local"}})
cmd := exec.CommandContext(ctx, r.goBin, "get", mod.Mod.S())
cmd.Env = r.goEnv()
cmd.Dir = tmpDir
cmd.Stdout = io.Discard
cmd.Stderr = io.Discard
Expand All @@ -200,7 +199,7 @@ func fetchPrivate(ctx context.Context, fSys fsh.FS, goBin string, mod moduleInfo
}

goModFilename := filepath.Join(tmpDir, "go.mod")
bb, err := afero.ReadFile(fSys, goModFilename)
bb, err := afero.ReadFile(r.fs, goModFilename)
if err != nil {
return nil, fmt.Errorf("failed to read go.mod: %w", err)
}
Expand All @@ -212,7 +211,7 @@ func fetchPrivate(ctx context.Context, fSys fsh.FS, goBin string, mod moduleInfo

for _, require := range modFile.Require {
if strings.HasPrefix(mod.Mod.Name(), require.Mod.Path) {
return parse(ctx, goBin, mod.Mod.Name()+at+require.Mod.Version)
return r.parse(ctx, mod.Mod.Name()+at+require.Mod.Version)
}
}

Expand Down Expand Up @@ -268,12 +267,9 @@ func envAllOverride(envs [][2]string) []string {
"GOARM64",
"GOAUTH",
"GOBIN",
"GOCACHE",
"GOCACHEPROG",
"GODEBUG",
"GOENV",
"GOEXE",
//"GOEXPERIMENT",
"GOFIPS140",
"GOFLAGS",
"GOGCCFLAGS",
Expand All @@ -282,15 +278,9 @@ func envAllOverride(envs [][2]string) []string {
"GOINSECURE",
"GOMOD",
"GOMODCACHE",
//"GONOPROXY",
//"GONOSUMDB",
"GOOS",
"GOPATH",
//"GOPRIVATE",
//"GOPROXY",
"GOROOT",
//"GOSUMDB",
//"GOTELEMETRY",
"GOTELEMETRYDIR",
"GOTMPDIR",
"GOTOOLCHAIN",
Expand All @@ -299,6 +289,16 @@ func envAllOverride(envs [][2]string) []string {
"GOVERSION",
"GOWORK",
"PKG_CONFIG",

// "GOCACHE",
// "GOCACHEPROG",
// "GOEXPERIMENT",
// "GONOPROXY",
// "GONOSUMDB",
// "GOPRIVATE",
// "GOPROXY",
// "GOSUMDB",
// "GOTELEMETRY",
}

for _, env := range excluded {
Expand Down
31 changes: 24 additions & 7 deletions internal/workdir/runtimes/runtime-go/private_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ import (
"strings"
"testing"

"github.com/kazhuravlev/optional"
"github.com/kazhuravlev/toolset/internal/fsh"

"github.com/kazhuravlev/toolset/internal/prog"
"github.com/stretchr/testify/require"
)

func Test_parse(t *testing.T) {
goBin, err := exec.LookPath("go")
require.NoError(t, err, "install go")
rt := newTestRuntime(t)

f := func(name, in string, exp moduleInfo) {
t.Run(name, func(t *testing.T) {
ctx := context.Background()
mod, err := parse(ctx, goBin, in)
mod, err := rt.parse(ctx, in)
require.NoError(t, err)
require.NotEmpty(t, mod)
require.Equal(t, exp, *mod)
Expand Down Expand Up @@ -49,14 +49,12 @@ func Test_parse(t *testing.T) {
}

func Test_fetchModule(t *testing.T) {
fs := fsh.NewRealFS()
goBin, err := exec.LookPath("go")
require.NoError(t, err, "install go")
rt := newTestRuntime(t)

f := func(name, link string, exp moduleInfo) {
t.Run(name, func(t *testing.T) {
ctx := context.Background()
mod, err := fetchModule(ctx, fs, goBin, link)
mod, err := rt.fetchModule(ctx, link)
require.NoError(t, err)
require.NotEmpty(t, mod)
require.Equal(t, exp, *mod)
Expand Down Expand Up @@ -85,3 +83,22 @@ func Test_getGoVersion(t *testing.T) {
require.NotEmpty(t, goVersion)
require.True(t, strings.HasPrefix(goVersion, "1.")) // NOTE(zhuravlev): should looks like 1.23.4
}

func newTestRuntime(t *testing.T) *Runtime {
t.Helper()

fs := fsh.NewRealFS()
goBin, err := exec.LookPath("go")
require.NoError(t, err, "install go")

ctx := context.Background()
goVersion, err := getGoVersion(ctx, goBin)
require.NoError(t, err)

binDir := t.TempDir()

rt, err := New(fs, binDir, goBin, goVersion, optional.Empty[string]())
require.NoError(t, err)

return rt
}
51 changes: 42 additions & 9 deletions internal/workdir/runtimes/runtime-go/runtime_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path/filepath"
"strings"

"github.com/kazhuravlev/optional"
"github.com/spf13/afero"

"github.com/kazhuravlev/toolset/internal/fsh"
Expand All @@ -28,15 +29,23 @@ type Runtime struct {
isGlobal bool
goVersion string // ex: 1.23
binToolDir string
goCacheDir optional.Val[string]
}

func New(fs fsh.FS, binToolDir, goBin, goVer string) *Runtime {
func New(fs fsh.FS, binToolDir, goBin, goVer string, goCache optional.Val[string]) (*Runtime, error) {
if goCacheVal, ok := goCache.Get(); ok {
if err := fs.MkdirAll(goCacheVal, fsh.DefaultDirPerm); err != nil {
return nil, fmt.Errorf("create go cache dir (%s): %w", goCacheVal, err)
}
}

return &Runtime{
fs: fs,
goBin: goBin,
goVersion: goVer,
binToolDir: binToolDir,
}
goCacheDir: goCache,
}, nil
}

// Parse will parse string to normal version.
Expand All @@ -48,7 +57,7 @@ func (r *Runtime) Parse(ctx context.Context, str string) (string, error) {
return "", errors.New("program name not provided")
}

goModule, err := fetchModule(ctx, r.fs, r.goBin, str)
goModule, err := r.fetchModule(ctx, str)
if err != nil {
return "", fmt.Errorf("get go module version: %w", err)
}
Expand All @@ -57,7 +66,7 @@ func (r *Runtime) Parse(ctx context.Context, str string) (string, error) {
}

func (r *Runtime) GetModule(ctx context.Context, module string) (*structs.ModuleInfo, error) {
mod, err := parse(ctx, r.goBin, module)
mod, err := r.parse(ctx, module)
if err != nil {
return nil, fmt.Errorf("parse module (%s): %w", module, err)
}
Expand Down Expand Up @@ -86,7 +95,7 @@ func (r *Runtime) Install(ctx context.Context, program string) error {
}

cmd := exec.CommandContext(ctx, r.goBin, "install", program)
cmd.Env = envAllOverride([][2]string{{"GOTOOLCHAIN", "local"}, {"GOBIN", mod.BinDir}})
cmd.Env = r.goEnv([2]string{"GOBIN", mod.BinDir})

var stdout bytes.Buffer
cmd.Stderr = &stdout
Expand Down Expand Up @@ -127,13 +136,13 @@ func (r *Runtime) Run(ctx context.Context, program string, args ...string) error
}

func (r *Runtime) GetLatest(ctx context.Context, moduleReq string) (string, bool, error) {
mod, err := parse(ctx, r.goBin, moduleReq)
mod, err := r.parse(ctx, moduleReq)
if err != nil {
return "", false, fmt.Errorf("parse module (%s): %w", moduleReq, err)
}

latestStr := mod.Mod.AsLatest().S()
latestMod, err := fetchModule(ctx, r.fs, r.goBin, latestStr)
latestMod, err := r.fetchModule(ctx, latestStr)
if err != nil {
return "", false, fmt.Errorf("get go module: %w", err)
}
Expand Down Expand Up @@ -162,6 +171,19 @@ func (r *Runtime) Remove(ctx context.Context, tool structs.Tool) error {
return nil
}

func (r *Runtime) goEnv(overrides ...[2]string) []string {
base := make([][2]string, 0, len(overrides)+2)

if val, ok := r.goCacheDir.Get(); ok {
base = append(base, [2]string{"GOCACHE", val})
}

base = append(base, [2]string{"GOTOOLCHAIN", "local"})
base = append(base, overrides...)

return envAllOverride(base)
}

func (r *Runtime) Version() string {
if r.isGlobal {
return "go"
Expand Down Expand Up @@ -190,7 +212,11 @@ func Discover(ctx context.Context, fSys fsh.FS, binToolDir string) ([]*Runtime,
return res, fmt.Errorf("get go version: %w", err)
}

rt := New(fSys, binToolDir, lp, ver)
rt, err := New(fSys, binToolDir, lp, ver, optional.Empty[string]())
if err != nil {
return res, fmt.Errorf("init go runtime (%s): %w", ver, err)
}

rt.isGlobal = true
res = append(res, rt)
}
Expand Down Expand Up @@ -224,7 +250,14 @@ func Discover(ctx context.Context, fSys fsh.FS, binToolDir string) ([]*Runtime,
return res, fmt.Errorf("get go version for (%s): %w", goBin, err)
}

res = append(res, New(fSys, binToolDir, goBin, goVer))
goCache := filepath.Join(binToolDir, e.Name(), "gocache")

rt, err := New(fSys, binToolDir, goBin, goVer, optional.New(goCache))
if err != nil {
return res, fmt.Errorf("init go runtime (%s): %w", goVer, err)
}

res = append(res, rt)
}
}

Expand Down
Loading