mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-08-15 18:14:08 +00:00
128 lines
3.4 KiB
Julia
128 lines
3.4 KiB
Julia
|
|
#!/usr/bin/env julia
|
|||
|
|
#
|
|||
|
|
# Static audit for docs/src/developer/architecture_layers.md (layers A–C).
|
|||
|
|
# Run from anywhere:
|
|||
|
|
# julia scripts/check_layer_contract.jl [REPO_ROOT]
|
|||
|
|
#
|
|||
|
|
# Uses only Base — no --project required.
|
|||
|
|
|
|||
|
|
const REPO_ROOT = isempty(ARGS) ? dirname(dirname(@__FILE__)) : abspath(ARGS[1])
|
|||
|
|
|
|||
|
|
const INCLUDE_IO_REGEX = r"include\s*\(\s*\"[^\"]*\bio/"
|
|||
|
|
|
|||
|
|
function jl_files(dir::AbstractString)
|
|||
|
|
list = String[]
|
|||
|
|
isdir(dir) || return list
|
|||
|
|
for (root, _, files) in walkdir(dir)
|
|||
|
|
for f in files
|
|||
|
|
endswith(f, ".jl") || continue
|
|||
|
|
push!(list, joinpath(root, f))
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
sort!(list)
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
function code_fragment(line::AbstractString)::SubString{String}
|
|||
|
|
# Ignore trailing `# …` so notes do not false-positive the auditors.
|
|||
|
|
parts = split(line, '#'; limit = 2)
|
|||
|
|
return rstrip(parts[1])
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
function skip_line(line::AbstractString)::Bool
|
|||
|
|
s = strip(line)
|
|||
|
|
isempty(s) && return true
|
|||
|
|
startswith(s, '#') && return true
|
|||
|
|
return false
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
const DOMAIN_FORBIDDEN_SUBSTRINGS = [
|
|||
|
|
"GmshReader",
|
|||
|
|
"read_gmsh_mesh",
|
|||
|
|
"GmshMesh",
|
|||
|
|
"JuliaFEM.Legacy",
|
|||
|
|
"KernelAbstractions",
|
|||
|
|
"CUDABackend",
|
|||
|
|
"MetalBackend",
|
|||
|
|
"AMDGPUBackend",
|
|||
|
|
"oneAPIBackend",
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
const FOUNDATION_EXTRA_SUBSTRINGS = [
|
|||
|
|
"DOFHandler",
|
|||
|
|
"create_structured_box_mesh",
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
function violations_for_line(line::AbstractString, extra_substrings)::Vector{String}
|
|||
|
|
hits = String[]
|
|||
|
|
if occursin(INCLUDE_IO_REGEX, line)
|
|||
|
|
push!(hits, "include(\"…io/…\")")
|
|||
|
|
end
|
|||
|
|
for tok in DOMAIN_FORBIDDEN_SUBSTRINGS
|
|||
|
|
if occursin(tok, line)
|
|||
|
|
push!(hits, tok)
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
for tok in extra_substrings
|
|||
|
|
if occursin(tok, line)
|
|||
|
|
push!(hits, tok)
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
return hits
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
function audit_tree(label::AbstractString, dir::AbstractString, extra_substrings)::Bool
|
|||
|
|
ok = true
|
|||
|
|
rel = relpath(dir, REPO_ROOT)
|
|||
|
|
for path in jl_files(dir)
|
|||
|
|
lineno = 0
|
|||
|
|
for line in eachline(path)
|
|||
|
|
lineno += 1
|
|||
|
|
skip_line(line) && continue
|
|||
|
|
frag = code_fragment(line)
|
|||
|
|
isempty(strip(frag)) && continue
|
|||
|
|
hits = violations_for_line(frag, extra_substrings)
|
|||
|
|
isempty(hits) && continue
|
|||
|
|
ok = false
|
|||
|
|
relfile = relpath(path, REPO_ROOT)
|
|||
|
|
println(stderr, "$relfile:$lineno: [layer contract] $(join(sort!(unique(hits)), ", "))")
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
ok || println(stderr, "($label) violations under $rel")
|
|||
|
|
return ok
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
function main()::Int
|
|||
|
|
src = joinpath(REPO_ROOT, "src")
|
|||
|
|
isdir(src) || error("expected src/ under $REPO_ROOT")
|
|||
|
|
|
|||
|
|
println("Layer contract audit (see docs/src/developer/architecture_layers.md)")
|
|||
|
|
println("Repository: ", REPO_ROOT)
|
|||
|
|
|
|||
|
|
all_ok = true
|
|||
|
|
|
|||
|
|
domains = joinpath(src, "domains")
|
|||
|
|
all_ok &= audit_tree("Layer C (domains)", domains, String[])
|
|||
|
|
|
|||
|
|
foundation_dirs = [
|
|||
|
|
joinpath(src, "topology"),
|
|||
|
|
joinpath(src, "quadrature"),
|
|||
|
|
joinpath(src, "geometry"),
|
|||
|
|
joinpath(src, "basis"),
|
|||
|
|
joinpath(src, "sparse"),
|
|||
|
|
]
|
|||
|
|
for d in foundation_dirs
|
|||
|
|
all_ok &= audit_tree("Layer A (foundation)", d, FOUNDATION_EXTRA_SUBSTRINGS)
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
if all_ok
|
|||
|
|
println("OK — no forbidden coupling patterns found.")
|
|||
|
|
return 0
|
|||
|
|
else
|
|||
|
|
println(stderr, "")
|
|||
|
|
println(stderr, "FAILED — fix imports/includes or move code to an outer layer.")
|
|||
|
|
return 1
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
exit(main())
|