Repository navigation
Expand file tree
/
Copy pathREVIEW.das
More file actions
140 lines (127 loc) · 6.78 KB
/
Copy pathREVIEW.das
File metadata and controls
140 lines (127 loc) · 6.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
options gen2
require strings
require daslib/strings_boost
require daslib/strings_convert
require daslib/fio
require dastest/review_gate
// The mechanical half of REVIEW.md at the repo root (contract: REVIEW_COMMON.md beside it).
// Run from the repo root: bin/daslang REVIEW.das - exit 0 clean, 1 with findings.
struct private SharedTwin {
name : string //!< the shared module name two files may both declare
file : string //!< one of those files; a name's rows together are the whole set allowed to declare it
why : string //!< why no process compiles two of them by accident
}
// A third declaration of a tolerated name is still a finding: the rows are the whole allowed set.
var private TOLERATED_SHARED_TWINS <- [
SharedTwin(name = "foo", file = "tests/module_tests/_modules/conflict/pkgA/foo.das", why = "the module tests compile the pair on purpose, to assert the conflict error"),
SharedTwin(name = "foo", file = "tests/module_tests/_modules/conflict/pkgB/foo.das", why = "the module tests compile the pair on purpose, to assert the conflict error"),
SharedTwin(name = "dupfoo", file = "tests/module_tests/_modules/extra_errors/pkgA/dupfoo.das", why = "the module tests compile the pair on purpose, to assert the conflict error"),
SharedTwin(name = "dupfoo", file = "tests/module_tests/_modules/extra_errors/pkgB/dupfoo.das", why = "the module tests compile the pair on purpose, to assert the conflict error"),
SharedTwin(name = "testing_boost", file = "dastest/testing_boost.das", why = "dastest_wasm/ is the wasm build's own root; the two roots are never compiled together"),
SharedTwin(name = "testing_boost", file = "dastest_wasm/testing_boost.das", why = "dastest_wasm/ is the wasm build's own root; the two roots are never compiled together"),
SharedTwin(name = "sql_provider", file = "daslib/sql_provider.das", why = "the dasSQLITE copy is a deprecation stub that fails to compile by design, pointing here"),
SharedTwin(name = "sql_provider", file = "modules/dasSQLITE/daslib/sql_provider.das", why = "the dasSQLITE copy is a deprecation stub that fails to compile by design, pointing here")
]
//! true when every file declaring `name` is one of the rows tolerating it
def private is_tolerated_set(name : string; files : array<string>) : bool {
for (f in files) {
var listed = false
for (row in TOLERATED_SHARED_TWINS) {
listed ||= row.name == name && row.file == f
}
return false if (!listed)
}
return true
}
//! every tracked file matching one of `globs` - the generated and vendored copies git ignores
//! stay out; a git that fails is a finding, never an empty tree
def private tracked_files(globs : array<string>; check_name : string) : array<string> {
var out : string
var inscope cmd <- ["git", "ls-files", "--"]
cmd |> push_from(globs)
let rc = run_and_capture(cmd, out, 60.0)
var inscope files <- [for (ln in split(out, "\n")); strip(ln); where !empty(strip(ln))]
if (rc != 0 || empty(files)) {
gate_finding("REVIEW.das", "git ls-files failed (exit {rc}, {length(files)} files) - the {check_name} check ran over nothing")
}
return <- files
}
struct private SharedDecl {
name : string
line : int
}
//! the `module <name> ... shared ...` declaration of a file, name "" when it declares none
def private shared_module_decl(path : string) : SharedDecl {
var at = 0
for (line in split(strip_line_comments(fread(path)), "\n")) {
at++
let t = strip(line)
continue if (!(t |> starts_with("module ")))
var inscope toks <- [for (tok in split(t, " ")); tok; where !empty(tok)]
return SharedDecl() if (length(toks) < 3)
for (i in range(2, length(toks))) {
return SharedDecl(name = toks[1], line = at) if (toks[i] == "shared")
}
return SharedDecl()
}
return SharedDecl()
}
def private check_shared_module_names {
var inscope files <- tracked_files(["*.das"], "shared-module")
var sites : table<string; array<string>>
for (f in files) {
let d = shared_module_decl(f)
continue if (empty(d.name))
sites[d.name] |> push("{f}:{d.line}")
}
for (name, decls in keys(sites), values(sites)) {
continue if (length(decls) < 2)
var inscope declaring <- [for (s in decls); slice(s, 0, rfind(s, ":"))]
continue if (is_tolerated_set(name, declaring))
for (s in decls) {
let colon = rfind(s, ":")
let others = join([for (o in decls); o; where o != s], ", ")
gate_finding(slice(s, 0, colon), to_int(slice(s, colon + 1)),
"shared module `{name}` is also declared by {others} - the first file a process compiles that declares it becomes that process's module, and every later file declaring or requiring the name gets that module; rename one, or list every file that may share the name in TOLERATED_SHARED_TWINS with why no process compiles two of them by accident")
}
}
}
def private is_url_download(command : string; args : array<string>) : bool {
if (command == "file") {
return !empty(args) && to_upper(args[0]) == "DOWNLOAD"
}
return find_index(args, "URL") >= 0
}
//! `0`, a variable, or a missing value leaves the download without a timeout
def private has_inactivity_timeout(args : array<string>) : bool {
let at = find_index(args, "INACTIVITY_TIMEOUT")
return at >= 0 && at + 1 < length(args) && (try_to_int(args[at + 1]) ?? 0) > 0
}
def private check_download_timeouts {
var inscope files <- tracked_files(["*CMakeLists.txt", "*.cmake"], "download-timeout")
for (f in files) {
continue if (!fexist(f))
let text = fread(f)
for (command in ["ExternalProject_Add", "FetchContent_Declare", "file"]) {
var inscope calls <- cmake_command_blocks(text, command)
for (call in calls) {
var inscope args <- cmake_args(call)
continue if (!is_url_download(command, args) || has_inactivity_timeout(args))
let shown_command = command == "file" ? "file(DOWNLOAD)" : command
let retry = command == "file" ? "" : " ({command} then retries it and moves on to the next URL)"
gate_finding(f, find_line(text, call),
"{shown_command} downloads from a URL with no positive literal INACTIVITY_TIMEOUT - a server that stops sending leaves the download waiting until the CI job's own time limit kills it; add INACTIVITY_TIMEOUT 60, so a stalled transfer fails instead{retry}")
}
}
}
}
[export]
def main {
if (!fexist("REVIEW_COMMON.md") || !fexist("CMakeLists.txt")) {
to_log(LOG_ERROR, "REVIEW.das: run from the repo root\n")
return 2
}
check_shared_module_names()
check_download_timeouts()
return gate_verdict("repo root")
}