wecisecode 4 روز پیش
والد
کامیت
7a9760b1c9

+ 540 - 0
aitool/godeps/dep-analyzer.go

@@ -0,0 +1,540 @@
+package main
+
+import (
+	"encoding/json"
+	"flag"
+	"fmt"
+	"go/parser"
+	"go/token"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+	"sync"
+)
+
+// DependencyGraph 表示依赖关系图
+type DependencyGraph struct {
+	Packages map[string]*PackageInfo
+	Mutex    sync.RWMutex
+}
+
+// PackageInfo 表示包的信息
+type PackageInfo struct {
+	Name       string
+	Path       string
+	Imports    []string
+	ImportedBy []string
+	IsExternal bool
+	IsStandard bool
+}
+
+// DependencyEdge 表示依赖边
+type DependencyEdge struct {
+	From string `json:"from"`
+	To   string `json:"to"`
+}
+
+// DependencyOutput 输出结构
+type DependencyOutput struct {
+	Packages []PackageOutput  `json:"packages"`
+	Edges    []DependencyEdge `json:"edges"`
+}
+
+// PackageOutput 包输出结构
+type PackageOutput struct {
+	Name       string   `json:"name"`
+	Path       string   `json:"path"`
+	Imports    []string `json:"imports"`
+	ImportedBy []string `json:"imported_by,omitempty"`
+	IsExternal bool     `json:"is_external"`
+	IsStandard bool     `json:"is_standard"`
+}
+
+func main() {
+	// 解析命令行参数
+	rootDir := flag.String("dir", ".", "要扫描的Go工程目录")
+	outputFormat := flag.String("format", "text", "输出格式: text, json, dot, csv")
+	outputFile := flag.String("output", "", "输出文件路径(默认输出到控制台)")
+	ignoreStdLib := flag.Bool("ignore-std", false, "忽略标准库依赖")
+	includeTests := flag.Bool("include-tests", false, "包含测试文件")
+	flag.Parse()
+
+	// 检查目录是否存在
+	if _, err := os.Stat(*rootDir); os.IsNotExist(err) {
+		fmt.Printf("错误: 目录不存在: %s\n", *rootDir)
+		os.Exit(1)
+	}
+
+	// 构建依赖图
+	graph := &DependencyGraph{
+		Packages: make(map[string]*PackageInfo),
+	}
+
+	fmt.Printf("正在扫描目录: %s\n", *rootDir)
+
+	// 扫描Go文件
+	err := scanDirectory(*rootDir, graph, *includeTests)
+	if err != nil {
+		fmt.Printf("扫描错误: %v\n", err)
+		os.Exit(1)
+	}
+
+	// 计算导入关系
+	calculateImportedBy(graph)
+
+	// 生成输出
+	output := generateOutput(graph, *ignoreStdLib)
+
+	// 输出结果
+	err = outputResult(output, *outputFormat, *outputFile)
+	if err != nil {
+		fmt.Printf("输出错误: %v\n", err)
+		os.Exit(1)
+	}
+
+	fmt.Printf("\n扫描完成! 共发现 %d 个包,%d 个依赖关系\n",
+		len(output.Packages), len(output.Edges))
+}
+
+// scanDirectory 递归扫描目录
+func scanDirectory(dir string, graph *DependencyGraph, includeTests bool) error {
+	return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+
+		// 跳过vendor目录和隐藏目录
+		if info.IsDir() {
+			if strings.Contains(path, "vendor") || strings.HasPrefix(filepath.Base(path), ".") {
+				return filepath.SkipDir
+			}
+			return nil
+		}
+
+		// 只处理.go文件
+		if filepath.Ext(path) != ".go" {
+			return nil
+		}
+
+		// 可选跳过测试文件
+		if !includeTests && strings.HasSuffix(path, "_test.go") {
+			return nil
+		}
+
+		// 解析Go文件
+		analyzeGoFile(path, graph)
+		return nil
+	})
+}
+
+// analyzeGoFile 分析单个Go文件
+func analyzeGoFile(filePath string, graph *DependencyGraph) {
+	fset := token.NewFileSet()
+	node, err := parser.ParseFile(fset, filePath, nil, parser.ImportsOnly)
+	if err != nil {
+		fmt.Printf("警告: 无法解析文件 %s: %v\n", filePath, err)
+		return
+	}
+
+	// 获取包名和相对路径
+	relPath, _ := filepath.Rel(".", filepath.Dir(filePath))
+	if relPath == "." {
+		relPath = ""
+	}
+	packagePath := relPath
+	if packagePath == "" {
+		packagePath = "."
+	}
+
+	// 创建或获取包信息
+	graph.Mutex.Lock()
+	packageInfo, exists := graph.Packages[packagePath]
+	if !exists {
+		packageInfo = &PackageInfo{
+			Name:       node.Name.Name,
+			Path:       packagePath,
+			Imports:    []string{},
+			ImportedBy: []string{},
+		}
+		graph.Packages[packagePath] = packageInfo
+	}
+	graph.Mutex.Unlock()
+
+	// 收集导入
+	var imports []string
+	for _, imp := range node.Imports {
+		importPath := strings.Trim(imp.Path.Value, `"`)
+		imports = append(imports, importPath)
+	}
+
+	// 更新导入列表(去重)
+	graph.Mutex.Lock()
+	existingImports := make(map[string]bool)
+	for _, imp := range packageInfo.Imports {
+		existingImports[imp] = true
+	}
+	for _, imp := range imports {
+		if !existingImports[imp] {
+			packageInfo.Imports = append(packageInfo.Imports, imp)
+		}
+	}
+	graph.Mutex.Unlock()
+}
+
+// calculateImportedBy 计算每个包被哪些包导入
+func calculateImportedBy(graph *DependencyGraph) {
+	graph.Mutex.Lock()
+	defer graph.Mutex.Unlock()
+
+	// 清空现有的importedBy
+	for _, pkg := range graph.Packages {
+		pkg.ImportedBy = []string{}
+		pkg.IsExternal = false
+		pkg.IsStandard = true // 先假设是标准库,后续会修正
+	}
+
+	// 遍历所有包,构建导入关系
+	for pkgPath, pkg := range graph.Packages {
+		for _, imp := range pkg.Imports {
+			// 标记外部包和标准库
+			if isStandardPackage(imp) {
+				// 如果是标准库,检查是否在已有包中
+				if _, exists := graph.Packages[imp]; !exists {
+					graph.Packages[imp] = &PackageInfo{
+						Name:       filepath.Base(imp),
+						Path:       imp,
+						IsStandard: true,
+					}
+				}
+			} else {
+				// 外部包
+				if importedPkg, exists := graph.Packages[imp]; exists {
+					importedPkg.IsExternal = true
+					importedPkg.IsStandard = false
+				}
+			}
+
+			// 添加importedBy关系
+			if importedPkg, exists := graph.Packages[imp]; exists {
+				importedPkg.ImportedBy = append(importedPkg.ImportedBy, pkgPath)
+			}
+		}
+	}
+
+	// 标记项目内部的包
+	for pkgPath, pkg := range graph.Packages {
+		if _, exists := graph.Packages[pkgPath]; exists && !pkg.IsExternal {
+			// 如果路径中包含.或者没有/,可能是本地包
+			if strings.Contains(pkgPath, ".") || !strings.Contains(pkgPath, "/") {
+				pkg.IsStandard = true
+			} else {
+				pkg.IsStandard = false
+			}
+		}
+	}
+}
+
+// isStandardPackage 检查是否是标准库包
+func isStandardPackage(pkgPath string) bool {
+	// 标准库通常不包含域名
+	if strings.Contains(pkgPath, ".") {
+		return false
+	}
+
+	// 常见的一级标准库目录
+	stdLibs := map[string]bool{
+		"fmt":       true,
+		"io":        true,
+		"net":       true,
+		"http":      true,
+		"os":        true,
+		"strings":   true,
+		"strconv":   true,
+		"encoding":  true,
+		"json":      true,
+		"xml":       true,
+		"time":      true,
+		"sync":      true,
+		"math":      true,
+		"sort":      true,
+		"container": true,
+		"crypto":    true,
+		"database":  true,
+		"debug":     true,
+		"embed":     true,
+		"errors":    true,
+		"expvar":    true,
+		"flag":      true,
+		"go":        true,
+		"hash":      true,
+		"html":      true,
+		"image":     true,
+		"index":     true,
+		"log":       true,
+		"mime":      true,
+		"path":      true,
+		"reflect":   true,
+		"regexp":    true,
+		"runtime":   true,
+		"testing":   true,
+		"text":      true,
+		"unicode":   true,
+		"unsafe":    true,
+	}
+
+	// 获取第一级目录
+	firstPart := pkgPath
+	if idx := strings.Index(pkgPath, "/"); idx != -1 {
+		firstPart = pkgPath[:idx]
+	}
+
+	return stdLibs[firstPart]
+}
+
+// generateOutput 生成输出数据
+func generateOutput(graph *DependencyGraph, ignoreStdLib bool) *DependencyOutput {
+	graph.Mutex.RLock()
+	defer graph.Mutex.RUnlock()
+
+	output := &DependencyOutput{
+		Packages: []PackageOutput{},
+		Edges:    []DependencyEdge{},
+	}
+
+	// 收集包信息
+	var packagePaths []string
+	for pkgPath := range graph.Packages {
+		packagePaths = append(packagePaths, pkgPath)
+	}
+	sort.Strings(packagePaths)
+
+	for _, pkgPath := range packagePaths {
+		pkg := graph.Packages[pkgPath]
+
+		// 如果忽略标准库且当前包是标准库,则跳过
+		if ignoreStdLib && pkg.IsStandard {
+			continue
+		}
+
+		// 添加包信息
+		pkgOutput := PackageOutput{
+			Name:       pkg.Name,
+			Path:       pkg.Path,
+			Imports:    make([]string, len(pkg.Imports)),
+			ImportedBy: make([]string, len(pkg.ImportedBy)),
+			IsExternal: pkg.IsExternal,
+			IsStandard: pkg.IsStandard,
+		}
+		copy(pkgOutput.Imports, pkg.Imports)
+		copy(pkgOutput.ImportedBy, pkg.ImportedBy)
+		output.Packages = append(output.Packages, pkgOutput)
+
+		// 添加依赖边(排除指向被忽略的标准库的边)
+		for _, imp := range pkg.Imports {
+			if importedPkg, exists := graph.Packages[imp]; exists {
+				if ignoreStdLib && importedPkg.IsStandard {
+					continue
+				}
+				output.Edges = append(output.Edges, DependencyEdge{
+					From: pkgPath,
+					To:   imp,
+				})
+			}
+		}
+	}
+
+	return output
+}
+
+// outputResult 输出结果
+func outputResult(output *DependencyOutput, format string, outputFile string) error {
+	var result string
+	var err error
+
+	switch format {
+	case "json":
+		result, err = outputJSON(output)
+	case "dot":
+		result, err = outputDOT(output)
+	case "csv":
+		result, err = outputCSV(output)
+	default: // text
+		result, err = outputText(output)
+	}
+
+	if err != nil {
+		return err
+	}
+
+	// 输出到文件或控制台
+	if outputFile != "" {
+		err = os.WriteFile(outputFile, []byte(result), 0644)
+		if err != nil {
+			return err
+		}
+		fmt.Printf("结果已保存到: %s\n", outputFile)
+	} else {
+		fmt.Println(result)
+	}
+
+	return nil
+}
+
+// outputText 文本格式输出
+func outputText(output *DependencyOutput) (string, error) {
+	var builder strings.Builder
+
+	builder.WriteString("=== 包依赖分析报告 ===\n\n")
+
+	// 按类型分组
+	var stdPackages, localPackages, extPackages []PackageOutput
+	for _, pkg := range output.Packages {
+		if pkg.IsStandard {
+			stdPackages = append(stdPackages, pkg)
+		} else if pkg.IsExternal {
+			extPackages = append(extPackages, pkg)
+		} else {
+			localPackages = append(localPackages, pkg)
+		}
+	}
+
+	// 输出本地包
+	if len(localPackages) > 0 {
+		builder.WriteString("本地包:\n")
+		for _, pkg := range localPackages {
+			builder.WriteString(fmt.Sprintf("  %s (%s)\n", pkg.Path, pkg.Name))
+			if len(pkg.Imports) > 0 {
+				builder.WriteString("    导入:\n")
+				for _, imp := range pkg.Imports {
+					builder.WriteString(fmt.Sprintf("      - %s\n", imp))
+				}
+			}
+			if len(pkg.ImportedBy) > 0 {
+				builder.WriteString("    被以下包导入:\n")
+				for _, by := range pkg.ImportedBy {
+					builder.WriteString(fmt.Sprintf("      - %s\n", by))
+				}
+			}
+			builder.WriteString("\n")
+		}
+	}
+
+	// 输出外部包
+	if len(extPackages) > 0 {
+		builder.WriteString("外部依赖:\n")
+		for _, pkg := range extPackages {
+			builder.WriteString(fmt.Sprintf("  %s\n", pkg.Path))
+			if len(pkg.ImportedBy) > 0 {
+				builder.WriteString("    被以下包导入:\n")
+				for _, by := range pkg.ImportedBy {
+					builder.WriteString(fmt.Sprintf("      - %s\n", by))
+				}
+			}
+			builder.WriteString("\n")
+		}
+	}
+
+	// 输出标准库(简略)
+	if len(stdPackages) > 0 {
+		builder.WriteString("标准库依赖:\n")
+		libs := make(map[string]bool)
+		for _, pkg := range stdPackages {
+			libs[pkg.Path] = true
+		}
+		var libList []string
+		for lib := range libs {
+			libList = append(libList, lib)
+		}
+		sort.Strings(libList)
+		for _, lib := range libList {
+			builder.WriteString(fmt.Sprintf("  %s\n", lib))
+		}
+	}
+
+	// 依赖统计
+	builder.WriteString("\n=== 依赖统计 ===\n")
+	builder.WriteString(fmt.Sprintf("总包数: %d\n", len(output.Packages)))
+	builder.WriteString(fmt.Sprintf("本地包: %d\n", len(localPackages)))
+	builder.WriteString(fmt.Sprintf("外部包: %d\n", len(extPackages)))
+	builder.WriteString(fmt.Sprintf("标准库: %d\n", len(stdPackages)))
+	builder.WriteString(fmt.Sprintf("依赖关系数: %d\n", len(output.Edges)))
+
+	return builder.String(), nil
+}
+
+// outputJSON JSON格式输出
+func outputJSON(output *DependencyOutput) (string, error) {
+	data, err := json.MarshalIndent(output, "", "  ")
+	if err != nil {
+		return "", err
+	}
+	return string(data), nil
+}
+
+// outputDOT DOT格式输出(用于Graphviz)
+func outputDOT(output *DependencyOutput) (string, error) {
+	var builder strings.Builder
+
+	builder.WriteString("digraph GoDependencies {\n")
+	builder.WriteString("  rankdir=LR;\n")
+	builder.WriteString("  node [shape=box, style=filled];\n\n")
+
+	// 定义节点
+	for _, pkg := range output.Packages {
+		color := "lightblue"
+		if pkg.IsExternal {
+			color = "lightcoral"
+		} else if pkg.IsStandard {
+			color = "lightgrey"
+		}
+
+		builder.WriteString(fmt.Sprintf("  \"%s\" [label=\"%s\", fillcolor=\"%s\"];\n",
+			pkg.Path, pkg.Path, color))
+	}
+
+	builder.WriteString("\n")
+
+	// 定义边
+	for _, edge := range output.Edges {
+		builder.WriteString(fmt.Sprintf("  \"%s\" -> \"%s\";\n", edge.From, edge.To))
+	}
+
+	builder.WriteString("}\n")
+	return builder.String(), nil
+}
+
+// outputCSV CSV格式输出
+func outputCSV(output *DependencyOutput) (string, error) {
+	var builder strings.Builder
+
+	// 写表头
+	builder.WriteString("From,To,Type\n")
+
+	// 写数据
+	for _, edge := range output.Edges {
+		toPkg := findPackage(output.Packages, edge.To)
+
+		depType := "local"
+		if toPkg != nil {
+			if toPkg.IsExternal {
+				depType = "external"
+			} else if toPkg.IsStandard {
+				depType = "standard"
+			}
+		}
+
+		builder.WriteString(fmt.Sprintf("%s,%s,%s\n", edge.From, edge.To, depType))
+	}
+
+	return builder.String(), nil
+}
+
+func findPackage(packages []PackageOutput, path string) *PackageOutput {
+	for _, pkg := range packages {
+		if pkg.Path == path {
+			return &pkg
+		}
+	}
+	return nil
+}

+ 1 - 1
chat/chat.go

@@ -7,7 +7,7 @@ import (
 	"sync"
 	"time"
 
-	"trial/chat/api"
+	"git.wecise.com/wecise/trial/chat/api"
 
 	"gitee.com/wecisecode/util/merrs"
 	"gitee.com/wecisecode/util/mfmt"

+ 1 - 1
chat/chat_test.go

@@ -3,7 +3,7 @@ package chat_test
 import (
 	"testing"
 
-	"trial/chat"
+	"git.wecise.com/wecise/trial/chat"
 
 	"github.com/stretchr/testify/assert"
 )

+ 2 - 1
go-chord/chord_test/chord_test.go

@@ -5,7 +5,8 @@ import (
 	"runtime"
 	"testing"
 	"time"
-	"trial/go-chord"
+
+	"git.wecise.com/wecise/trial/go-chord"
 )
 
 type MultiLocalTrans struct {

+ 2 - 1
go-chord/chord_test/iter_closest_test.go

@@ -4,7 +4,8 @@ import (
 	"fmt"
 	"math/big"
 	"testing"
-	"trial/go-chord"
+
+	"git.wecise.com/wecise/trial/go-chord"
 )
 
 func TestNextClosest(t *testing.T) {

+ 2 - 1
go-chord/chord_test/ring_test.go

@@ -7,7 +7,8 @@ import (
 	"sort"
 	"testing"
 	"time"
-	"trial/go-chord"
+
+	"git.wecise.com/wecise/trial/go-chord"
 )
 
 type MockDelegate struct {

+ 2 - 1
go-chord/chord_test/transport_test.go

@@ -3,7 +3,8 @@ package chord_test
 import (
 	"bytes"
 	"testing"
-	"trial/go-chord"
+
+	"git.wecise.com/wecise/trial/go-chord"
 )
 
 type MockVnodeRPC struct {

+ 2 - 1
go-chord/chord_test/util_test.go

@@ -4,7 +4,8 @@ import (
 	"errors"
 	"testing"
 	"time"
-	"trial/go-chord"
+
+	"git.wecise.com/wecise/trial/go-chord"
 )
 
 func TestRandStabilize(t *testing.T) {

+ 2 - 1
go-chord/chord_test/vnode_test.go

@@ -6,7 +6,8 @@ import (
 	"sort"
 	"testing"
 	"time"
-	"trial/go-chord"
+
+	"git.wecise.com/wecise/trial/go-chord"
 )
 
 func makeVnode() *chord.LocalVnode {

+ 2 - 1
go-chord/tcptransport/net.go

@@ -8,7 +8,8 @@ import (
 	"sync"
 	"sync/atomic"
 	"time"
-	"trial/go-chord"
+
+	"git.wecise.com/wecise/trial/go-chord"
 )
 
 /*

+ 3 - 2
go-chord/tcptransport/net_test.go

@@ -4,8 +4,9 @@ import (
 	"fmt"
 	"testing"
 	"time"
-	"trial/go-chord"
-	"trial/go-chord/tcptransport"
+
+	"git.wecise.com/wecise/trial/go-chord"
+	"git.wecise.com/wecise/trial/go-chord/tcptransport"
 )
 
 func prepRing(port int) (*chord.Config, *tcptransport.TCPTransport, error) {

+ 1 - 1
go.mod

@@ -1,4 +1,4 @@
-module trial
+module git.wecise.com/wecise/trial
 
 go 1.23.0
 

+ 2 - 1
grpc-odbserver/grpc/test/test.go

@@ -6,7 +6,8 @@ import (
 	"log"
 	"net"
 	"time"
-	"trial/grpc-odbserver/grpc/api"
+
+	"git.wecise.com/wecise/trial/grpc-odbserver/grpc/api"
 
 	"google.golang.org/grpc"
 	"gopkg.in/yaml.v3"

+ 3 - 2
grpc-odbserver/main.go

@@ -4,8 +4,9 @@ import (
 	"os"
 	"os/signal"
 	"syscall"
-	"trial/grpc-odbserver/mnode"
-	"trial/grpc-odbserver/msn"
+
+	"git.wecise.com/wecise/trial/grpc-odbserver/mnode"
+	"git.wecise.com/wecise/trial/grpc-odbserver/msn"
 
 	"git.wecise.com/wecise/common/matrix/util"
 	z "git.wecise.com/wecise/mring/z/m"

+ 2 - 1
grpc-odbserver/matrix/topo.go

@@ -6,7 +6,8 @@ import (
 	"log"
 	"net"
 	"time"
-	"trial/grpc-odbserver/grpc/api"
+
+	"git.wecise.com/wecise/trial/grpc-odbserver/grpc/api"
 
 	"google.golang.org/grpc"
 	"gopkg.in/yaml.v3"

+ 2 - 1
grpc-odbserver/mnode/mnode.go

@@ -2,7 +2,8 @@ package mnode
 
 import (
 	"sync"
-	"trial/grpc-odbserver/api"
+
+	"git.wecise.com/wecise/trial/grpc-odbserver/api"
 
 	"git.wecise.com/wecise/mring/matrix"
 	"git.wecise.com/wecise/mring/mnet"

+ 2 - 1
grpc-odbserver/mnode/topo.go

@@ -5,7 +5,8 @@ import (
 	"fmt"
 	"log"
 	"time"
-	"trial/grpc-odbserver/grpc/api"
+
+	"git.wecise.com/wecise/trial/grpc-odbserver/grpc/api"
 
 	"google.golang.org/grpc"
 	"gopkg.in/yaml.v3"

+ 4 - 4
ping/ping.go

@@ -13,14 +13,14 @@ import (
 	"sync/atomic"
 	"time"
 
-	"trial/ping/probing"
-	"trial/ping/probing/icmp"
-	"trial/ping/utils"
+	"git.wecise.com/wecise/trial/ping/probing"
+	"git.wecise.com/wecise/trial/ping/probing/icmp"
+	"git.wecise.com/wecise/trial/ping/utils"
 
 	"git.wecise.com/wecise/common/matrix/util"
-	"github.com/scylladb/go-set/strset"
 	"gitee.com/wecisecode/util/cfg"
 	"gitee.com/wecisecode/util/logger"
+	"github.com/scylladb/go-set/strset"
 )
 
 type task struct {

+ 2 - 1
ping/probing/mpconn.go

@@ -6,7 +6,8 @@ import (
 	"sync"
 	"sync/atomic"
 	"time"
-	"trial/ping/probing/icmp"
+
+	"git.wecise.com/wecise/trial/ping/probing/icmp"
 
 	"github.com/google/uuid"
 )