diff --git a/modload/module.go b/modload/module.go index f20d6be..ce70824 100644 --- a/modload/module.go +++ b/modload/module.go @@ -204,16 +204,18 @@ func LoadFromEx(gomod, gopmod string, readFile func(string) ([]byte, error)) (p } var opt *modfile.File - data, err = readFile(gopmod) - if err != nil { - opt = newGopMod(gopmod, defaultGopVer) - } else { - opt, err = modfile.ParseLax(gopmod, data, fix) - if err != nil { - err = errors.NewWith(err, `modfile.Parse(gopmod, data, fix)`, -2, "modfile.Parse", gopmod, data, fix) - return + if gopmod != "" { + if data, err = readFile(gopmod); err == nil { + opt, err = modfile.ParseLax(gopmod, data, fix) + if err != nil { + err = errors.NewWith(err, `modfile.Parse(gopmod, data, fix)`, -2, "modfile.Parse", gopmod, data, fix) + return + } } } + if opt == nil { + opt = newGopMod(gopmod, defaultGopVer) + } importClassfileFromGoMod(opt, f) return Module{f, opt}, nil } @@ -300,13 +302,46 @@ func (p Module) Save() (err error) { return } +func (p Module) checkGopDeps() (flags int) { + for _, r := range p.File.Require { + switch r.Mod.Path { + case gopMod: + flags |= FlagDepModGop + case xMod: + flags |= FlagDepModX + } + } + return +} + +func findReplaceGopMod(work *gomodfile.WorkFile) bool { + for _, r := range work.Replace { + if r.Old.Path == gopMod { + return true + } + } + return false +} + +const ( + gopMod = "github.com/goplus/gop" + xMod = "github.com/qiniu/x" +) + +const ( + FlagDepModGop = 1 << iota // depends module github.com/goplus/gop + FlagDepModX // depends module github.com/qiniu/x +) + // SaveWithGopMod adds `require github.com/goplus/gop` and saves all // changes of this module. func (p Module) SaveWithGopMod(gop *env.Gop, flags int) (err error) { gopVer := getGopVer(gop) - p.requireGop(gop, gopVer, flags) - if err = p.Save(); err != nil { - return + if old := p.checkGopDeps(); old != flags { + p.requireGop(gop, gopVer, old, flags) + if err = p.Save(); err != nil { + return + } } var work *gomodfile.WorkFile @@ -324,14 +359,34 @@ func (p Module) SaveWithGopMod(gop *env.Gop, flags int) (err error) { if work, err = gomodfile.ParseWork(workFile, b, fix); err != nil { return } - work.AddReplace("github.com/goplus/gop", gopVer, gop.Root, "") + if findReplaceGopMod(work) { + return + } + work.AddReplace(gopMod, gopVer, gop.Root, "") return os.WriteFile(workFile, gomodfile.Format(work.Syntax), 0666) } // requireGop adds require for the github.com/goplus/gop module. -func (p Module) requireGop(gop *env.Gop, gopVer string, flags int) { - p.File.AddRequire("github.com/goplus/gop", gopVer) - // TODO: AddRequire "github.com/qiniu/x" if necessary +func (p Module) requireGop(gop *env.Gop, gopVer string, old, flags int) { + if (flags&FlagDepModGop) != 0 && (old&FlagDepModGop) == 0 { + p.File.AddRequire(gopMod, gopVer) + } + if (flags&FlagDepModX) != 0 && (old&FlagDepModX) == 0 { // depends module github.com/qiniu/x + if x, ok := getXVer(gop); ok { + p.File.AddRequire(x.Path, x.Version) + } + } +} + +func getXVer(gop *env.Gop) (modVer module.Version, ok bool) { + if mod, err := LoadFrom(gop.Root+"/go.mod", ""); err == nil { + for _, r := range mod.File.Require { + if r.Mod.Path == xMod { + return r.Mod, true + } + } + } + return } func getGopVer(gop *env.Gop) string { diff --git a/modload/module_test.go b/modload/module_test.go index 40a0da7..79b4143 100644 --- a/modload/module_test.go +++ b/modload/module_test.go @@ -18,6 +18,7 @@ package modload import ( "encoding/json" + "log" "os" "runtime" "testing" @@ -145,7 +146,7 @@ func TestSaveDefault(t *testing.T) { func TestSave(t *testing.T) { dir := ".gop/_tempdir" - os.RemoveAll(dir) + os.RemoveAll(".gop") os.MkdirAll(dir, 0777) mod, err := Create(dir, "github.com/foo/bar", "", "") if err != nil { @@ -160,7 +161,7 @@ func TestSave(t *testing.T) { if err != nil { t.Fatal("Load:", err) } - if err = mod.SaveWithGopMod(&env.Gop{Version: "v1.2.0 devel", Root: "/foo/bar/gop"}, 0); err != nil { + if err = mod.SaveWithGopMod(&env.Gop{Version: "v1.2.0 devel", Root: "/foo/bar/gop"}, FlagDepModGop); err != nil { t.Fatal("mod.SaveWithGopMod:", err) } if b, err := mod.File.Format(); err != nil { @@ -186,6 +187,43 @@ replace github.com/goplus/gop v1.2.0 => /foo/bar/gop ` { t.Fatal("workFile:", v) } + + // SaveWithGopMod with FlagDepModX + os.WriteFile(".gop/go.mod", []byte(` +module github.com/goplus/gop + +go 1.18 + +require ( + github.com/qiniu/x v1.13.0 +) +`), 0666) + if err = mod.SaveWithGopMod(&env.Gop{Version: "v1.2.0 devel", Root: ".gop"}, FlagDepModGop|FlagDepModX); err != nil { + t.Fatal("mod.SaveWithGopMod 2:", err) + } + if b, err := mod.File.Format(); err != nil { + t.Fatal("Format:", err) + } else if v := string(b); v != `module github.com/foo/bar + +go 1.18 + +require ( + github.com/goplus/yap v0.5.0 //gop:class + github.com/goplus/gop v1.2.0 + github.com/qiniu/x v1.13.0 +) +` { + t.Fatal("SaveWithGopMod:", v) + } + if _, ok := getXVer(&env.Gop{Root: "/foo/bar"}); ok { + t.Fatal("getXVer: ok?") + } + + // SaveWithGopMod again. noop. + if err = mod.SaveWithGopMod(&env.Gop{Version: "v1.2.0 devel", Root: ".gop"}, FlagDepModGop|FlagDepModX); err != nil { + log.Fatal("mod.SaveWithGopMod 3:", err) + } + mod.Opt.Projects = append(mod.Opt.Projects, spxProject) mod.Save() b, err = os.ReadFile(mod.Opt.Syntax.Name)