Restructure the monorepo into clear top-level directories: - backend/: Go module root (cmd, internal, pkg, configs, migrations, docs/swagger, scripts, tests, go.mod, Makefile, .air.toml) - deploy/: Docker (Dockerfile, docker-compose*), quickstart, fluentd - docs/: project documentation + reports/ (moved from repo root) - AGENTS.md: new AI coding-agent guide at repo root Update all references to the new layout: - Dockerfile: COPY backend/go.mod, COPY backend/ (context = repo root) - docker-compose files: context ../.., dockerfile deploy/docker/Dockerfile, env_file ../../.env, volume mounts ../../backend:/app - deploy/quickstart/compose.yaml: dockerfile deploy/docker/Dockerfile - CI: working-directory: backend for go commands, file deploy/docker/Dockerfile, coverage path backend/coverage.out, health_check backend/scripts/ - backend/Makefile: docker target uses -f ../deploy/docker/Dockerfile ../ - README: architecture tree, quickstart, config paths updated Move root stray scripts (rename_models.*, run_m11_tests.sh, verify_build.sh, gorm_bool_main.go) to backend/scripts/legacy/. All moves via git mv to preserve history. Build, vet, SQLite tests, and docker compose config verified.
92 lines
3.4 KiB
Python
92 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Scan router.go for Gin radix tree param name conflicts.
|
|
Gin requires all routes at the same URL position to use the same param name.
|
|
|
|
Strategy: Build a prefix tree, find all positions where multiple param names are used.
|
|
"""
|
|
import re
|
|
|
|
with open('/home/yanghao05/Workspace/gochat/internal/router/router.go') as f:
|
|
lines = f.readlines()
|
|
|
|
# Track Group nesting to build full paths
|
|
group_stack = [] # list of (var_name, prefix_path)
|
|
routes = []
|
|
|
|
# Parse the file line by line
|
|
for i, line in enumerate(lines):
|
|
stripped = line.strip()
|
|
if stripped.startswith('//') or not stripped:
|
|
continue
|
|
|
|
# Detect Group definition: varName := parent.Group("/path")
|
|
gmatch = re.match(r'(\w+)\s*:?=\s*(\w+)\.Group\("([^"]+)"\)', stripped)
|
|
if gmatch:
|
|
var_name = gmatch.group(1)
|
|
parent = gmatch.group(2)
|
|
path = gmatch.group(3)
|
|
# Find parent prefix
|
|
parent_prefix = ''
|
|
for name, prefix in group_stack:
|
|
if name == parent:
|
|
parent_prefix = prefix
|
|
break
|
|
full_prefix = parent_prefix + path
|
|
group_stack.append((var_name, full_prefix))
|
|
continue
|
|
|
|
# Detect route registration: var.Method("/path", handler)
|
|
for method in ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']:
|
|
pattern = rf'^(\w+)\.{method}\("([^"]+)"\s*,'
|
|
rmatch = re.match(pattern, stripped)
|
|
if rmatch:
|
|
var_name = rmatch.group(1)
|
|
path = rmatch.group(2)
|
|
# Find prefix for this group variable
|
|
prefix = ''
|
|
for name, p in group_stack:
|
|
if name == var_name:
|
|
prefix = p
|
|
break
|
|
full_path = prefix + path
|
|
routes.append((method, full_path, i+1))
|
|
break
|
|
|
|
# Now build a radix-tree-like structure to find conflicts
|
|
# At each path segment position, track all param names seen
|
|
tree = {} # key: tuple of segments up to a position -> set of param names at that position
|
|
|
|
for method, path, linenum in routes:
|
|
segments = [s for s in path.split('/') if s] # skip empty segments
|
|
for pos, seg in enumerate(segments):
|
|
if seg.startswith(':'):
|
|
param_name = seg[1:]
|
|
prefix_key = '/'.join(segments[:pos])
|
|
if prefix_key not in tree:
|
|
tree[prefix_key] = {}
|
|
if pos not in tree[prefix_key]:
|
|
tree[prefix_key][pos] = {}
|
|
if param_name not in tree[prefix_key][pos]:
|
|
tree[prefix_key][pos][param_name] = []
|
|
tree[prefix_key][pos][param_name].append((method, path, linenum))
|
|
|
|
# Find conflicts
|
|
print("=== Gin路由参数名冲突检测 ===\n")
|
|
conflicts_found = 0
|
|
for prefix, positions in sorted(tree.items()):
|
|
for pos, names_dict in positions.items():
|
|
if len(names_dict) > 1:
|
|
names = sorted(names_dict.keys())
|
|
conflicts_found += 1
|
|
print(f"冲突 #{conflicts_found}: 前缀 '{prefix}' 位置 {pos}")
|
|
print(f" 参数名: {names}")
|
|
for name, refs in names_dict.items():
|
|
print(f" :{name} 的使用:")
|
|
for method, path, linenum in refs[:3]:
|
|
print(f" Line {linenum}: {method} {path}")
|
|
if len(refs) > 3:
|
|
print(f" ... (还有 {len(refs)-3} 条)")
|
|
print()
|
|
|
|
print(f"总计冲突: {conflicts_found}") |