feat(goctl): go work multi-module support (#1800)
* feat(goctl): go work multi-module support Resolve: #1793 * chore: print log when getting project ctx fails
This commit is contained in:
@@ -12,6 +12,9 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/tools/goctl/vars"
|
"github.com/zeromicro/go-zero/tools/goctl/vars"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RunFunc defines a function type of Run function
|
||||||
|
type RunFunc func(string, string, ...*bytes.Buffer) (string, error)
|
||||||
|
|
||||||
// Run provides the execution of shell scripts in golang,
|
// Run provides the execution of shell scripts in golang,
|
||||||
// which can support macOS, Windows, and Linux operating systems.
|
// which can support macOS, Windows, and Linux operating systems.
|
||||||
// Other operating systems are currently not supported
|
// Other operating systems are currently not supported
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ctx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
|
"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
|
||||||
@@ -31,6 +32,7 @@ func Prepare(workDir string) (*ProjectContext, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return ctx, nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
|
fmt.Printf("get project context from workdir[%s] failed: %s\n", workDir, err)
|
||||||
|
|
||||||
name := filepath.Base(workDir)
|
name := filepath.Base(workDir)
|
||||||
_, err = execx.Run("go mod init "+name, workDir)
|
_, err = execx.Run("go mod init "+name, workDir)
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package ctx
|
package ctx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/jsonx"
|
|
||||||
"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
|
"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
|
||||||
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
)
|
)
|
||||||
@@ -36,16 +39,11 @@ func projectFromGoMod(workDir string) (*ProjectContext, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := execx.Run("go list -json -m", workDir)
|
m, err := getRealModule(workDir, execx.Run)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var m Module
|
|
||||||
err = jsonx.Unmarshal([]byte(data), &m)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var ret ProjectContext
|
var ret ProjectContext
|
||||||
ret.WorkDir = workDir
|
ret.WorkDir = workDir
|
||||||
ret.Name = filepath.Base(m.Dir)
|
ret.Name = filepath.Base(m.Dir)
|
||||||
@@ -58,3 +56,34 @@ func projectFromGoMod(workDir string) (*ProjectContext, error) {
|
|||||||
ret.Path = m.Path
|
ret.Path = m.Path
|
||||||
return &ret, nil
|
return &ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRealModule(workDir string, execRun execx.RunFunc) (*Module, error) {
|
||||||
|
data, err := execRun("go list -json -m", workDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
modules, err := decodePackages(strings.NewReader(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, m := range modules {
|
||||||
|
if strings.HasPrefix(workDir, m.Dir) {
|
||||||
|
return &m, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("no matched module")
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodePackages(rc io.Reader) ([]Module, error) {
|
||||||
|
var modules []Module
|
||||||
|
decoder := json.NewDecoder(rc)
|
||||||
|
for decoder.More() {
|
||||||
|
var m Module
|
||||||
|
if err := decoder.Decode(&m); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid module: %v", err)
|
||||||
|
}
|
||||||
|
modules = append(modules, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return modules, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package ctx
|
package ctx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"go/build"
|
"go/build"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -36,3 +38,75 @@ func TestProjectFromGoMod(t *testing.T) {
|
|||||||
assert.Equal(t, projectName, ctx.Path)
|
assert.Equal(t, projectName, ctx.Path)
|
||||||
assert.Equal(t, dir, ctx.Dir)
|
assert.Equal(t, dir, ctx.Dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_getRealModule(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
workDir string
|
||||||
|
execRun execx.RunFunc
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *Module
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "single module",
|
||||||
|
args: args{
|
||||||
|
workDir: "/home/foo",
|
||||||
|
execRun: func(arg, dir string, in ...*bytes.Buffer) (string, error) {
|
||||||
|
return `{
|
||||||
|
"Path":"foo",
|
||||||
|
"Dir":"/home/foo",
|
||||||
|
"GoMod":"/home/foo/go.mod",
|
||||||
|
"GoVersion":"go1.16"}`, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &Module{
|
||||||
|
Path: "foo",
|
||||||
|
Dir: "/home/foo",
|
||||||
|
GoMod: "/home/foo/go.mod",
|
||||||
|
GoVersion: "go1.16",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "go work multiple modules",
|
||||||
|
args: args{
|
||||||
|
workDir: "/home/bar",
|
||||||
|
execRun: func(arg, dir string, in ...*bytes.Buffer) (string, error) {
|
||||||
|
return `
|
||||||
|
{
|
||||||
|
"Path":"foo",
|
||||||
|
"Dir":"/home/foo",
|
||||||
|
"GoMod":"/home/foo/go.mod",
|
||||||
|
"GoVersion":"go1.18"
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"Path":"bar",
|
||||||
|
"Dir":"/home/bar",
|
||||||
|
"GoMod":"/home/bar/go.mod",
|
||||||
|
"GoVersion":"go1.18"
|
||||||
|
}`, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &Module{
|
||||||
|
Path: "bar",
|
||||||
|
Dir: "/home/bar",
|
||||||
|
GoMod: "/home/bar/go.mod",
|
||||||
|
GoVersion: "go1.18",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := getRealModule(tt.args.workDir, tt.args.execRun)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("getRealModule() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("getRealModule() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/jsonx"
|
|
||||||
"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
|
"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,16 +16,10 @@ func IsGoMod(workDir string) (bool, error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := execx.Run("go list -json -m", workDir)
|
data, err := execx.Run("go list -m -f '{{.GoMod}}'", workDir)
|
||||||
if err != nil {
|
if err != nil || len(data) == 0 {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var m Module
|
return true, nil
|
||||||
err = jsonx.Unmarshal([]byte(data), &m)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return len(m.GoMod) > 0, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user