feat: Linux/cloud platform stack (TLS, registry, static/cross, selfhost PM)
ci / build (ubuntu) (push) Has been cancelled
ci / macos smoke (push) Has been cancelled
ci / windows smoke (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
ci / unit + fmt (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / goldens + tools (push) Has been cancelled
ci / apps (push) Has been cancelled
ci / selfhost smoke (push) Has been cancelled
ci / CI gate (push) Has been cancelled
ci / build (ubuntu) (push) Has been cancelled
ci / macos smoke (push) Has been cancelled
ci / windows smoke (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
ci / unit + fmt (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / goldens + tools (push) Has been cancelled
ci / apps (push) Has been cancelled
ci / selfhost smoke (push) Has been cancelled
ci / CI gate (push) Has been cancelled
Ship the QUALITY_PLAN platform focus: thin/minimal runtime, --static/--target, Nexus HTTPS/mTLS with graceful stop, lock checksums + install --locked, selfhost registry (search/add/HTTP), containers, and CI smokes for cloud path.
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
// Session 75 — CTFE tables for embedded / firmware-style use.
|
||||
// Precomputes CRC-8 (poly 0x07) cells at compile time; runtime only indexes them.
|
||||
import Std::Io::{PrintLine, PrintInt};
|
||||
|
||||
const POLY: int = 0x07;
|
||||
|
||||
// One shift step of CRC-8 (MSB-first).
|
||||
const func CrcStep(crc: int) -> int {
|
||||
let c: int = crc & 0xFF;
|
||||
if (c & 0x80) != 0 {
|
||||
return ((c << 1) ^ POLY) & 0xFF;
|
||||
}
|
||||
return (c << 1) & 0xFF;
|
||||
}
|
||||
|
||||
// Fold remaining shift steps (recursive — CTFE-friendly).
|
||||
const func CrcFold(crc: int, bits: int) -> int {
|
||||
if bits <= 0 {
|
||||
return crc & 0xFF;
|
||||
}
|
||||
return CrcFold(CrcStep(crc), bits - 1);
|
||||
}
|
||||
|
||||
const func Crc8Byte(byte: int) -> int {
|
||||
return CrcFold(byte & 0xFF, 8);
|
||||
}
|
||||
|
||||
// Known table cells (full 256-entry array const init is future work).
|
||||
const CRC_0: int = Crc8Byte(0);
|
||||
const CRC_1: int = Crc8Byte(1);
|
||||
const CRC_2: int = Crc8Byte(2);
|
||||
const CRC_65: int = Crc8Byte(65); // 'A'
|
||||
const CRC_255: int = Crc8Byte(255);
|
||||
|
||||
// Table size as CTFE power-of-two (classic embedded pattern).
|
||||
const func Pow2(n: int) -> int {
|
||||
if n <= 0 {
|
||||
return 1;
|
||||
}
|
||||
return 2 * Pow2(n - 1);
|
||||
}
|
||||
const TABLE_SIZE: int = Pow2(8); // 256
|
||||
|
||||
func Crc8Known(b: int) -> int {
|
||||
if b == 0 { return CRC_0; }
|
||||
if b == 1 { return CRC_1; }
|
||||
if b == 2 { return CRC_2; }
|
||||
if b == 65 { return CRC_65; }
|
||||
if b == 255 { return CRC_255; }
|
||||
return -1;
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
PrintInt(TABLE_SIZE);
|
||||
PrintLine("");
|
||||
PrintInt(CRC_0);
|
||||
PrintLine("");
|
||||
PrintInt(CRC_1);
|
||||
PrintLine("");
|
||||
PrintInt(CRC_65);
|
||||
PrintLine("");
|
||||
if TABLE_SIZE != 256 {
|
||||
PrintLine("FAIL ctfe_crc TABLE_SIZE");
|
||||
return 1;
|
||||
}
|
||||
if CRC_0 != 0 {
|
||||
PrintLine("FAIL ctfe_crc CRC_0");
|
||||
return 1;
|
||||
}
|
||||
// Reference: poly 0x07, byte 0x01 → 0x07 after 8 steps
|
||||
if CRC_1 != 7 {
|
||||
PrintLine("FAIL ctfe_crc CRC_1 expected 7");
|
||||
return 1;
|
||||
}
|
||||
let a: int = Crc8Known(1);
|
||||
if a != 7 {
|
||||
PrintLine("FAIL ctfe_crc runtime path");
|
||||
return 1;
|
||||
}
|
||||
PrintLine("PASS ctfe_crc");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# Session 79 — Alpine multi-stage build of http_health with musl (when host
|
||||
# can run docker). The *builder* stage expects a prebuilt Linux binary
|
||||
# produced on Alpine or via musl-gcc:
|
||||
#
|
||||
# # On Alpine / with musl-gcc:
|
||||
# BUX_CC=musl-gcc BUX_RUNTIME=minimal ./buxc --static --release build …
|
||||
# # or: ./tools/smoke_musl_static.sh
|
||||
#
|
||||
# docker build -f examples/docker/Dockerfile.alpine-health -t bux-health-alpine .
|
||||
#
|
||||
# Fallback: copy a glibc binary and use debian (see Dockerfile.health).
|
||||
|
||||
FROM alpine:3.20 AS runtime
|
||||
RUN apk add --no-cache ca-certificates
|
||||
WORKDIR /app
|
||||
# Prefer a static musl binary if present; else fail the build clearly.
|
||||
COPY build/http_health_musl /app/http_health
|
||||
ENV HEALTH_BIND=0.0.0.0
|
||||
ENV HEALTH_PORT=8080
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/app/http_health"]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Session 78 — minimal health probe image (dynamic glibc + no OpenSSL needed if
|
||||
# linked without crypto... full runtime still needs libcrypto today).
|
||||
#
|
||||
# Build binary first:
|
||||
# ./tools/build_health_bin.sh
|
||||
# docker build -f examples/docker/Dockerfile.health -t bux-health .
|
||||
# docker run --rm -p 8080:8080 bux-health
|
||||
|
||||
FROM debian:bookworm-slim
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates libssl3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /app
|
||||
COPY build/http_health /app/http_health
|
||||
ENV HEALTH_BIND=0.0.0.0
|
||||
ENV HEALTH_PORT=8080
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/app/http_health"]
|
||||
@@ -0,0 +1,26 @@
|
||||
# Session 78 — Nexus in a slim runtime image (dynamic link: pthread + OpenSSL).
|
||||
#
|
||||
# From repo root (after building apps/nexus/build/nexus on Linux):
|
||||
# docker build -f examples/docker/Dockerfile.nexus -t bux-nexus .
|
||||
# docker run --rm -p 8080:8080 bux-nexus
|
||||
#
|
||||
# HTTPS:
|
||||
# docker run --rm -p 8443:8443 \
|
||||
# -v $PWD/certs:/certs:ro \
|
||||
# -e NEXUS_PORT=8443 -e NEXUS_TLS=1 \
|
||||
# -e NEXUS_TLS_CERT=/certs/cert.pem -e NEXUS_TLS_KEY=/certs/key.pem \
|
||||
# bux-nexus
|
||||
|
||||
FROM debian:bookworm-slim
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates libssl3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /app
|
||||
COPY apps/nexus/build/nexus /app/nexus
|
||||
COPY apps/nexus/public /app/public
|
||||
ENV NEXUS_BIND=0.0.0.0
|
||||
ENV NEXUS_PORT=8080
|
||||
ENV NEXUS_WORKERS=4
|
||||
ENV NEXUS_ACCESS_LOG=1
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/app/nexus"]
|
||||
@@ -0,0 +1,20 @@
|
||||
# Session 75 — fully-static Bux binary in a distroless/scratch container.
|
||||
#
|
||||
# Build (from repo root):
|
||||
# # 1) produce a static host binary with the bootstrap compiler
|
||||
# ./buxc --static --release build /path/to/pkg
|
||||
# # or use the helper:
|
||||
# ./tools/build_static_hello.sh
|
||||
#
|
||||
# # 2) package it
|
||||
# docker build -f examples/docker/Dockerfile.static \
|
||||
# --build-arg BIN=build/hello_static \
|
||||
# -t bux-hello-static .
|
||||
#
|
||||
# Run:
|
||||
# docker run --rm bux-hello-static
|
||||
|
||||
ARG BIN=build/hello_static
|
||||
FROM scratch
|
||||
COPY ${BIN} /app
|
||||
ENTRYPOINT ["/app"]
|
||||
@@ -0,0 +1,78 @@
|
||||
// Session 78 — tiny health HTTP server for containers / ops probes.
|
||||
// Needs full POSIX runtime (sockets). Not TLS — use Nexus for HTTPS.
|
||||
import Std::Io::{Print, PrintLine, PrintInt};
|
||||
import Std::Net::{Net_Create, Net_SetReuse, Net_Bind, Net_Listen, Net_Accept, Net_Send, Net_Recv, Net_Close};
|
||||
import Std::String::{String_Len, String_Contains, String_FromInt, String_Concat, String_ToInt};
|
||||
import Std::Os::{Os_GetEnv, Os_InstallStopHandlers, Os_ShouldStop, Os_SetStopListenFd};
|
||||
|
||||
func HealthBody() -> String {
|
||||
return "{\"status\":\"ok\",\"server\":\"bux-health\",\"version\":\"0.1.0\"}\n";
|
||||
}
|
||||
|
||||
func BuildHttp(body: String) -> String {
|
||||
let n: int = String_Len(body) as int;
|
||||
return String_Concat(
|
||||
String_Concat(
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: ",
|
||||
String_FromInt(n as int64)
|
||||
),
|
||||
String_Concat("\r\nConnection: close\r\n\r\n", body)
|
||||
);
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
var port: int = 8080;
|
||||
let pe: String = Os_GetEnv("HEALTH_PORT");
|
||||
if String_Len(pe) > 0 {
|
||||
let p: int64 = String_ToInt(pe);
|
||||
if p > 0 && p < 65536 {
|
||||
port = p as int;
|
||||
}
|
||||
}
|
||||
var bind: String = "0.0.0.0";
|
||||
let bindEnv: String = Os_GetEnv("HEALTH_BIND");
|
||||
if String_Len(bindEnv) > 0 {
|
||||
bind = bindEnv;
|
||||
}
|
||||
|
||||
Os_InstallStopHandlers();
|
||||
let fd: int = Net_Create();
|
||||
if fd < 0 {
|
||||
PrintLine("socket failed");
|
||||
return 1;
|
||||
}
|
||||
discard Net_SetReuse(fd);
|
||||
if !Net_Bind(fd, bind, port) {
|
||||
PrintLine("bind failed");
|
||||
return 1;
|
||||
}
|
||||
if !Net_Listen(fd, 64) {
|
||||
PrintLine("listen failed");
|
||||
return 1;
|
||||
}
|
||||
Os_SetStopListenFd(fd);
|
||||
Print("health listening on http://");
|
||||
Print(bind);
|
||||
Print(":");
|
||||
PrintInt(port);
|
||||
PrintLine("");
|
||||
|
||||
let body: String = HealthBody();
|
||||
let resp: String = BuildHttp(body);
|
||||
|
||||
while !Os_ShouldStop() {
|
||||
let c: int = Net_Accept(fd);
|
||||
if c < 0 {
|
||||
if Os_ShouldStop() { break; }
|
||||
continue;
|
||||
}
|
||||
let raw: String = Net_Recv(c, 4096);
|
||||
if String_Contains(raw, "GET ") {
|
||||
discard Net_Send(c, resp);
|
||||
}
|
||||
Net_Close(c);
|
||||
}
|
||||
Net_Close(fd);
|
||||
PrintLine("health: stopped");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Session 76 — `$x:tt` accepts any single call-site AST fragment
|
||||
// (expr, literal, ident, block, stmt wrapper, …). Broader than `:expr`.
|
||||
import Std::Io::{PrintLine, PrintInt};
|
||||
import Std::Test::{Test_Pass};
|
||||
|
||||
// id_tt already existed in macro_repeat; here we also wrap blocks and stmts.
|
||||
macro! id_tt {
|
||||
( $x:tt ) => { $x }
|
||||
}
|
||||
|
||||
macro! wrap_tt {
|
||||
( $x:tt ) => {
|
||||
let v: int = $x;
|
||||
v + 1
|
||||
}
|
||||
}
|
||||
|
||||
// stmt fragment via tt (call site parses `let …` as MacroStmt when using stmt kind;
|
||||
// with tt, expression form still works: wrap values)
|
||||
macro! twice_tt {
|
||||
( $x:tt ) => { $x + $x }
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
let a: int = id_tt!(21);
|
||||
PrintInt(a);
|
||||
PrintLine("");
|
||||
let b: int = wrap_tt!(10);
|
||||
PrintInt(b);
|
||||
PrintLine("");
|
||||
let c: int = twice_tt!(3 + 4);
|
||||
PrintInt(c);
|
||||
PrintLine("");
|
||||
let d: int = id_tt!({ 1 + 2 });
|
||||
PrintInt(d);
|
||||
PrintLine("");
|
||||
if a != 21 || b != 11 || c != 14 || d != 3 {
|
||||
PrintLine("FAIL macro_tt");
|
||||
return 1;
|
||||
}
|
||||
PrintLine("PASS macro_tt");
|
||||
Test_Pass("macro_tt");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// Session 76 — cross-function pointer ownership transfer.
|
||||
// TakeItems(&bag) moves bag.items inside the callee; the caller must not
|
||||
// auto-Drop bag.items (only remaining fields / skip parent Drop).
|
||||
import Std::Io::{PrintLine};
|
||||
import Std::Array::{Array, Array_New, Array_Push, Array_Len, Array_Get};
|
||||
import Std::String::{String_FromInt, String_Concat};
|
||||
import Std::Test::{Test_AssertTrue, Test_Pass};
|
||||
|
||||
@[Drop]
|
||||
struct Tracked {
|
||||
id: int,
|
||||
counter: *int
|
||||
}
|
||||
|
||||
func Tracked_Drop(self: *Tracked) {
|
||||
if self.counter != null as *int {
|
||||
*self.counter = *self.counter + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@[Drop]
|
||||
struct Bag {
|
||||
items: Array<int>,
|
||||
tag: Tracked
|
||||
}
|
||||
|
||||
func Bag_Drop(self: *Bag) {
|
||||
Array_Drop<int>(&self.items);
|
||||
Tracked_Drop(&self.tag);
|
||||
}
|
||||
|
||||
// Callee moves p.items out of the pointee — caller passed &bag.
|
||||
func TakeItems(p: *Bag) -> Array<int> {
|
||||
return p.items;
|
||||
}
|
||||
|
||||
func NestedTake(p: *Bag) -> Array<int> {
|
||||
let moved: Array<int> = p.items;
|
||||
return moved;
|
||||
}
|
||||
|
||||
// Caller holds bag and transfers via &bag into TakeItems.
|
||||
func CallTakeItems(counter: *int) -> int {
|
||||
var items: Array<int> = Array_New<int>(2);
|
||||
Array_Push<int>(&items, 1);
|
||||
Array_Push<int>(&items, 2);
|
||||
let bag: Bag = Bag {
|
||||
items: items,
|
||||
tag: Tracked { id: 1, counter: counter }
|
||||
};
|
||||
let taken: Array<int> = TakeItems(&bag);
|
||||
Test_AssertTrue(Array_Len<int>(&taken) == 2);
|
||||
Test_AssertTrue(Array_Get<int>(&taken, 0) == 1);
|
||||
return Array_Len<int>(&taken) as int;
|
||||
}
|
||||
|
||||
func CallNestedTake(counter: *int) -> int {
|
||||
var items2: Array<int> = Array_New<int>(1);
|
||||
Array_Push<int>(&items2, 9);
|
||||
let bag2: Bag = Bag {
|
||||
items: items2,
|
||||
tag: Tracked { id: 2, counter: counter }
|
||||
};
|
||||
let taken2: Array<int> = NestedTake(&bag2);
|
||||
Test_AssertTrue(Array_Get<int>(&taken2, 0) == 9);
|
||||
return Array_Get<int>(&taken2, 0);
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
var drops: int = 0;
|
||||
|
||||
let n: int = CallTakeItems(&drops);
|
||||
Test_AssertTrue(n == 2);
|
||||
// bag left scope inside CallTakeItems → only tag Drop (items moved out)
|
||||
Test_AssertTrue(drops == 1);
|
||||
|
||||
let v: int = CallNestedTake(&drops);
|
||||
Test_AssertTrue(v == 9);
|
||||
Test_AssertTrue(drops == 2);
|
||||
|
||||
PrintLine(String_Concat("cross_fn_drops=", String_FromInt(drops as int64)));
|
||||
Test_Pass("move_cross_fn");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user