Skip to content
Open
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
141 changes: 116 additions & 25 deletions tools/goctl/rpc/generator/mkdir.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package generator

import (
"os"
"path"
"path/filepath"
"strings"

Expand Down Expand Up @@ -82,9 +84,7 @@ func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, conf *conf.Config, c *ZR
return "", err
}
}
childPath = strings.TrimPrefix(abs, ctx.Dir)
pkg := filepath.Join(ctx.Path, childPath)
return filepath.ToSlash(pkg), nil
return resolveDirPackage(ctx, abs, ""), nil
}

var callClientDir string
Expand All @@ -106,9 +106,8 @@ func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, conf *conf.Config, c *ZR
if c.IsGenClient {
inner[call] = Dir{
Filename: callClientDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path,
strings.TrimPrefix(callClientDir, ctx.Dir))),
Base: filepath.Base(callClientDir),
Package: resolveDirPackage(ctx, callClientDir, ""),
Base: filepath.Base(callClientDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(callClientDir, childPath)
},
Expand All @@ -117,57 +116,55 @@ func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, conf *conf.Config, c *ZR

inner[wd] = Dir{
Filename: ctx.WorkDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path,
strings.TrimPrefix(ctx.WorkDir, ctx.Dir))),
Base: filepath.Base(ctx.WorkDir),
Package: resolveDirPackage(ctx, ctx.WorkDir, ""),
Base: filepath.Base(ctx.WorkDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(ctx.WorkDir, childPath)
},
}
inner[etc] = Dir{
Filename: etcDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(etcDir, ctx.Dir))),
Package: resolveDirPackage(ctx, etcDir, ""),
Base: filepath.Base(etcDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(etcDir, childPath)
},
}
inner[internal] = Dir{
Filename: internalDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path,
strings.TrimPrefix(internalDir, ctx.Dir))),
Base: filepath.Base(internalDir),
Package: resolveDirPackage(ctx, internalDir, ""),
Base: filepath.Base(internalDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(internalDir, childPath)
},
}
inner[config] = Dir{
Filename: configDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(configDir, ctx.Dir))),
Package: resolveDirPackage(ctx, configDir, ""),
Base: filepath.Base(configDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(configDir, childPath)
},
}
inner[logic] = Dir{
Filename: logicDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(logicDir, ctx.Dir))),
Package: resolveDirPackage(ctx, logicDir, ""),
Base: filepath.Base(logicDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(logicDir, childPath)
},
}
inner[server] = Dir{
Filename: serverDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(serverDir, ctx.Dir))),
Package: resolveDirPackage(ctx, serverDir, ""),
Base: filepath.Base(serverDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(serverDir, childPath)
},
}
inner[svc] = Dir{
Filename: svcDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(svcDir, ctx.Dir))),
Package: resolveDirPackage(ctx, svcDir, ""),
Base: filepath.Base(svcDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(svcDir, childPath)
Expand All @@ -176,7 +173,7 @@ func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, conf *conf.Config, c *ZR

inner[pb] = Dir{
Filename: pbDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(pbDir, ctx.Dir))),
Package: resolveDirPackage(ctx, pbDir, proto.GoPackage),
Base: filepath.Base(pbDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(pbDir, childPath)
Expand All @@ -185,9 +182,8 @@ func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, conf *conf.Config, c *ZR

inner[protoGo] = Dir{
Filename: protoGoDir,
Package: filepath.ToSlash(filepath.Join(ctx.Path,
strings.TrimPrefix(protoGoDir, ctx.Dir))),
Base: filepath.Base(protoGoDir),
Package: resolveDirPackage(ctx, protoGoDir, proto.GoPackage),
Base: filepath.Base(protoGoDir),
GetChildPackage: func(childPath string) (string, error) {
return getChildPackage(protoGoDir, childPath)
},
Expand All @@ -212,18 +208,113 @@ func mkdir(ctx *ctx.ProjectContext, proto parser.Proto, conf *conf.Config, c *ZR
func (d *defaultDirContext) SetPbDir(pbDir, grpcDir string) {
d.inner[pb] = Dir{
Filename: pbDir,
Package: filepath.ToSlash(filepath.Join(d.ctx.Path, strings.TrimPrefix(pbDir, d.ctx.Dir))),
Package: resolveDirPackage(d.ctx, pbDir, d.inner[pb].Package),
Base: filepath.Base(pbDir),
}

d.inner[protoGo] = Dir{
Filename: grpcDir,
Package: filepath.ToSlash(filepath.Join(d.ctx.Path,
strings.TrimPrefix(grpcDir, d.ctx.Dir))),
Base: filepath.Base(grpcDir),
Package: resolveDirPackage(d.ctx, grpcDir, d.inner[protoGo].Package),
Base: filepath.Base(grpcDir),
}
}

func resolveDirPackage(project *ctx.ProjectContext, dir, fallback string) string {
dir = filepath.Clean(dir)
projectDir := filepath.Clean(project.Dir)

if rel, ok := relativeImportPath(projectDir, dir); ok {
return joinImportPath(project.Path, rel)
}

if modulePath, moduleDir, ok := resolveModuleForDir(dir); ok {
if rel, ok := relativeImportPath(moduleDir, dir); ok {
return joinImportPath(modulePath, rel)
}
}

if isImportPath(fallback) {
return filepath.ToSlash(fallback)
}

return filepath.ToSlash(filepath.Base(dir))
}

func relativeImportPath(baseDir, targetDir string) (string, bool) {
rel, err := filepath.Rel(baseDir, targetDir)
if err != nil {
return "", false
}
if rel == "." {
return "", true
}
if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) || filepath.IsAbs(rel) {
return "", false
}

return filepath.ToSlash(rel), true
}

func joinImportPath(basePath, rel string) string {
if rel == "" || rel == "." {
return filepath.ToSlash(basePath)
}

return path.Join(filepath.ToSlash(basePath), filepath.ToSlash(rel))
}

func isImportPath(value string) bool {
if value == "" || strings.HasPrefix(value, ".") || strings.HasPrefix(value, "/") || filepath.IsAbs(value) {
return false
}

if len(value) >= 3 && value[1] == ':' {
switch value[2] {
case '/', '\\':
return false
}
}

return true
}

func resolveModuleForDir(dir string) (modulePath, moduleDir string, ok bool) {
current := filepath.Clean(dir)
for {
goMod := filepath.Join(current, "go.mod")
if info, err := os.Stat(goMod); err == nil && !info.IsDir() {
modulePath, err := readModulePath(goMod)
if err == nil && modulePath != "" {
return modulePath, current, true
}
}

parent := filepath.Dir(current)
if parent == current {
return "", "", false
}
current = parent
}
}

func readModulePath(goMod string) (string, error) {
data, err := os.ReadFile(goMod)
if err != nil {
return "", err
}

for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
line, _, _ = strings.Cut(line, "//")
fields := strings.Fields(line)
if len(fields) >= 2 && fields[0] == "module" {
return fields[1], nil
}
}

return "", nil
}

func (d *defaultDirContext) GetCall() Dir {
return d.inner[call]
}
Expand Down
Loading