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
29 changes: 21 additions & 8 deletions .github/tools/bump_index.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
# updater does it for every package (`xpkgindex-update.yml`, pinned
# openxlings/xpkgindex-update): it discovers the release from the recipe's
# `extensions.autoupdate.source` (xlings-res/<project> releases), requires the
# GLOBAL and CN resources, computes each sha256 and opens
# `auto/bump-xim-<project>-<version>`. The script that used to do this here,
# GLOBAL and CN resources, computes each sha256 and opens a PR whose body
# starts with `<!-- xpkgindex-update: {"id":"xim:<project>","candidate":"<version>"} -->`
# (its branch, `auto/bump-xim-<project>`, does not name the version, so the
# marker is what identifies the proposal). The script that used to do this here,
# `.github/scripts/version-check.py`, was removed from the index by that
# change; 2026.10.24.1 is the release that found out (publish-ecosystem
# failed on the missing file). Asking the index's own updater keeps one writer
Expand All @@ -17,27 +19,38 @@
#
# Usage: bump_index.sh <project> <version> # e.g. mcpp 2026.10.24.1
# Auth:
# PKGINDEX_TOKEN (required) -- may dispatch workflows of openxlings/xim-pkgindex
# PKGINDEX_TOKEN (required) -- a token with Actions: write on
# openxlings/xim-pkgindex (a workflow dispatch needs that permission;
# Contents and Pull requests do not grant it)
set -euo pipefail

PROJ="${1:?usage: bump_index.sh <project> <version>}"
VER="${2:?usage: bump_index.sh <project> <version>}"
INDEX_REPO="${INDEX_REPO:-openxlings/xim-pkgindex}"
BRANCH="auto/bump-xim-${PROJ}-${VER}"
export MARKER="<!-- xpkgindex-update: {\"id\":\"xim:${PROJ}\",\"candidate\":\"${VER}\"} -->"
WAIT_S="${BUMP_WAIT_S:-1200}"
export GH_TOKEN="${PKGINDEX_TOKEN:?PKGINDEX_TOKEN required (dispatch on $INDEX_REPO)}"

info() { echo "[bump] $*"; }

pr_url() { gh pr view "$BRANCH" -R "$INDEX_REPO" --json url --jq .url 2>/dev/null || true; }
# The updater's PR for this version, open or merged.
pr_url() {
gh pr list -R "$INDEX_REPO" --state all --limit 50 --json url,body,state \
--jq '[.[] | select(.state != "CLOSED" and (.body | startswith(env.MARKER)))][0].url // empty' \
2>/dev/null || true
}

if url="$(pr_url)" && [[ -n "$url" ]]; then
info "PR already open: $url"
info "PR already proposed: $url"
exit 0
fi

info "dispatching xpkgindex-update.yml for xim:$PROJ"
gh workflow run xpkgindex-update.yml -R "$INDEX_REPO" --ref main -f "package=xim:$PROJ"
if ! gh workflow run xpkgindex-update.yml -R "$INDEX_REPO" --ref main -f "package=xim:$PROJ"; then
echo "[bump] PKGINDEX_TOKEN cannot dispatch on $INDEX_REPO (it needs Actions: write);" \
"a maintainer runs: gh workflow run xpkgindex-update.yml -R $INDEX_REPO --ref main -f package=xim:$PROJ" >&2
exit 1
fi

deadline=$(( $(date +%s) + WAIT_S ))
while (( $(date +%s) < deadline )); do
Expand All @@ -50,6 +63,6 @@ done

# BLOCKING: without the PR the index never learns the release exists. The
# updater's run says why (a resource missing on one host, a policy refusal).
echo "[bump] no $BRANCH after ${WAIT_S}s; see" \
echo "[bump] no PR for xim:$PROJ $VER after ${WAIT_S}s; see" \
"https://github.com/$INDEX_REPO/actions/workflows/xpkgindex-update.yml" >&2
exit 1
19 changes: 19 additions & 0 deletions .github/tools/upgrade_lane.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
# revisions (llvm revision 0, gcc 16.1.0 before -r1).
# orphan every payload recorded at another revision, and `c++` active at
# gcc's version whose registration is gone (a reported home).
# modules a module dependency the previous release compiled is served from
# its cache when the spelling of its BMI has not moved.
# programs the previous release builds an ok image, whose platform's build
# program imports mcpp.plugins over the engine interface (`mcpp`);
# this commit's mcpp builds it again over that cache, and no
# library compiled against another interface is served ("CRC
# mismatch").
#
# Asserted, every variant: the first `mcpp new && mcpp run` of the new mcpp
# succeeds and downloads nothing; a second run likewise; `mcpp self doctor`
Expand Down Expand Up @@ -158,6 +165,12 @@ if [ "$VARIANT" = modules ]; then
fi
new_project p-old "$OLD"
run old-run "$W/p-old" "$OLD" run || fail "the previous release cannot run a new project"
case "$PLAT" in linux-x86_64) OK_TARGET=x86_64-openkal ;; *) OK_TARGET=aarch64-openkal ;; esac
if [ "$VARIANT" = programs ]; then
new_project k-old "$OLD"
run old-programs "$W/k-old" "$OLD" build --target "$OK_TARGET" \
|| fail "the previous release cannot build an ok image"
fi

if [ "$VARIANT" = orphan ]; then
"$PY" - "$REG" <<'PY' || fail "could not shape the orphan home"
Expand Down Expand Up @@ -238,6 +251,12 @@ if [ "$VARIANT" = modules ]; then
grep -q "STAGE gcm.cache/mcpplibs.openkal/" "$W/new-modules2.log" \
|| fail "the rebuilt dependency was not served from the cache"
fi
if [ "$VARIANT" = programs ]; then
run new-programs "$W/k-old" "$NEW" build --target "$OK_TARGET" \
|| fail "the ok image the previous release built does not build over its cache"
grep -q "CRC mismatch" "$W/new-programs.log" \
&& fail "a build program's library compiled against the previous engine interface was served"
fi
if [ "$VARIANT" = orphan ]; then
run new-provision "$W" "$NEW" toolchain install "$TC" || fail "toolchain install could not replace the payload"
grep -q "installed asset registration missing" "$W/new-provision.log" \
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci-upgrade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
- { host: linux-x86_64, runs-on: ubuntu-24.04, variant: snapshot }
- { host: linux-x86_64, runs-on: ubuntu-24.04, variant: orphan }
- { host: linux-x86_64, runs-on: ubuntu-24.04, variant: modules }
- { host: linux-x86_64, runs-on: ubuntu-24.04, variant: programs }
- { host: linux-aarch64, runs-on: ubuntu-24.04-arm, variant: plain }
- { host: macos-arm64, runs-on: macos-15, variant: plain }
- { host: windows-x86_64, runs-on: windows-latest, variant: plain }
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@ examples/*/target/

# Local review reports (not part of the design record).
/.agents/reviews/

# The logs .github/tools/upgrade_lane.sh copies beside the workspace (CI uploads
# them as an artifact; a local run leaves them here).
/upgrade-lane-logs/
67 changes: 67 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,73 @@
> Each `## [<version>]` section is that release's notes. Entries are written in English
> from 2026.9.28.3 on; earlier entries remain as written.

## [2026.10.28.1] - 2026-10-28

### Fixed

- **A package's cache key covers every package whose module it imports.**
A BMI is bound to the BMIs it read, and the key folded in only the
dependencies a manifest states. A package can import a module its manifest
does not name: the libraries of a build program import the engine
interface (`mcpp`), which the engine adds to the build program's graph.
Such a package was served an entry compiled against another BMI of that
module and failed with "CRC mismatch" (measured: `mcpp.plugins` in a build
of an ok image, over a cache earlier builds had filled). The provider of
each imported module is now an upstream of the importer's key, a declared
edge or not; a module this build generates for a dependency below its
consumer's root is not one (e2e 849). e2e 959 serves a package an
interface it does not declare at two versions; the upgrade lane gains a
`programs` variant that builds an ok image over the previous release's
cache.
- **A build ended by SIGTERM exits 143 however the race falls.** The watcher
that takes a request to end over ends the programs mcpp runs, writes the
cancelled record, runs the cleanups and then ends mcpp as asked; the main
thread, woken by its compiler's end, could return from `main` first with
the build's own failure (exit 1, seen once on CI in e2e 936 H). The end of
`main` now ends mcpp as the request asks, after the watcher has finished.
- **`mcpp emit xpkg --package` names each system's program directory.** The
packages of one program for several systems may place it apart: a Windows
package holds the program at its root, a POSIX one under `bin/` beside the
root's convenience script. The entry registered the first package's
directory for every system, so on Windows xvm pointed at a `bin/` the
package does not have. It now writes `bindir[os.host()]` from a table of
each system's directory when they differ (SPEC-014 §8).
- **`mcpp emit xpkg --package` states the runner dependency with its
namespace** (`deps = { "xim:okrun" }`). A bare name turns ambiguous once a
second index the home lists has a package of that name, and xim-pkgindex's
`check-dep-namespace` refuses it for a published package.
- **The install of an `emit xpkg --package` entry finds the package.** It
looked the archive's directory up with `os.dirs("<name>-0.1.3-*")`, and
libxpkg's `os.dirs` lists `<base>/*` without matching names: no xlings
install of such an entry succeeded. The directory is now the downloaded
archive's name without its extension, which is what `mcpp pack` names it
after, so it holds for every system, architecture and later version; an
archive renamed since it was packed, or a file xim does not unpack, is
refused when the entry is written. `mcpp pack --merge -o <archive>` names
the merged package's directory after its output as `mcpp pack -o` does,
where it kept the first input's, so a merged package is described as
every other is.
- **`mcpp emit xpkg` refuses a word that is not an option.** Each archive is
its own `--package`; `--package a.zip b.zip` (a shell glob's expansion)
described `a.zip` alone and left `b.zip` out without a word.
- **The release proposes its index bump again.** `bump_index.sh` waited for
`auto/bump-xim-mcpp-<version>`, and the index's updater opens
`auto/bump-xim-mcpp`; the proposal is now found by the marker in its body.
A dispatch the token is refused for (it needs Actions: write on
openxlings/xim-pkgindex) names the permission and the command a maintainer
runs.

### Changed

- **`upgrade-lane-logs/` is no longer in the tree.** A local run's logs were
committed with 2026.10.17.1; the directory is ignored, as the lane writes
it beside the workspace for CI to upload.
- **SPEC-014 1.2** states what 2026.10.27.1 already does: a package's name
carries its mode's suffix, a single file's launcher exits 127 on its own
failure, `--merge` takes its container from `[pack] format` before `-o`, and
`--linkage static` moves this machine's row and each `-linux-gnu` `--target`
to musl while a project's own `[build] target` is packed as it is.

## [2026.10.27.1] - 2026-10-27

### Added
Expand Down
7 changes: 5 additions & 2 deletions docs/10-pack-and-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -881,10 +881,13 @@ package.
writes the xim-pkgindex entry (spec 2) of packages this command wrote, from
their `mcpp-package.json`. A universal package is one asset that `linux`,
`macosx` and `windows` install alike, with the runner as a dependency
(`deps = { "okrun" }`) unless the package carries it; packages of one system
(`deps = { "xim:okrun" }`) unless the package carries it; packages of one system
and architecture each make that system's entry, one URL with `${arch}` and a
sha256 per architecture. The install moves the archive's top directory into
place and registers the program with xvm (the `.cmd` launcher on Windows).
place and registers the program with xvm (the `.cmd` launcher on Windows),
from each system's own directory when the packages place the program apart
(a Windows program at the root, a POSIX one under `bin/`). Each archive is its
own `--package`.

### Compression and signing

Expand Down
4 changes: 2 additions & 2 deletions docs/90-build-from-source.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ src/

tests/
├── unit/ 156 C++ tests, discovered by `mcpp test`
└── e2e/ 645 shell scripts against a real binary
└── e2e/ 646 shell scripts against a real binary
```

## Test Organization
Expand All @@ -93,7 +93,7 @@ Two layers, and they answer different questions.
discovers. They exercise a module's contract with no binary and no filesystem
state.

**End-to-end tests** (`tests/e2e/NN_<name>.sh`, 645 files) run a real `mcpp`
**End-to-end tests** (`tests/e2e/NN_<name>.sh`, 646 files) run a real `mcpp`
binary against a real project. `run_all.sh` is the CI entry point. `mcpp test`
does **not** run them.

Expand Down
2 changes: 1 addition & 1 deletion docs/specs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
| [SPEC-011](concurrency.md) | 并发运行:三段、构建目录锁、原子发布、`mcpp.lock` 的乐观写入、取消 | 评审中 v1.0 | 2026-10-26 | mcpp >= 2026.10.26.1 |
| [SPEC-012](human-output.md) | 面向人的输出:两条流、两种介质、行的种类、颜色 | 评审中 v1.0 | 2026-10-26 | mcpp >= 2026.10.26.1 |
| [SPEC-013](platforms.md) | 平台:`[platform]` 的七组键、版本组与 `hosted`,三种写法与层次,目标图与宿主图的选择,`cfg(platform)`,依赖图的补全,链接、命名与封装,运行器与载体,平台阶段与协议 17 | 评审中 v1.0 | 2026-10-28 | mcpp >= 2026.10.27.1 |
| [SPEC-014](packaging.md) | 打包与分发:链接、闭包、容器三个维度与构建腿,暂存树与 `mcpp-package.json`,通用包、单文件、签名、压缩、合并与分发描述 | 评审中 v1.0 | 2026-10-28 | mcpp >= 2026.10.27.1;逐条标注 |
| [SPEC-014](packaging.md) | 打包与分发:链接、闭包、容器三个维度与构建腿,暂存树与 `mcpp-package.json`,通用包、单文件、签名、压缩、合并与分发描述 | 评审中 v1.2 | 2026-10-28 | mcpp >= 2026.10.28.1;逐条标注 |

## 文档约定

Expand Down
Loading
Loading