Reorganize repo: backend/, deploy/, docs/ layout + AGENTS.md
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.
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
#!/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}")
|
||||
Reference in New Issue
Block a user