Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,16 @@ jobs:
fetch-depth: 0
- name: Install lua
run: sudo apt-get install -y --no-install-recommends lua5.4
# The dependencies stated by the manifests inside packages' archives,
# read by tests/select_members.py. An archive is pinned by its sha256,
# so an entry never goes stale; a new key per descriptor set keeps the
# entries of the previous one and adds the archives it adds.
- name: Restore the archive manifests read before
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/select-manifests.json
key: select-manifests-${{ hashFiles('pkgs/**/*.lua') }}
restore-keys: select-manifests-
# ── Selective member testing ──────────────────────────────────────
# `mcpp test --workspace` builds every member (opencv, ffmpeg, …) and
# dominates CI wall-clock, while a PR almost always touches one
Expand Down Expand Up @@ -830,7 +840,7 @@ jobs:
changed=""
fi
printf 'changed files vs %s:\n%s\n' "${base:-<none>}" "$changed"
sel=""; pkgsel=""
sel=""; pkgsel=""; descriptors=""
add() { case " $sel " in *" $1 "*) ;; *) sel="$sel $1" ;; esac; }
while IFS= read -r f; do
[ -n "$f" ] || continue
Expand All @@ -856,15 +866,11 @@ jobs:
if [ -d "tests/examples/$m" ] || [ -d "tests/mwrap/$m" ]; then add "$m"; fi ;;
pkgs/*.lua|pkgs/*/*.lua)
# A DELETED descriptor is in the diff but not on disk, and its
# CN urls are gone with it — nothing left to reach.
# CN urls are gone with it — nothing left to reach. The members
# it reaches are selected after the loop, all descriptors at
# once (tests/select_members.py).
if [ -f "$f" ]; then pkgsel="$pkgsel $f"; fi
lib=$(basename "$f" .lua); lib=${lib##*.}
hit=0
for mt in tests/examples/*/mcpp.toml tests/mwrap/*/mcpp.toml; do
[ -f "$mt" ] || continue
if grep -Fq "$lib" "$mt"; then add "$(basename "$(dirname "$mt")")"; hit=1; fi
done
[ "$hit" = 1 ] || echo "note: no workspace member exercises $f" ;;
descriptors="$descriptors $f" ;;
# tools/ holds OFFLINE descriptor-generation and publishing
# helpers (tools/compat-*/, tools/gtc/, publish_mcpp_index.sh).
# Nothing under it is consumed by a package build: when one of
Expand All @@ -890,6 +896,18 @@ jobs:
done <<EOF
$changed
EOF
# The members a changed descriptor reaches: those whose declared
# dependency graph holds its identity, directly or through other
# packages of this index (tests/select_members.py says how the
# graph is read). It replaced a substring search for the short name,
# under which pkgs/o/os.lua selected 113 members and two consumed it.
python3 tests/test_select_members.py
if [ -n "$descriptors" ]; then
for m in $(python3 tests/select_members.py ${base:+--base "$base"} \
--cache "$RUNNER_TEMP/select-manifests.json" $descriptors); do
add "$m"
done
fi
sel=${sel# }
echo "MEMBERS=$sel" >> "$GITHUB_ENV"
echo "selected members: ${sel:-<none>}"
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@

### Changed

- **CI 按包身份选择受影响的成员。** `validate.yml` 的 select 曾在成员清单中查找描述符短名的
子串:`pkgs/o/os.lua` 选中 205 个成员中的 113 个(`boost-*`、`macos`、`cfg(os = ...)`、
注释里的 `exists`),而经 asio、curl 依赖 `compat.openssl` 的成员一个也未选中。
`tests/select_members.py` 以 mcpp 的规则读取成员声明的 `(namespace, name)`,沿描述符的
`deps` 与包归档内清单(按 tag 读 raw.githubusercontent.com;release 资产则读归档本身,
并经 `path` 依赖到达同一归档的其他清单)陈述的依赖求传递闭包,选出依赖图含被修改身份的成员。
归档以 sha256 固定,已读结果由 `actions/cache` 保存。读不到的清单记为警告,由每周全量运行覆盖。
- **`compat.sycl-runtime` 在 Linux 上要求 `mcpp:c++-abi=libstdc++`。** `libsycl.so` 在 libstdc++
上抛出 `sycl::exception`,而一个进程中的两套 C++ 运行时之间带类型的 `catch` 不会匹配
(mcpp-community/mcpp#838)。gcc 工具链,或 llvm 加 `gcc.libstdcxx`,满足该要求;其他构建
Expand Down
76 changes: 76 additions & 0 deletions tests/descriptor_identities.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
-- Print what each descriptor declares about itself and about its neighbours:
--
-- <file> TAB <namespace> TAB <name> TAB <dependency>,... TAB <archive>#<manifest> ...
--
-- A dependency is a key of any `deps` table inside `package`, spelled as the
-- descriptor spells it (`compat.openssl`, `compat:openssl`, `zlib`); the
-- reader of this output (tests/select_members.py) resolves the spelling
-- against the identities printed here.
--
-- The last column is where the rest of the package's dependencies are stated
-- when the descriptor does not state them: a package whose `mcpp` is not an
-- inline table builds from the manifest inside its archive (`mcpp =
-- "*/ld/mcpp.toml"`, or `mcpp.toml` at the archive's root when the field is
-- absent). One entry per version: the archive's GLOBAL url, `#`, and the
-- manifest's path inside it, prefixed with `?` when the field is absent --
-- the archive may then hold no manifest at all (a package built by xpm, or
-- one whose install() writes it). A descriptor that does not load prints no line.
--
-- Usage: lua5.4 tests/descriptor_identities.lua pkgs/*/*.lua

function import(...)
return setmetatable({}, {__index = function() return function() end end})
end

local function collect(t, out, seen)
if seen[t] then return end
seen[t] = true
for k, v in pairs(t) do
if k == "deps" and type(v) == "table" then
for dk, dv in pairs(v) do
if type(dk) == "string" then out[dk] = true
elseif type(dv) == "string" then out[dv] = true end
end
end
if type(v) == "table" then collect(v, out, seen) end
end
end

for i = 1, #arg do
package = nil
local chunk = loadfile(arg[i], "t")
if chunk then
-- `package = { ... }` is the first statement, so it is populated even
-- if a later top-level line fails under the stubbed `import`.
pcall(chunk)
local p = package
if type(p) == "table" and type(p.name) == "string" then
local deps = {}
collect(p, deps, {})
local list = {}
for d in pairs(deps) do list[#list + 1] = d end
table.sort(list)
local manifests = {}
if type(p.mcpp) ~= "table" then
local inside = "?mcpp.toml"
if type(p.mcpp) == "string" then inside = (p.mcpp:gsub("^%*/", "")) end
local seen = {}
for _, versions in pairs(type(p.xpm) == "table" and p.xpm or {}) do
for _, entry in pairs(type(versions) == "table" and versions or {}) do
local url = type(entry) == "table" and entry.url
if type(url) == "table" then url = url.GLOBAL end
if type(url) == "string" and not seen[url] then
seen[url] = true
manifests[#manifests + 1] = url .. "#" .. inside
end
end
end
table.sort(manifests)
end
print(table.concat({ arg[i],
type(p.namespace) == "string" and p.namespace or "",
p.name, table.concat(list, ","),
table.concat(manifests, " ") }, "\t"))
end
end
end
Loading
Loading