Model declarative FreeBSD source inputs

This commit is contained in:
2026-04-03 11:47:52 +02:00
parent 390bfb248f
commit d89225fe11
9 changed files with 1213 additions and 4 deletions

406
docs/PLAN_4.md Normal file
View File

@@ -0,0 +1,406 @@
# Fruix on FreeBSD, Path D: Declarative Source Acquisition, Installation Artifacts, and the Road to Self-Hosting
This document extends `docs/PLAN_3.md` after the completion of Phases 1 through 15.
The project has now crossed another important threshold:
- Fruix builds native FreeBSD base artifacts from `/usr/src` into `/frx/store`
- the validated boot/runtime path is host-base-free at the deployed system layer
- the FreeBSD base is now an explicit declarative Fruix input
- side-by-side base versions can coexist in `/frx/store`
- Fruix can rebuild, redeploy, and roll back between declared base versions
That means the next question is no longer whether Fruix can assemble and boot a native FreeBSD system. It can.
The next question is how to make that native base path **more reproducible, more source-declarative, and more installable**.
The biggest remaining impurity is now clear:
- the native base build path still relies on the builder host's ambient `/usr/src`
That was the right bridge through Phases 13 to 15, but it should not be the long-term source story.
Accordingly, Plan 4 focuses on three connected goals:
1. make FreeBSD source acquisition and source identity more declarative
2. turn the current image-generation path into a real installation story
3. only then move carefully toward self-hosted base builds
This preserves the Guix-inspired core while continuing to embrace FreeBSD semantics rather than trying to imitate Linux-specific workflows.
Throughout this plan, the canonical Fruix roots remain:
- `/frx/store`
- `/frx/var`
- `/frx/etc`
The user-facing system remains **Fruix**, with CLI `fruix`, while internal upstream-derived names continue to be renamed selectively rather than mechanically.
The current real-VM validation constraints still apply unless explicitly relaxed later:
- approved VM: `90490f2e-e8fc-4b7a-388e-5c26f0157289`
- approved A/B VDIs:
- `0f1f90d3-48ca-4fa2-91d8-fc6339b95743`
- `7061d761-3639-4bec-87f7-2ba1af924eaa`
---
## Current State at the Start of Plan 4
Fruix on FreeBSD already has:
- a functioning content-addressed store and derivation path under `/frx/store`
- daemon-mediated builds with validated FreeBSD isolation concepts
- a working declarative FreeBSD operating-system model
- validated system closure, rootfs, and image generation through `fruix system ...`
- real QEMU and XCP-ng boot validation
- a host-base-free native boot/runtime composition built from:
- `freebsd-native-kernel`
- `freebsd-native-bootloader`
- `freebsd-native-runtime`
- a declarative `freebsd-base` model that records:
- base identity
- version label
- branch
- source root
- target and kernel configuration
- side-by-side native base versions in `/frx/store`
- rollback-friendly redeploy across those declared base versions
- a documented decision to continue using host-built native base artifacts for now rather than jumping immediately to guest self-hosting
The main remaining architectural compromise is now not the runtime/boot artifact split, but the **source boundary**:
- native FreeBSD base builds still use ambient `/usr/src`
- source acquisition is not yet a first-class Fruix-managed input
- therefore reproducibility and provenance still stop short of a fully declared source story
At the same time, Fruix still lacks a real installation workflow beyond image generation and validation harnesses.
---
## Guiding Decision for the Next Milestone
The next major milestone should be:
- **declarative FreeBSD source acquisition and source pinning first**,
- then **native base builds from fetched or materialized source inputs**,
- then a **real installation story**,
- and only after that, a controlled re-evaluation of self-hosted base builds.
This means the next work should optimize for:
- explicit source identity
- stronger provenance
- side-by-side source revisions
- repeatable rebuilds from fetched or materialized source trees
- installation artifacts that are operator-usable beyond current validation harnesses
It should **not** optimize for:
- jumping straight into guest self-hosting while source identity is still weak
- building a large interactive installer before the installation primitives are clear
- replacing the current validated host-built native-base path prematurely
---
## Phase 16: Make FreeBSD Source Acquisition Declarative
This is the next architectural pivot after the native base/runtime split.
The goal is to move from:
- “build from whatever `/usr/src` is on the host”
into:
- “build from a declared FreeBSD source input with explicit provenance.”
### Intermediate Goal 16.1: Model FreeBSD Source Inputs Explicitly
**Verification Goal 16.1:** Introduce a first-class Fruix model for FreeBSD source inputs.
This can be a new `freebsd-source` record, an extension of `freebsd-base`, or another explicit source object, but it should represent at least:
- source kind:
- local checkout snapshot
- fetched Git checkout
- fetched `src.txz` archive
- source URL or local path
- branch or release line
- commit, tag, or revision when applicable
- expected tree or archive hash
- any intended patch queue or source transformation layer
This step should also document how that source object relates to:
- `freebsd-base`
- native kernel/world/runtime/bootloader/headers builds
- output identity in `/frx/store`
**Success Criteria:** Fruix can describe FreeBSD source inputs as explicit declared objects rather than only relying on ambient `/usr/src`.
### Intermediate Goal 16.2: Fetch or Materialize Source Trees Under Fruix Control
**Verification Goal 16.2:** Materialize a clean FreeBSD source tree from a declared source input using Fruix-managed fetch/materialization logic.
The first implementation may be intentionally modest, such as:
- fetching a Git checkout at a pinned revision from `https://git.FreeBSD.org/src.git`
- or downloading a `src.txz` archive and verifying its hash
- for example from `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz`
- or from snapshot paths such as `https://download.freebsd.org/snapshots/amd64/15.0-STABLE/src.txz`
- or snapshotting a local source tree into a content-addressed source artifact with explicit metadata
This phase should also define where downloaded or temporary source material lives, for example under:
- `/frx/var/cache/fruix/freebsd-source`
The important point is that the eventual build input should no longer be “the current mutable host tree” but a **materialized source snapshot with recorded identity**.
**Success Criteria:** Fruix can fetch or materialize a pinned FreeBSD source tree with recorded provenance and a stable identity suitable for native base builds.
### Intermediate Goal 16.3: Build Native Base Artifacts From the Declared Source Input
**Verification Goal 16.3:** Teach the native FreeBSD base build path to consume the declared source artifact rather than ambient `/usr/src`.
This should preserve the validated Plan-3/Plan-4 deployment story:
- native kernel
- native bootloader slice
- native runtime slice
- host-base-free validated path
The goal is not yet to change the successful boot/runtime model, only the **source input boundary**.
**Success Criteria:** Fruix builds native FreeBSD base artifacts from a declared source input, and the resulting store artifacts record that source identity explicitly.
---
## Phase 17: Support Multiple FreeBSD Source Revisions Side by Side
Once source acquisition is explicit, Fruix should prove that it can treat source revisions the way it already treats declared base versions: as side-by-side inputs rather than in-place mutations.
### Intermediate Goal 17.1: Support Side-by-Side FreeBSD Source Revisions in `/frx/store`
**Verification Goal 17.1:** Demonstrate that at least two distinct declared FreeBSD source inputs can coexist and produce distinct native base artifacts in `/frx/store`.
These can differ by:
- Git revision
- source archive hash
- local source snapshot hash
- or another explicit source identity boundary
The goal is to prove that the source declaration, not ambient host state, now drives the base build outputs.
**Success Criteria:** Fruix can hold at least two distinct FreeBSD source revisions side by side as meaningful native base inputs and outputs.
### Intermediate Goal 17.2: Rebuild and Boot From Two Distinct Source Revisions
**Verification Goal 17.2:** Build and boot systems from at least two distinct declared source revisions using the validated native base path.
This should preserve the current validation strategy:
- local QEMU/UEFI/TCG where useful
- real XCP-ng validation on the approved VM and approved A/B VDI path
The booted systems do not necessarily need to differ in obvious runtime behavior; the important point is that their source identity and native base outputs differ and are tracked correctly.
**Success Criteria:** Fruix boots systems built from two distinct declared FreeBSD source revisions and records those revisions in system metadata.
### Intermediate Goal 17.3: Clarify Source Provenance, Caching, and Update Policy
**Verification Goal 17.3:** Document and encode the intended policy for:
- source caching
- source refresh/invalidation
- patch application if any
- tree hashing rules
- when a new source identity should or should not invalidate native base outputs
This step should reduce ambiguity before installation artifacts and later self-hosting experiments depend on these source objects.
**Success Criteria:** the repo clearly explains how FreeBSD source objects are fetched, cached, identified, invalidated, and consumed by native base builds.
---
## Phase 18: Turn System Images Into a Real Installation Story
Fruix can already produce bootable images. The next step is to make installation itself a first-class Fruix story rather than a manual consequence of image generation.
### Intermediate Goal 18.1: Define a Minimal Non-Interactive Installation Flow
**Verification Goal 18.1:** Introduce a minimal installation workflow that can take a Fruix system artifact and install it to a target disk or image in a repeatable way.
The first version should prefer clarity and automation over interactivity. For example, it may:
- partition a target disk
- create required filesystems
- copy or materialize the selected system closure
- install boot assets
- stage activation/runtime metadata
- configure root SSH key or basic operator access
This first step should be VM-friendly and serial-console-friendly.
**Success Criteria:** Fruix can perform a repeatable installation of a declarative system onto a target disk or image without relying on ad hoc manual assembly.
### Intermediate Goal 18.2: Produce a Minimal Installer Environment
**Verification Goal 18.2:** Produce a small installer environment that can boot into a Fruix-managed install context and perform the installation workflow.
This environment may initially be one of:
- a special-purpose disk image
- a minimal recovery/install rootfs
- a proto-installer medium with only the tools needed for partitioning, filesystem creation, and deployment
The target here is not a polished live environment. It is a reliable installer substrate.
**Success Criteria:** Fruix can boot a minimal installer environment and use it to install a selected Fruix system to a target disk.
### Intermediate Goal 18.3: Build a Bootable Installer ISO
**Verification Goal 18.3:** Produce a bootable installer ISO for UEFI systems.
The first ISO can be intentionally narrow in scope. It should be enough to:
- boot under QEMU and, where practical, on the validated virtualization path
- expose the install workflow
- install a target Fruix system
- leave the machine bootable into the installed system
A polished graphical or highly interactive installer is not required here.
**Success Criteria:** Fruix can build a bootable installer ISO that installs a declarative Fruix-on-FreeBSD system.
---
## Phase 19: Strengthen System Deployment and Generation Management
The current deployment model already has the important Guix-like semantic properties at the closure/store layer. This phase is about making that story more operator-facing and less harness-specific.
### Intermediate Goal 19.1: Define a First-Class Fruix Deployment Workflow
**Verification Goal 19.1:** Define and document the canonical user-facing deployment workflow for system rebuild, image generation, installation, and rollback.
This may introduce or refine user-facing commands such as:
- `fruix system build`
- `fruix system image`
- future deployment/install/switch subcommands if justified
The key goal is clarity: operators should have an obvious Fruix way to move between generations and deployments.
**Success Criteria:** the repo documents a coherent user-facing deployment workflow for system build, install, roll-forward, and rollback.
### Intermediate Goal 19.2: Model System Generations More Explicitly
**Verification Goal 19.2:** Make the system-generation story more explicit in metadata and deployment roots.
This should include deciding how Fruix wants to represent:
- current system generation
- previous system generation
- rollback target
- GC roots associated with installed systems
This does not have to copy Guix System mechanically, but it should preserve the same important properties.
**Success Criteria:** Fruix has a clearer model for installed system generations and rollback roots rather than relying mainly on test-harness knowledge.
### Intermediate Goal 19.3: Validate Installed-System Rollback as an Operator Workflow
**Verification Goal 19.3:** Validate rollback through the intended installed-system workflow, not only through build/image test harnesses.
This step should prove that the installation and generation model work together coherently.
**Success Criteria:** an installed Fruix system can move between generations using the intended operator-facing deployment model.
---
## Phase 20: Controlled Steps Toward Self-Hosted Base Builds
Only after source identity and installation/deployment boundaries are stronger should Fruix seriously revisit self-hosted base builds.
### Intermediate Goal 20.1: Validate a Fruix-Managed Development Environment for Native Base Work
**Verification Goal 20.1:** Ensure that a Fruix-managed system can expose the development/runtime/toolchain environment needed for deeper FreeBSD-native build work.
This should build on the cleaner runtime/development split already established in Phase 14.
The goal is not yet full self-hosting; it is to prove that the system can host the tools and profiles needed for that work in a controlled way.
**Success Criteria:** a Fruix-managed system can expose a usable development environment for native FreeBSD build tasks.
### Intermediate Goal 20.2: Run Host-Initiated Native Base Builds Inside a Fruix-Managed Environment
**Verification Goal 20.2:** As an intermediate step, perform native base builds inside a Fruix-managed environment or jail while still using the host as the outer orchestrator.
This narrows the remaining gap without immediately demanding full guest self-hosting.
**Success Criteria:** Fruix can build native FreeBSD base artifacts from inside a Fruix-managed build environment, with the host still orchestrating the outer loop.
### Intermediate Goal 20.3: Reassess and Potentially Prototype Guest Self-Hosted Base Builds
**Verification Goal 20.3:** Revisit guest self-hosting only after the earlier source/install/deployment goals are complete enough to make that experiment meaningful.
At that point, the question should be answered with real evidence:
- what exactly self-hosting would improve
- what it would cost in complexity
- how it would fit with the source/deployment model already established
**Success Criteria:** the project either:
- validates a first controlled guest self-hosted base build, or
- records a clear evidence-based decision to continue preferring host-orchestrated native builds.
---
## Strategic Notes
### Why this order?
This sequence is intended to preserve the most important win from Plan 3 and Phase 15:
- Fruix already has a native, store-based, rollback-friendly FreeBSD base path
The next improvement should therefore be to make the **source input** as explicit as the **deployment output** already is.
After that, Fruix can turn its successful image-generation path into a real installation story. Only then will self-hosting be judged in the right context.
### Why not jump straight to self-hosting?
Because at the end of Phase 15, the biggest remaining weakness is not “where the build runs”, but “how explicitly the source is declared and acquired”.
If self-hosting were attempted immediately, it would mix together:
- source acquisition problems
- toolchain/profile maturity problems
- build-environment questions
- deployment/installation questions
- and virtualization/operator constraints
That would make debugging and design less clear.
### Why add installation work before self-hosting?
Because Fruix should become more usable as a system even if self-hosting remains a later milestone.
A real installation story would:
- make the current system model more operator-meaningful
- improve validation of generation/deployment semantics
- prepare the project for broader VM and eventually hardware use
- make later self-hosting experiments easier to stage and reproduce
### What success will mean
Success under this plan means the project moves from:
- “Fruix builds native FreeBSD base artifacts from the hosts current `/usr/src` and boots them successfully”
into:
- “Fruix acquires FreeBSD sources declaratively, builds native base artifacts from pinned source inputs, installs systems through a real Fruix workflow, and approaches self-hosting from a much cleaner architectural position.”

View File

@@ -1,5 +1,83 @@
# Progress # Progress
## 2026-04-03 — Phase 16.1 completed: FreeBSD source inputs are now explicit Fruix objects
Completed work:
- added `docs/PLAN_4.md` to define the post-Phase-15 roadmap around:
- declarative FreeBSD source acquisition
- installation artifacts
- the controlled path toward self-hosting
- introduced a first-class `freebsd-source` record in `modules/fruix/packages/freebsd.scm` with:
- supported kinds:
- `local-tree`
- `git`
- `src-txz`
- exported accessors for:
- `name`
- `kind`
- `url`
- `path`
- `ref`
- `commit`
- `sha256`
- new `%default-freebsd-source`
- extended `freebsd-base` so it now records both:
- transitional `source-root`
- declarative `source`
- added/exported:
- `freebsd-base-source`
- threaded declared source fields into native package plans so native build outputs can record them
- in `modules/fruix/system/freebsd.scm`:
- added source validation for:
- `local-tree`
- `git`
- `src-txz`
- added `freebsd-source-spec`
- `freebsd-base-spec` now nests the declared source
- native manifests and `.freebsd-native-build-info.scm` now include:
- `declared-source`
- closures now generate:
- `metadata/freebsd-source.scm`
- `metadata/store-layout.scm` now records:
- `freebsd-source`
- in `scripts/fruix.scm`, `build` and `image` metadata now emit:
- `freebsd_source_name`
- `freebsd_source_kind`
- `freebsd_source_url`
- `freebsd_source_path`
- `freebsd_source_ref`
- `freebsd_source_commit`
- `freebsd_source_sha256`
- `freebsd_source_file`
- added validation artifacts:
- `tests/system/phase16-declarative-source-operating-system.scm.in`
- `tests/system/run-phase16-declarative-source-build.sh`
- `tests/system/validate-phase16-freebsd-source.scm`
- compared Fruix's new source model with Guix's source modeling via:
- `~/repos/guix/guix/packages.scm`
- `~/repos/guix/guix/git-download.scm`
- wrote:
- `docs/reports/phase16-declarative-source-model-freebsd.md`
Validation:
- `PASS phase16-declarative-source-build`
- source model probe confirmed support for:
- local-tree `/usr/src`
- Git refs such as `stable/15` at `https://git.FreeBSD.org/src.git`
- canonical `src.txz` URLs such as:
- `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz`
- `https://download.freebsd.org/snapshots/amd64/15.0-STABLE/src.txz`
- closure/native metadata now records the declared source explicitly while preserving the current validated `/usr/src` build path
Current assessment:
- Phase 16.1 is complete
- Fruix can now describe FreeBSD source inputs explicitly, but it does not fetch/materialize them yet
- the next step is Phase 16.2:
- fetch or materialize declared FreeBSD source inputs under Fruix control and use their stable identity as the next reproducibility boundary
## 2026-04-01 — Phase 1.1 started: Guile verified on FreeBSD amd64 ## 2026-04-01 — Phase 1.1 started: Guile verified on FreeBSD amd64
Completed work: Completed work:

View File

@@ -0,0 +1,202 @@
# Phase 16.1: model FreeBSD source inputs explicitly
Date: 2026-04-03
## Goal
Phase 16.1 introduces a first-class Fruix model for FreeBSD source inputs so the native base path is no longer described only as "whatever `/usr/src` is on the host".
This step does **not** yet fetch or materialize remote source trees. It makes the source declaration explicit and records it through the package, system, and CLI metadata layers so later phases can replace ambient `/usr/src` with fetched or materialized inputs cleanly.
## Implementation
### New declarative FreeBSD source record
Added in `modules/fruix/packages/freebsd.scm`:
- `freebsd-source`
- `freebsd-source?`
- accessors for:
- `name`
- `kind`
- `url`
- `path`
- `ref`
- `commit`
- `sha256`
- `%default-freebsd-source`
Supported source kinds are now modeled explicitly as:
- `local-tree`
- `git`
- `src-txz`
The default source remains a local-tree declaration for:
- `/usr/src`
### FreeBSD bases now carry a declared source object
Extended `freebsd-base` so it now records:
- the transitional `source-root` still used by the current native build path
- a new `source` record describing the declared FreeBSD source input
Added/exported:
- `freebsd-base-source`
This keeps the validated `/usr/src` path working while giving the base a source object that can later point at fetched Git or `src.txz` materializations.
### Native package plans and metadata now record the declared source
`modules/fruix/packages/freebsd.scm` now threads source fields into native package install plans.
`modules/fruix/system/freebsd.scm` now records a `declared-source` block in:
- native package manifests
- `.freebsd-native-build-info.scm`
This means native kernel, bootloader, and runtime outputs now remember both:
- the declared base
- the declared source input
### Operating-system validation now checks source declarations
Added source validation in `modules/fruix/system/freebsd.scm`.
Current accepted source declarations are:
- `local-tree`
- requires a path
- `git`
- requires a URL and at least a ref or commit
- `src-txz`
- requires a URL
This is intentionally enough for Phase 16.1 modeling without yet enforcing the later fetch/materialization policy.
### Closure metadata now includes a dedicated source file
System closures now generate:
- `metadata/freebsd-source.scm`
and embed source information in:
- `metadata/freebsd-base.scm`
- `metadata/store-layout.scm`
- `parameters.scm`
### CLI metadata now exposes the declared FreeBSD source
`scripts/fruix.scm` now emits the following for `fruix system build` and `image`:
- `freebsd_source_name`
- `freebsd_source_kind`
- `freebsd_source_url`
- `freebsd_source_path`
- `freebsd_source_ref`
- `freebsd_source_commit`
- `freebsd_source_sha256`
- `freebsd_source_file`
## Guix comparison
This follows the same broad idea as Guix source modeling:
- Guix uses `origin` in `guix/packages.scm`
- Git-backed sources are modeled with `git-reference` in `guix/git-download.scm`
Phase 16.1 does not copy Guix mechanically, but it adopts the same useful architectural boundary:
- source identity should be a declarative object
- builds should record that source object explicitly
For Fruix, the source kinds are FreeBSD-oriented:
- local source tree snapshots for development
- FreeBSD Git refs/commits
- official FreeBSD `src.txz` archives
## Upstream source forms verified during this step
Verified usable upstream source forms include:
- Git:
- `https://git.FreeBSD.org/src.git`
- release archive:
- `https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz`
- snapshot archive:
- `https://download.freebsd.org/snapshots/amd64/15.0-STABLE/src.txz`
The shorter release URL form above is treated as the canonical example in this phase.
## New files
Added:
- `docs/PLAN_4.md`
- `tests/system/phase16-declarative-source-operating-system.scm.in`
- `tests/system/run-phase16-declarative-source-build.sh`
- `tests/system/validate-phase16-freebsd-source.scm`
## Validation
Passing run:
- `PASS phase16-declarative-source-build`
- workdir:
- `/tmp/fruix-phase16-declarative-source.0LRvaC`
The source model probe confirmed:
```text
local_kind=local-tree
local_path=/usr/src
git_kind=git
git_url=https://git.FreeBSD.org/src.git
git_ref=stable/15
txz_kind=src-txz
txz_url=https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz
txz_sha256=example-sha256
base_source_accessor=ok
```
The closure build confirmed:
```text
closure_path=/frx/store/ac73a2a89c3c3f794462ccde0d9f0952362dc2ae32e631a7e99e07e7363e6118-fruix-system-fruix-freebsd
kernel_store=/frx/store/c2f771a794f94cf168ae26a421ffab33e0ae4765f23882257d5bb7b2947d493d-freebsd-native-kernel-15.0-STABLE-source-model
bootloader_store=/frx/store/a146c9c2fcacdc02454fe3bfd3afb5c5dbea54b6514242d53df0783ef4ee34fd-freebsd-native-bootloader-15.0-STABLE-source-model
runtime_store=/frx/store/530e96440a518821a701db03f9437d7646c0447f8ea55c5df08417e9274dead1-freebsd-native-runtime-15.0-STABLE-source-model
native_base_store_count=3
host_base_store_count=0
freebsd_source_name=host-usr-src
freebsd_source_kind=local-tree
freebsd_source_path=/usr/src
freebsd_source_file=/frx/store/ac73a2a89c3c3f794462ccde0d9f0952362dc2ae32e631a7e99e07e7363e6118-fruix-system-fruix-freebsd/metadata/freebsd-source.scm
declarative_source_model=ok
```
The harness also verified that:
- `metadata/freebsd-source.scm` exists
- `metadata/freebsd-base.scm` contains a nested source block
- `metadata/store-layout.scm` records the declared source explicitly
- native build info files contain a `declared-source` block with:
- `kind . local-tree`
- `path . "/usr/src"`
## Result
Phase 16.1 is complete.
Fruix now has an explicit source declaration layer for FreeBSD bases while preserving the current validated `/usr/src`-driven native build path.
That means Phase 16.2 can focus narrowly on the next real boundary:
- fetching or materializing declared FreeBSD source inputs under Fruix control
- instead of just describing them

View File

@@ -3,6 +3,16 @@
#:use-module (srfi srfi-9) #:use-module (srfi srfi-9)
#:use-module (srfi srfi-13) #:use-module (srfi srfi-13)
#:export (freebsd-release #:export (freebsd-release
freebsd-source
freebsd-source?
freebsd-source-name
freebsd-source-kind
freebsd-source-url
freebsd-source-path
freebsd-source-ref
freebsd-source-commit
freebsd-source-sha256
%default-freebsd-source
freebsd-base freebsd-base
freebsd-base? freebsd-base?
freebsd-base-name freebsd-base-name
@@ -10,6 +20,7 @@
freebsd-base-release freebsd-base-release
freebsd-base-branch freebsd-base-branch
freebsd-base-source-root freebsd-base-source-root
freebsd-base-source
freebsd-base-target freebsd-base-target
freebsd-base-target-arch freebsd-base-target-arch
freebsd-base-kernconf freebsd-base-kernconf
@@ -87,8 +98,32 @@
(define freebsd-release "15.0-STABLE") (define freebsd-release "15.0-STABLE")
(define-record-type <freebsd-source>
(make-freebsd-source name kind url path ref commit sha256)
freebsd-source?
(name freebsd-source-name)
(kind freebsd-source-kind)
(url freebsd-source-url)
(path freebsd-source-path)
(ref freebsd-source-ref)
(commit freebsd-source-commit)
(sha256 freebsd-source-sha256))
(define* (freebsd-source #:key
(name "default")
(kind 'local-tree)
(url (and (eq? kind 'git) "https://git.FreeBSD.org/src.git"))
(path (and (eq? kind 'local-tree) "/usr/src"))
(ref #f)
(commit #f)
(sha256 #f))
(make-freebsd-source name kind url path ref commit sha256))
(define %default-freebsd-source
(freebsd-source))
(define-record-type <freebsd-base> (define-record-type <freebsd-base>
(make-freebsd-base name version-label release branch source-root target (make-freebsd-base name version-label release branch source-root source target
target-arch kernconf make-flags) target-arch kernconf make-flags)
freebsd-base? freebsd-base?
(name freebsd-base-name) (name freebsd-base-name)
@@ -96,6 +131,7 @@
(release freebsd-base-release) (release freebsd-base-release)
(branch freebsd-base-branch) (branch freebsd-base-branch)
(source-root freebsd-base-source-root) (source-root freebsd-base-source-root)
(source freebsd-base-source)
(target freebsd-base-target) (target freebsd-base-target)
(target-arch freebsd-base-target-arch) (target-arch freebsd-base-target-arch)
(kernconf freebsd-base-kernconf) (kernconf freebsd-base-kernconf)
@@ -123,13 +159,18 @@
(version-label freebsd-release) (version-label freebsd-release)
(release freebsd-release) (release freebsd-release)
(branch (default-freebsd-branch release)) (branch (default-freebsd-branch release))
(source-root "/usr/src") (source #f)
(source-root #f)
(target "amd64") (target "amd64")
(target-arch "amd64") (target-arch "amd64")
(kernconf "GENERIC") (kernconf "GENERIC")
(make-flags default-native-make-flags)) (make-flags default-native-make-flags))
(make-freebsd-base name version-label release branch source-root target (let* ((source (or source %default-freebsd-source))
target-arch kernconf make-flags)) (source-root (or source-root
(freebsd-source-path source)
"/usr/src")))
(make-freebsd-base name version-label release branch source-root source target
target-arch kernconf make-flags)))
(define %default-freebsd-base (define %default-freebsd-base
(freebsd-base)) (freebsd-base))
@@ -574,6 +615,13 @@ library for profile experiments."
(base-version-label . ,(freebsd-base-version-label base)) (base-version-label . ,(freebsd-base-version-label base))
(base-release . ,(freebsd-base-release base)) (base-release . ,(freebsd-base-release base))
(base-branch . ,(freebsd-base-branch base)) (base-branch . ,(freebsd-base-branch base))
(base-source-name . ,(freebsd-source-name (freebsd-base-source base)))
(base-source-kind . ,(freebsd-source-kind (freebsd-base-source base)))
(base-source-url . ,(freebsd-source-url (freebsd-base-source base)))
(base-source-path . ,(freebsd-source-path (freebsd-base-source base)))
(base-source-ref . ,(freebsd-source-ref (freebsd-base-source base)))
(base-source-commit . ,(freebsd-source-commit (freebsd-base-source base)))
(base-source-sha256 . ,(freebsd-source-sha256 (freebsd-base-source base)))
(source-root . ,(freebsd-base-source-root base)) (source-root . ,(freebsd-base-source-root base))
(target . ,(freebsd-base-target base)) (target . ,(freebsd-base-target base))
(target-arch . ,(freebsd-base-target-arch base)) (target-arch . ,(freebsd-base-target-arch base))

View File

@@ -313,10 +313,20 @@
(release . ,(build-plan-ref plan 'base-release freebsd-release)) (release . ,(build-plan-ref plan 'base-release freebsd-release))
(branch . ,(build-plan-ref plan 'base-branch "unknown")))) (branch . ,(build-plan-ref plan 'base-branch "unknown"))))
(define (native-build-declared-source plan)
`((name . ,(build-plan-ref plan 'base-source-name "default"))
(kind . ,(build-plan-ref plan 'base-source-kind 'local-tree))
(url . ,(build-plan-ref plan 'base-source-url #f))
(path . ,(build-plan-ref plan 'base-source-path #f))
(ref . ,(build-plan-ref plan 'base-source-ref #f))
(commit . ,(build-plan-ref plan 'base-source-commit #f))
(sha256 . ,(build-plan-ref plan 'base-source-sha256 #f))))
(define (native-build-manifest-string package input-paths) (define (native-build-manifest-string package input-paths)
(let* ((plan (freebsd-package-install-plan package)) (let* ((plan (freebsd-package-install-plan package))
(common (native-build-common-manifest plan)) (common (native-build-common-manifest plan))
(declared-base (native-build-declared-base plan)) (declared-base (native-build-declared-base plan))
(declared-source (native-build-declared-source plan))
(keep-paths (build-plan-ref plan 'keep-paths '())) (keep-paths (build-plan-ref plan 'keep-paths '()))
(prune-paths (build-plan-ref plan 'prune-paths '()))) (prune-paths (build-plan-ref plan 'prune-paths '())))
(string-append (string-append
@@ -326,6 +336,8 @@
"inputs=" (string-join input-paths ",") "\n" "inputs=" (string-join input-paths ",") "\n"
"declared-base=\n" "declared-base=\n"
(object->string declared-base) (object->string declared-base)
"\ndeclared-source=\n"
(object->string declared-source)
"\nnative-build-common=\n" "\nnative-build-common=\n"
(object->string common) (object->string common)
"\nkeep-paths=\n" "\nkeep-paths=\n"
@@ -479,6 +491,7 @@
`((package . ,(freebsd-package-name package)) `((package . ,(freebsd-package-name package))
(version . ,(freebsd-package-version package)) (version . ,(freebsd-package-version package))
(declared-base . ,(native-build-declared-base plan)) (declared-base . ,(native-build-declared-base plan))
(declared-source . ,(native-build-declared-source plan))
(build-system . ,(freebsd-package-build-system package)) (build-system . ,(freebsd-package-build-system package))
(source-root . ,(assoc-ref common 'source-root)) (source-root . ,(assoc-ref common 'source-root))
(source-tree-sha256 . ,(assoc-ref common 'source-tree-sha256)) (source-tree-sha256 . ,(assoc-ref common 'source-tree-sha256))
@@ -682,12 +695,22 @@
(define (package-names packages) (define (package-names packages)
(map freebsd-package-name packages)) (map freebsd-package-name packages))
(define (freebsd-source-spec source)
`((name . ,(freebsd-source-name source))
(kind . ,(freebsd-source-kind source))
(url . ,(freebsd-source-url source))
(path . ,(freebsd-source-path source))
(ref . ,(freebsd-source-ref source))
(commit . ,(freebsd-source-commit source))
(sha256 . ,(freebsd-source-sha256 source))))
(define (freebsd-base-spec base) (define (freebsd-base-spec base)
`((name . ,(freebsd-base-name base)) `((name . ,(freebsd-base-name base))
(version-label . ,(freebsd-base-version-label base)) (version-label . ,(freebsd-base-version-label base))
(release . ,(freebsd-base-release base)) (release . ,(freebsd-base-release base))
(branch . ,(freebsd-base-branch base)) (branch . ,(freebsd-base-branch base))
(source-root . ,(freebsd-base-source-root base)) (source-root . ,(freebsd-base-source-root base))
(source . ,(freebsd-source-spec (freebsd-base-source base)))
(target . ,(freebsd-base-target base)) (target . ,(freebsd-base-target base))
(target-arch . ,(freebsd-base-target-arch base)) (target-arch . ,(freebsd-base-target-arch base))
(kernconf . ,(freebsd-base-kernconf base)) (kernconf . ,(freebsd-base-kernconf base))
@@ -702,6 +725,31 @@
(loop tail seen (if (member head duplicates) duplicates (cons head duplicates))) (loop tail seen (if (member head duplicates) duplicates (cons head duplicates)))
(loop tail (cons head seen) duplicates)))))) (loop tail (cons head seen) duplicates))))))
(define (non-empty-string? value)
(and (string? value)
(not (string-null? value))))
(define (validate-freebsd-source source)
(unless (freebsd-source? source)
(error "freebsd base source must be a <freebsd-source> record"))
(let ((kind (freebsd-source-kind source)))
(unless (member kind '(local-tree git src-txz))
(error "unsupported freebsd source kind" kind))
(case kind
((local-tree)
(unless (non-empty-string? (freebsd-source-path source))
(error "local-tree freebsd source must declare a path" source)))
((git)
(unless (non-empty-string? (freebsd-source-url source))
(error "git freebsd source must declare a URL" source))
(unless (or (non-empty-string? (freebsd-source-ref source))
(non-empty-string? (freebsd-source-commit source)))
(error "git freebsd source must declare a ref or commit" source)))
((src-txz)
(unless (non-empty-string? (freebsd-source-url source))
(error "src-txz freebsd source must declare a URL" source)))))
#t)
(define (validate-operating-system os) (define (validate-operating-system os)
(let* ((host-name (operating-system-host-name os)) (let* ((host-name (operating-system-host-name os))
(base (operating-system-freebsd-base os)) (base (operating-system-freebsd-base os))
@@ -716,6 +764,7 @@
(error "operating-system host-name must not be empty")) (error "operating-system host-name must not be empty"))
(unless (freebsd-base? base) (unless (freebsd-base? base)
(error "operating-system freebsd-base must be a <freebsd-base> record")) (error "operating-system freebsd-base must be a <freebsd-base> record"))
(validate-freebsd-source (freebsd-base-source base))
(let ((dups (duplicate-elements user-names))) (let ((dups (duplicate-elements user-names)))
(unless (null? dups) (unless (null? dups)
(error "duplicate user names in operating-system" dups))) (error "duplicate user names in operating-system" dups)))
@@ -1386,11 +1435,14 @@
(metadata-files (metadata-files
`(("metadata/freebsd-base.scm" `(("metadata/freebsd-base.scm"
. ,(object->string (freebsd-base-spec (operating-system-freebsd-base os)))) . ,(object->string (freebsd-base-spec (operating-system-freebsd-base os))))
("metadata/freebsd-source.scm"
. ,(object->string (freebsd-source-spec (freebsd-base-source (operating-system-freebsd-base os)))))
("metadata/host-base-provenance.scm" ("metadata/host-base-provenance.scm"
. ,(object->string (host-freebsd-provenance))) . ,(object->string (host-freebsd-provenance)))
("metadata/store-layout.scm" ("metadata/store-layout.scm"
. ,(object->string . ,(object->string
`((freebsd-base . ,(freebsd-base-spec (operating-system-freebsd-base os))) `((freebsd-base . ,(freebsd-base-spec (operating-system-freebsd-base os)))
(freebsd-source . ,(freebsd-source-spec (freebsd-base-source (operating-system-freebsd-base os))))
(host-base-store-count . ,(length host-base-stores)) (host-base-store-count . ,(length host-base-stores))
(host-base-stores . ,host-base-stores) (host-base-stores . ,host-base-stores)
(native-base-store-count . ,(length native-base-stores)) (native-base-store-count . ,(length native-base-stores))
@@ -1466,6 +1518,7 @@
(native-base-stores . ,native-base-stores) (native-base-stores . ,native-base-stores)
(fruix-runtime-stores . ,fruix-runtime-stores) (fruix-runtime-stores . ,fruix-runtime-stores)
(freebsd-base-file . ,(string-append closure-path "/metadata/freebsd-base.scm")) (freebsd-base-file . ,(string-append closure-path "/metadata/freebsd-base.scm"))
(freebsd-source-file . ,(string-append closure-path "/metadata/freebsd-source.scm"))
(host-base-provenance-file . ,(string-append closure-path "/metadata/host-base-provenance.scm")) (host-base-provenance-file . ,(string-append closure-path "/metadata/host-base-provenance.scm"))
(store-layout-file . ,(string-append closure-path "/metadata/store-layout.scm")) (store-layout-file . ,(string-append closure-path "/metadata/store-layout.scm"))
(generated-files . ,(map car generated-files)) (generated-files . ,(map car generated-files))

View File

@@ -176,6 +176,7 @@ Options:\n\
(native-base-stores (assoc-ref result 'native-base-stores)) (native-base-stores (assoc-ref result 'native-base-stores))
(fruix-runtime-stores (assoc-ref result 'fruix-runtime-stores)) (fruix-runtime-stores (assoc-ref result 'fruix-runtime-stores))
(base (operating-system-freebsd-base os)) (base (operating-system-freebsd-base os))
(source (freebsd-base-source base))
(host-provenance (call-with-input-file (assoc-ref result 'host-base-provenance-file) read))) (host-provenance (call-with-input-file (assoc-ref result 'host-base-provenance-file) read)))
(emit-metadata (emit-metadata
`((action . "build") `((action . "build")
@@ -192,6 +193,14 @@ Options:\n\
(freebsd_base_target_arch . ,(freebsd-base-target-arch base)) (freebsd_base_target_arch . ,(freebsd-base-target-arch base))
(freebsd_base_kernconf . ,(freebsd-base-kernconf base)) (freebsd_base_kernconf . ,(freebsd-base-kernconf base))
(freebsd_base_file . ,(assoc-ref result 'freebsd-base-file)) (freebsd_base_file . ,(assoc-ref result 'freebsd-base-file))
(freebsd_source_name . ,(freebsd-source-name source))
(freebsd_source_kind . ,(freebsd-source-kind source))
(freebsd_source_url . ,(or (freebsd-source-url source) ""))
(freebsd_source_path . ,(or (freebsd-source-path source) ""))
(freebsd_source_ref . ,(or (freebsd-source-ref source) ""))
(freebsd_source_commit . ,(or (freebsd-source-commit source) ""))
(freebsd_source_sha256 . ,(or (freebsd-source-sha256 source) ""))
(freebsd_source_file . ,(assoc-ref result 'freebsd-source-file))
(ready_marker . ,(operating-system-ready-marker os)) (ready_marker . ,(operating-system-ready-marker os))
(kernel_store . ,(assoc-ref result 'kernel-store)) (kernel_store . ,(assoc-ref result 'kernel-store))
(bootloader_store . ,(assoc-ref result 'bootloader-store)) (bootloader_store . ,(assoc-ref result 'bootloader-store))
@@ -246,6 +255,7 @@ Options:\n\
(native-base-stores (assoc-ref result 'native-base-stores)) (native-base-stores (assoc-ref result 'native-base-stores))
(fruix-runtime-stores (assoc-ref result 'fruix-runtime-stores)) (fruix-runtime-stores (assoc-ref result 'fruix-runtime-stores))
(base (operating-system-freebsd-base os)) (base (operating-system-freebsd-base os))
(source (freebsd-base-source base))
(host-provenance (call-with-input-file (assoc-ref result 'host-base-provenance-file) read))) (host-provenance (call-with-input-file (assoc-ref result 'host-base-provenance-file) read)))
(emit-metadata (emit-metadata
`((action . "image") `((action . "image")
@@ -261,6 +271,14 @@ Options:\n\
(freebsd_base_target_arch . ,(freebsd-base-target-arch base)) (freebsd_base_target_arch . ,(freebsd-base-target-arch base))
(freebsd_base_kernconf . ,(freebsd-base-kernconf base)) (freebsd_base_kernconf . ,(freebsd-base-kernconf base))
(freebsd_base_file . ,(assoc-ref result 'freebsd-base-file)) (freebsd_base_file . ,(assoc-ref result 'freebsd-base-file))
(freebsd_source_name . ,(freebsd-source-name source))
(freebsd_source_kind . ,(freebsd-source-kind source))
(freebsd_source_url . ,(or (freebsd-source-url source) ""))
(freebsd_source_path . ,(or (freebsd-source-path source) ""))
(freebsd_source_ref . ,(or (freebsd-source-ref source) ""))
(freebsd_source_commit . ,(or (freebsd-source-commit source) ""))
(freebsd_source_sha256 . ,(or (freebsd-source-sha256 source) ""))
(freebsd_source_file . ,(assoc-ref result 'freebsd-source-file))
(disk_capacity . ,(assoc-ref image-spec 'disk-capacity)) (disk_capacity . ,(assoc-ref image-spec 'disk-capacity))
(root_size . ,(assoc-ref image-spec 'root-size)) (root_size . ,(assoc-ref image-spec 'root-size))
(image_store_path . ,(assoc-ref result 'image-store-path)) (image_store_path . ,(assoc-ref result 'image-store-path))

View File

@@ -0,0 +1,90 @@
(use-modules (fruix system freebsd)
(fruix packages freebsd))
(define phase16-source
(freebsd-source
#:name "__SOURCE_NAME__"
#:kind 'local-tree
#:path "/usr/src"))
(define phase16-base
(freebsd-base
#:name "__BASE_NAME__"
#:version-label "__BASE_VERSION_LABEL__"
#:release "__BASE_RELEASE__"
#:branch "__BASE_BRANCH__"
#:source phase16-source
#:source-root "/usr/src"
#:target "amd64"
#:target-arch "amd64"
#:kernconf "GENERIC"))
(define phase16-operating-system
(operating-system
#:host-name "fruix-freebsd"
#:freebsd-base phase16-base
#:kernel (freebsd-native-kernel-for phase16-base)
#:bootloader (freebsd-native-bootloader-for phase16-base)
#:base-packages (freebsd-native-system-packages-for phase16-base)
#:groups (list (user-group #:name "wheel" #:gid 0 #:system? #t)
(user-group #:name "sshd" #:gid 22 #:system? #t)
(user-group #:name "_dhcp" #:gid 65 #:system? #t)
(user-group #:name "operator" #:gid 1000 #:system? #f))
#:users (list (user-account #:name "root"
#:uid 0
#:group "wheel"
#:comment "Charlie &"
#:home "/root"
#:shell "/bin/sh"
#:system? #t)
(user-account #:name "sshd"
#:uid 22
#:group "sshd"
#:comment "Secure Shell Daemon"
#:home "/var/empty"
#:shell "/usr/sbin/nologin"
#:system? #t)
(user-account #:name "_dhcp"
#:uid 65
#:group "_dhcp"
#:comment "dhcp programs"
#:home "/var/empty"
#:shell "/usr/sbin/nologin"
#:system? #t)
(user-account #:name "operator"
#:uid 1000
#:group "operator"
#:supplementary-groups '("wheel")
#:comment "Fruix Operator"
#:home "/home/operator"
#:shell "/bin/sh"
#:system? #f))
#:file-systems (list (file-system #:device "/dev/gpt/fruix-root"
#:mount-point "/"
#:type "ufs"
#:options "rw"
#:needed-for-boot? #t)
(file-system #:device "devfs"
#:mount-point "/dev"
#:type "devfs"
#:options "rw"
#:needed-for-boot? #t)
(file-system #:device "tmpfs"
#:mount-point "/tmp"
#:type "tmpfs"
#:options "rw,size=64m"))
#:services '(shepherd ready-marker sshd)
#:loader-entries '(("autoboot_delay" . "1")
("boot_multicons" . "YES")
("boot_serial" . "YES")
("console" . "comconsole,vidconsole"))
#:rc-conf-entries '(("clear_tmp_enable" . "NO")
("hostid_enable" . "NO")
("sendmail_enable" . "NONE")
("sshd_enable" . "YES")
("ifconfig_xn0" . "SYNCDHCP")
("ifconfig_em0" . "SYNCDHCP")
("ifconfig_vtnet0" . "SYNCDHCP"))
#:init-mode 'shepherd-pid1
#:ready-marker "/var/lib/fruix/ready"
#:root-authorized-keys '("__ROOT_AUTHORIZED_KEY__")))

View File

@@ -0,0 +1,245 @@
#!/bin/sh
set -eu
project_root=${PROJECT_ROOT:-$(pwd)}
script_dir=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
fruix_cmd=$project_root/bin/fruix
os_template=${OS_TEMPLATE:-$script_dir/phase16-declarative-source-operating-system.scm.in}
source_probe=${SOURCE_PROBE:-$script_dir/validate-phase16-freebsd-source.scm}
system_name=${SYSTEM_NAME:-phase16-operating-system}
store_dir=${STORE_DIR:-/frx/store}
base_name=${BASE_NAME:-source-model}
base_version_label=${BASE_VERSION_LABEL:-15.0-STABLE-source-model}
base_release=${BASE_RELEASE:-15.0-STABLE}
base_branch=${BASE_BRANCH:-stable/15}
source_name=${SOURCE_NAME:-host-usr-src}
metadata_target=${METADATA_OUT:-}
root_authorized_key_file=${ROOT_AUTHORIZED_KEY_FILE:-$HOME/.ssh/id_ed25519.pub}
[ -x "$fruix_cmd" ] || {
echo "fruix command is not executable: $fruix_cmd" >&2
exit 1
}
[ -f "$os_template" ] || {
echo "missing operating-system template: $os_template" >&2
exit 1
}
[ -f "$source_probe" ] || {
echo "missing source probe script: $source_probe" >&2
exit 1
}
[ -f "$root_authorized_key_file" ] || {
echo "missing root authorized key file: $root_authorized_key_file" >&2
exit 1
}
cleanup=0
if [ -n "${WORKDIR:-}" ]; then
workdir=$WORKDIR
mkdir -p "$workdir"
else
workdir=$(mktemp -d /tmp/fruix-phase16-declarative-source.XXXXXX)
cleanup=1
fi
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
cleanup=0
fi
cleanup_workdir() {
if [ "$cleanup" -eq 1 ]; then
rm -rf "$workdir" 2>/dev/null || sudo rm -rf "$workdir"
fi
}
trap cleanup_workdir EXIT INT TERM
phase16_os_file=$workdir/phase16-declarative-source-operating-system.scm
source_probe_out=$workdir/source-probe.txt
build_out=$workdir/build.txt
metadata_file=$workdir/phase16-declarative-source-build-metadata.txt
root_authorized_key=$(tr -d '\n' < "$root_authorized_key_file")
sed \
-e "s|__BASE_NAME__|$base_name|g" \
-e "s|__BASE_VERSION_LABEL__|$base_version_label|g" \
-e "s|__BASE_RELEASE__|$base_release|g" \
-e "s|__BASE_BRANCH__|$base_branch|g" \
-e "s|__SOURCE_NAME__|$source_name|g" \
-e "s|__ROOT_AUTHORIZED_KEY__|$root_authorized_key|g" \
"$os_template" > "$phase16_os_file"
action_env() {
sudo env \
HOME="$HOME" \
GUILE_AUTO_COMPILE=0 \
FRUIX_FREEBSD_BUILD_JOBS="${FRUIX_FREEBSD_BUILD_JOBS:-8}" \
GUIX_SOURCE_DIR="${GUIX_SOURCE_DIR:-$HOME/repos/guix}" \
GUILE_BIN="${GUILE_BIN:-/tmp/guile-freebsd-validate-install/bin/guile}" \
GUILE_EXTRA_PREFIX="${GUILE_EXTRA_PREFIX:-/tmp/guile-gnutls-freebsd-validate-install}" \
SHEPHERD_PREFIX="${SHEPHERD_PREFIX:-/tmp/shepherd-freebsd-validate-install}" \
"$@"
}
action_env "${GUILE_BIN:-/tmp/guile-freebsd-validate-install/bin/guile}" \
-L "$project_root/modules" \
-c "(primitive-load \"$source_probe\")" >"$source_probe_out"
for expected in \
'local_kind=local-tree' \
'local_path=/usr/src' \
'git_kind=git' \
'git_url=https://git.FreeBSD.org/src.git' \
'git_ref=stable/15' \
'txz_kind=src-txz' \
'txz_url=https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz' \
'txz_sha256=example-sha256' \
'base_source_accessor=ok'
do
grep -F "$expected" "$source_probe_out" >/dev/null || {
echo "source probe missing expected line: $expected" >&2
exit 1
}
done
action_env "$fruix_cmd" system build "$phase16_os_file" --system "$system_name" --store "$store_dir" >"$build_out"
closure_path=$(sed -n 's/^closure_path=//p' "$build_out")
kernel_store=$(sed -n 's/^kernel_store=//p' "$build_out")
bootloader_store=$(sed -n 's/^bootloader_store=//p' "$build_out")
native_base_store_count=$(sed -n 's/^native_base_store_count=//p' "$build_out")
native_base_stores=$(sed -n 's/^native_base_stores=//p' "$build_out")
host_base_store_count=$(sed -n 's/^host_base_store_count=//p' "$build_out")
freebsd_base_name_out=$(sed -n 's/^freebsd_base_name=//p' "$build_out")
freebsd_base_version_label_out=$(sed -n 's/^freebsd_base_version_label=//p' "$build_out")
freebsd_base_release_out=$(sed -n 's/^freebsd_base_release=//p' "$build_out")
freebsd_base_branch_out=$(sed -n 's/^freebsd_base_branch=//p' "$build_out")
freebsd_base_source_root_out=$(sed -n 's/^freebsd_base_source_root=//p' "$build_out")
freebsd_base_file=$(sed -n 's/^freebsd_base_file=//p' "$build_out")
freebsd_source_name_out=$(sed -n 's/^freebsd_source_name=//p' "$build_out")
freebsd_source_kind_out=$(sed -n 's/^freebsd_source_kind=//p' "$build_out")
freebsd_source_url_out=$(sed -n 's/^freebsd_source_url=//p' "$build_out")
freebsd_source_path_out=$(sed -n 's/^freebsd_source_path=//p' "$build_out")
freebsd_source_ref_out=$(sed -n 's/^freebsd_source_ref=//p' "$build_out")
freebsd_source_commit_out=$(sed -n 's/^freebsd_source_commit=//p' "$build_out")
freebsd_source_sha256_out=$(sed -n 's/^freebsd_source_sha256=//p' "$build_out")
freebsd_source_file=$(sed -n 's/^freebsd_source_file=//p' "$build_out")
store_layout_file=$(sed -n 's/^store_layout_file=//p' "$build_out")
[ -n "$closure_path" ] || { echo "missing closure path" >&2; exit 1; }
[ "$host_base_store_count" = 0 ] || { echo "expected zero host base stores, got: $host_base_store_count" >&2; exit 1; }
[ "$native_base_store_count" = 3 ] || { echo "expected three native base stores, got: $native_base_store_count" >&2; exit 1; }
[ "$freebsd_base_name_out" = "$base_name" ] || { echo "unexpected freebsd base name: $freebsd_base_name_out" >&2; exit 1; }
[ "$freebsd_base_version_label_out" = "$base_version_label" ] || { echo "unexpected freebsd base version label: $freebsd_base_version_label_out" >&2; exit 1; }
[ "$freebsd_base_release_out" = "$base_release" ] || { echo "unexpected freebsd base release: $freebsd_base_release_out" >&2; exit 1; }
[ "$freebsd_base_branch_out" = "$base_branch" ] || { echo "unexpected freebsd base branch: $freebsd_base_branch_out" >&2; exit 1; }
[ "$freebsd_base_source_root_out" = /usr/src ] || { echo "unexpected freebsd base source root: $freebsd_base_source_root_out" >&2; exit 1; }
[ "$freebsd_source_name_out" = "$source_name" ] || { echo "unexpected freebsd source name: $freebsd_source_name_out" >&2; exit 1; }
[ "$freebsd_source_kind_out" = local-tree ] || { echo "unexpected freebsd source kind: $freebsd_source_kind_out" >&2; exit 1; }
[ "$freebsd_source_url_out" = "" ] || { echo "unexpected freebsd source URL: $freebsd_source_url_out" >&2; exit 1; }
[ "$freebsd_source_path_out" = /usr/src ] || { echo "unexpected freebsd source path: $freebsd_source_path_out" >&2; exit 1; }
[ "$freebsd_source_ref_out" = "" ] || { echo "unexpected freebsd source ref: $freebsd_source_ref_out" >&2; exit 1; }
[ "$freebsd_source_commit_out" = "" ] || { echo "unexpected freebsd source commit: $freebsd_source_commit_out" >&2; exit 1; }
[ "$freebsd_source_sha256_out" = "" ] || { echo "unexpected freebsd source sha256: $freebsd_source_sha256_out" >&2; exit 1; }
[ -f "$freebsd_base_file" ] || { echo "missing freebsd base file: $freebsd_base_file" >&2; exit 1; }
[ -f "$freebsd_source_file" ] || { echo "missing freebsd source file: $freebsd_source_file" >&2; exit 1; }
[ -f "$store_layout_file" ] || { echo "missing store layout file: $store_layout_file" >&2; exit 1; }
case "$kernel_store" in
/frx/store/*-freebsd-native-kernel-$base_version_label) : ;;
*) echo "unexpected kernel store path: $kernel_store" >&2; exit 1 ;;
esac
case "$bootloader_store" in
/frx/store/*-freebsd-native-bootloader-$base_version_label) : ;;
*) echo "unexpected bootloader store path: $bootloader_store" >&2; exit 1 ;;
esac
runtime_store=$(printf '%s\n' "$native_base_stores" | tr ',' '\n' | grep "freebsd-native-runtime-$base_version_label$" | head -n 1)
[ -n "$runtime_store" ] || { echo "failed to recover runtime store" >&2; exit 1; }
for path in "$kernel_store/.freebsd-native-build-info.scm" "$bootloader_store/.freebsd-native-build-info.scm" "$runtime_store/.freebsd-native-build-info.scm"; do
[ -f "$path" ] || {
echo "missing native build info file: $path" >&2
exit 1
}
grep -F "(declared-source" "$path" >/dev/null || {
echo "native build info missing declared source block in $path" >&2
exit 1
}
grep -F "(kind . local-tree)" "$path" >/dev/null || {
echo "native build info missing declared source kind in $path" >&2
exit 1
}
grep -F "(path . \"/usr/src\")" "$path" >/dev/null || {
echo "native build info missing declared source path in $path" >&2
exit 1
}
done
grep -F "(name . \"$source_name\")" "$freebsd_source_file" >/dev/null || {
echo "freebsd source file missing name" >&2
exit 1
}
grep -F "(kind . local-tree)" "$freebsd_source_file" >/dev/null || {
echo "freebsd source file missing kind" >&2
exit 1
}
grep -F "(path . \"/usr/src\")" "$freebsd_source_file" >/dev/null || {
echo "freebsd source file missing path" >&2
exit 1
}
grep -F "(source" "$freebsd_base_file" >/dev/null || {
echo "freebsd base file missing nested source block" >&2
exit 1
}
if ! grep -F "(source" "$closure_path/parameters.scm" >/dev/null; then
echo "closure parameters do not record the declared source" >&2
exit 1
fi
grep -F "(freebsd-source" "$store_layout_file" >/dev/null || {
echo "store layout file missing declared source block" >&2
exit 1
}
closure_base=$(basename "$closure_path")
cat >"$metadata_file" <<EOF
workdir=$workdir
phase16_os_file=$phase16_os_file
source_probe_out=$source_probe_out
closure_path=$closure_path
closure_base=$closure_base
kernel_store=$kernel_store
bootloader_store=$bootloader_store
runtime_store=$runtime_store
native_base_store_count=$native_base_store_count
native_base_stores=$native_base_stores
host_base_store_count=$host_base_store_count
freebsd_base_name=$freebsd_base_name_out
freebsd_base_version_label=$freebsd_base_version_label_out
freebsd_base_release=$freebsd_base_release_out
freebsd_base_branch=$freebsd_base_branch_out
freebsd_base_source_root=$freebsd_base_source_root_out
freebsd_base_file=$freebsd_base_file
freebsd_source_name=$freebsd_source_name_out
freebsd_source_kind=$freebsd_source_kind_out
freebsd_source_url=$freebsd_source_url_out
freebsd_source_path=$freebsd_source_path_out
freebsd_source_ref=$freebsd_source_ref_out
freebsd_source_commit=$freebsd_source_commit_out
freebsd_source_sha256=$freebsd_source_sha256_out
freebsd_source_file=$freebsd_source_file
store_layout_file=$store_layout_file
declarative_source_model=ok
EOF
if [ -n "$metadata_target" ]; then
mkdir -p "$(dirname "$metadata_target")"
cp "$metadata_file" "$metadata_target"
fi
printf 'PASS phase16-declarative-source-build\n'
printf 'Work directory: %s\n' "$workdir"
printf 'Metadata file: %s\n' "$metadata_file"
if [ -n "$metadata_target" ]; then
printf 'Copied metadata to: %s\n' "$metadata_target"
fi
printf '%s\n' '--- source probe ---'
cat "$source_probe_out"
printf '%s\n' '--- metadata ---'
cat "$metadata_file"

View File

@@ -0,0 +1,69 @@
(use-modules (fruix packages freebsd)
(ice-9 format))
(define (assert condition message . rest)
(unless condition
(apply error message rest)))
(define local-source
(freebsd-source
#:name "host-usr-src"
#:kind 'local-tree
#:path "/usr/src"))
(define git-source
(freebsd-source
#:name "stable15-git"
#:kind 'git
#:ref "stable/15"))
(define txz-source
(freebsd-source
#:name "release-15.0-txz"
#:kind 'src-txz
#:url "https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz"
#:sha256 "example-sha256"))
(define git-base
(freebsd-base
#:name "git-base"
#:source git-source
#:source-root "/usr/src"))
(define txz-base
(freebsd-base
#:name "txz-base"
#:source txz-source
#:source-root "/usr/src"))
(assert (eq? (freebsd-source-kind local-source) 'local-tree)
"unexpected local source kind")
(assert (string=? (freebsd-source-path local-source) "/usr/src")
"unexpected local source path")
(assert (eq? (freebsd-source-kind git-source) 'git)
"unexpected git source kind")
(assert (string=? (freebsd-source-url git-source) "https://git.FreeBSD.org/src.git")
"unexpected default git source URL")
(assert (string=? (freebsd-source-ref git-source) "stable/15")
"unexpected git source ref")
(assert (eq? (freebsd-source-kind txz-source) 'src-txz)
"unexpected txz source kind")
(assert (string=? (freebsd-source-url txz-source)
"https://download.freebsd.org/releases/amd64/15.0-RELEASE/src.txz")
"unexpected txz source URL")
(assert (string=? (freebsd-source-sha256 txz-source) "example-sha256")
"unexpected txz source sha256")
(assert (freebsd-source? (freebsd-base-source git-base))
"git base did not preserve source record")
(assert (freebsd-source? (freebsd-base-source txz-base))
"txz base did not preserve source record")
(format #t "local_kind=~a~%" (freebsd-source-kind local-source))
(format #t "local_path=~a~%" (freebsd-source-path local-source))
(format #t "git_kind=~a~%" (freebsd-source-kind git-source))
(format #t "git_url=~a~%" (freebsd-source-url git-source))
(format #t "git_ref=~a~%" (freebsd-source-ref git-source))
(format #t "txz_kind=~a~%" (freebsd-source-kind txz-source))
(format #t "txz_url=~a~%" (freebsd-source-url txz-source))
(format #t "txz_sha256=~a~%" (freebsd-source-sha256 txz-source))
(format #t "base_source_accessor=ok~%")