diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 605df58..7d85c6e 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -3447,3 +3447,94 @@ Next recommended step: 1. begin Phase 15 by making the FreeBSD base version a declarative Fruix input 2. demonstrate side-by-side native base versions in `/frx/store` 3. validate rebuild/redeploy/rollback across those base versions + +## 2026-04-03 — Phase 15.1: made the FreeBSD base a declarative Fruix input + +Completed work: + +- wrote the Phase 15.1 report: + - `docs/reports/phase15-declarative-base-freebsd.md` +- added a new declarative base record in `modules/fruix/packages/freebsd.scm`: + - `freebsd-base` + - `freebsd-base?` + - `%default-freebsd-base` +- the declarative base now records at least: + - `name` + - `version-label` + - `release` + - `branch` + - `source-root` + - `target` + - `target-arch` + - `kernconf` + - `make-flags` +- native FreeBSD package constructors are now parameterized by a declared base: + - `freebsd-native-kernel-for` + - `freebsd-native-world-for` + - `freebsd-native-runtime-for` + - `freebsd-native-bootloader-for` + - `freebsd-native-headers-for` + - `freebsd-native-system-packages-for` + - `freebsd-native-development-profile-packages-for` +- existing exported native package variables remain available as the `%default-freebsd-base` instances: + - `freebsd-native-kernel` + - `freebsd-native-world` + - `freebsd-native-runtime` + - `freebsd-native-bootloader` + - `freebsd-native-headers` +- added a new operating-system field in `modules/fruix/system/freebsd.scm`: + - `#:freebsd-base` + - exported accessor: `operating-system-freebsd-base` +- the declared base is now recorded in system/image metadata through: + - `operating-system-closure-spec` + - `operating-system-image-spec` + - `metadata/freebsd-base.scm` + - `metadata/store-layout.scm` +- native build manifests and `.freebsd-native-build-info.scm` now record: + - `declared-base` +- `scripts/fruix.scm` now emits declared base metadata for `build` and `image`: + - `freebsd_base_name` + - `freebsd_base_version_label` + - `freebsd_base_release` + - `freebsd_base_branch` + - `freebsd_base_source_root` + - `freebsd_base_target` + - `freebsd_base_target_arch` + - `freebsd_base_kernconf` + - `freebsd_base_file` + +New validation files: + +- `tests/system/phase15-declarative-base-pid1-operating-system.scm.in` +- `tests/system/run-phase15-declarative-base-build.sh` + +Validation: + +- declarative-base build harness passes: + - `tests/system/run-phase15-declarative-base-build.sh` + - workdir: `/tmp/phase15-1-build-1775202535` + - result: `PASS phase15-declarative-base-build` + - confirmed: + - `kernel_store=/frx/store/8fcef04c7e507e86ea5e92f251fe3c6ac1aa3bcf4809fa77ddd8b92854bfcde0-freebsd-native-kernel-15.0-STABLE-declarative` + - `bootloader_store=/frx/store/7a0ba431e487dc35a8f6318108da16a37c8426c43e77e7a7f91404ba1d980eef-freebsd-native-bootloader-15.0-STABLE-declarative` + - `runtime_store=/frx/store/17c24ad20ddcb136c39352b68e758deae0b480258ba0128a5546f696a7eba0a6-freebsd-native-runtime-15.0-STABLE-declarative` + - `native_base_store_count=3` + - `host_base_store_count=0` + - `freebsd_base_name=stable-default` + - `freebsd_base_version_label=15.0-STABLE-declarative` + - `freebsd_base_release=15.0-STABLE` + - `freebsd_base_branch=stable/15` + - `freebsd_base_source_root=/usr/src` + - `freebsd_base_kernconf=GENERIC` + - `declarative_base_input=ok` + - the harness also confirmed: + - `metadata/freebsd-base.scm` exists + - `parameters.scm` records the declared base + - `metadata/store-layout.scm` records the declared base + - native build info files record the declared base version/branch + +Current assessment: + +- Phase 15.1 is complete +- Fruix now models the FreeBSD base as an explicit declarative system input instead of leaving it implicit in the builder host alone +- the next step is to use that new declaration to prove side-by-side base versions and rollback-friendly rebuild/redeploy behavior diff --git a/docs/reports/phase15-declarative-base-freebsd.md b/docs/reports/phase15-declarative-base-freebsd.md new file mode 100644 index 0000000..32bc439 --- /dev/null +++ b/docs/reports/phase15-declarative-base-freebsd.md @@ -0,0 +1,141 @@ +# Phase 15.1: make the FreeBSD base version a declarative Fruix input + +Date: 2026-04-03 + +## Goal + +Phase 15.1 made the FreeBSD base an explicit declarative part of the Fruix system model instead of leaving it as an implicit property of whatever `/usr/src` happened to be present on the builder host. + +## Implementation + +### New declarative base record + +Added in `modules/fruix/packages/freebsd.scm`: + +- `freebsd-base` +- `freebsd-base?` +- accessors for: + - `name` + - `version-label` + - `release` + - `branch` + - `source-root` + - `target` + - `target-arch` + - `kernconf` + - `make-flags` +- `%default-freebsd-base` + +This gives Fruix an explicit model for the base input used by native FreeBSD artifacts. + +### Native package constructors now accept a declared base + +Added package constructors: + +- `freebsd-native-kernel-for` +- `freebsd-native-world-for` +- `freebsd-native-runtime-for` +- `freebsd-native-bootloader-for` +- `freebsd-native-headers-for` +- `freebsd-native-system-packages-for` +- `freebsd-native-development-profile-packages-for` + +The existing exported package variables remain as the `%default-freebsd-base` instances: + +- `freebsd-native-kernel` +- `freebsd-native-world` +- `freebsd-native-runtime` +- `freebsd-native-bootloader` +- `freebsd-native-headers` + +That preserves the validated Phase 14 path while making alternative declared bases possible. + +### Operating-system model now records the declared base + +Added to `modules/fruix/system/freebsd.scm`: + +- `operating-system-freebsd-base` +- new `#:freebsd-base` field on `operating-system` + +The declared base is now recorded in: + +- `operating-system-closure-spec` +- `operating-system-image-spec` +- `metadata/freebsd-base.scm` +- `metadata/store-layout.scm` + +### CLI metadata now exposes the declared base + +`scripts/fruix.scm` now emits, for `fruix system build` and `image`: + +- `freebsd_base_name` +- `freebsd_base_version_label` +- `freebsd_base_release` +- `freebsd_base_branch` +- `freebsd_base_source_root` +- `freebsd_base_target` +- `freebsd_base_target_arch` +- `freebsd_base_kernconf` +- `freebsd_base_file` + +### Native build metadata now records the declared base + +Native build manifests and `.freebsd-native-build-info.scm` now carry a `declared-base` block so the native artifacts themselves record the declarative base choice. + +## New files + +Added: + +- `tests/system/phase15-declarative-base-pid1-operating-system.scm.in` +- `tests/system/run-phase15-declarative-base-build.sh` + +## Validation + +Passing run: + +- `PASS phase15-declarative-base-build` +- workdir: `/tmp/phase15-1-build-1775202535` + +The harness used an explicit declared base: + +```scheme +(freebsd-base + #:name "stable-default" + #:version-label "15.0-STABLE-declarative" + #:release "15.0-STABLE" + #:branch "stable/15" + #:source-root "/usr/src" + #:target "amd64" + #:target-arch "amd64" + #:kernconf "GENERIC") +``` + +Confirmed: + +```text +kernel_store=/frx/store/8fcef04c7e507e86ea5e92f251fe3c6ac1aa3bcf4809fa77ddd8b92854bfcde0-freebsd-native-kernel-15.0-STABLE-declarative +bootloader_store=/frx/store/7a0ba431e487dc35a8f6318108da16a37c8426c43e77e7a7f91404ba1d980eef-freebsd-native-bootloader-15.0-STABLE-declarative +runtime_store=/frx/store/17c24ad20ddcb136c39352b68e758deae0b480258ba0128a5546f696a7eba0a6-freebsd-native-runtime-15.0-STABLE-declarative +native_base_store_count=3 +host_base_store_count=0 +freebsd_base_name=stable-default +freebsd_base_version_label=15.0-STABLE-declarative +freebsd_base_release=15.0-STABLE +freebsd_base_branch=stable/15 +freebsd_base_source_root=/usr/src +freebsd_base_kernconf=GENERIC +declarative_base_input=ok +``` + +The harness also confirmed: + +- `metadata/freebsd-base.scm` exists +- `parameters.scm` records the declared base +- `metadata/store-layout.scm` records the declared base +- native build info files record the declared base version/branch + +## Result + +Phase 15.1 is complete. + +Fruix now has an explicit declarative FreeBSD base input in the system model, while still allowing the current validated `/usr/src`-based path to work unchanged by default. diff --git a/modules/fruix/packages/freebsd.scm b/modules/fruix/packages/freebsd.scm index e66413c..6da5b03 100644 --- a/modules/fruix/packages/freebsd.scm +++ b/modules/fruix/packages/freebsd.scm @@ -1,7 +1,20 @@ (define-module (fruix packages freebsd) #:use-module (srfi srfi-1) #:use-module (srfi srfi-9) + #:use-module (srfi srfi-13) #:export (freebsd-release + freebsd-base + freebsd-base? + freebsd-base-name + freebsd-base-version-label + freebsd-base-release + freebsd-base-branch + freebsd-base-source-root + freebsd-base-target + freebsd-base-target-arch + freebsd-base-kernconf + freebsd-base-make-flags + %default-freebsd-base freebsd-package? freebsd-package-name freebsd-package-version @@ -33,6 +46,13 @@ freebsd-native-runtime freebsd-native-bootloader freebsd-native-headers + freebsd-native-kernel-for + freebsd-native-world-for + freebsd-native-runtime-for + freebsd-native-bootloader-for + freebsd-native-headers-for + freebsd-native-system-packages-for + freebsd-native-development-profile-packages-for freebsd-native-build-package? freebsd-host-staged-package? %freebsd-native-system-packages @@ -67,6 +87,53 @@ (define freebsd-release "15.0-STABLE") +(define-record-type + (make-freebsd-base name version-label release branch source-root target + target-arch kernconf make-flags) + freebsd-base? + (name freebsd-base-name) + (version-label freebsd-base-version-label) + (release freebsd-base-release) + (branch freebsd-base-branch) + (source-root freebsd-base-source-root) + (target freebsd-base-target) + (target-arch freebsd-base-target-arch) + (kernconf freebsd-base-kernconf) + (make-flags freebsd-base-make-flags)) + +(define default-native-make-flags + '("__MAKE_CONF=/dev/null" + "SRCCONF=/dev/null" + "SRC_ENV_CONF=/dev/null" + "MK_DEBUG_FILES=no" + "MK_TESTS=no")) + +(define (default-freebsd-branch release) + (let ((major (car (string-split release #\.)))) + (cond + ((string-contains release "STABLE") + (string-append "stable/" major)) + ((string-contains release "RELEASE") + (string-append "releng/" major)) + (else + "unknown")))) + +(define* (freebsd-base #:key + (name "default") + (version-label freebsd-release) + (release freebsd-release) + (branch (default-freebsd-branch release)) + (source-root "/usr/src") + (target "amd64") + (target-arch "amd64") + (kernconf "GENERIC") + (make-flags default-native-make-flags)) + (make-freebsd-base name version-label release branch source-root target + target-arch kernconf make-flags)) + +(define %default-freebsd-base + (freebsd-base)) + (define freebsd-kernel (freebsd-package #:name "freebsd-kernel" @@ -469,150 +536,145 @@ library for profile experiments." #:install-plan '((file "/lib/libz.so.6" "lib/libz.so.6")))) -(define freebsd-native-kernel +(define default-native-world-prune-paths + '("usr/share/doc" + "usr/share/examples" + "usr/share/info" + "usr/share/man" + "usr/tests")) + +(define default-native-runtime-prune-paths + '("boot" + "rescue" + "usr/include" + "usr/lib/debug" + "usr/lib32" + "usr/obj" + "usr/src" + "usr/share/doc" + "usr/share/examples" + "usr/share/info" + "usr/share/man" + "usr/share/mk" + "usr/tests")) + +(define default-native-bootloader-keep-paths + '("boot/loader" + "boot/loader.efi" + "boot/device.hints" + "boot/defaults" + "boot/lua")) + +(define default-native-headers-keep-paths + '("usr/include" + "usr/share/mk")) + +(define (freebsd-base-native-plan base) + `((base-name . ,(freebsd-base-name base)) + (base-version-label . ,(freebsd-base-version-label base)) + (base-release . ,(freebsd-base-release base)) + (base-branch . ,(freebsd-base-branch base)) + (source-root . ,(freebsd-base-source-root base)) + (target . ,(freebsd-base-target base)) + (target-arch . ,(freebsd-base-target-arch base)) + (kernconf . ,(freebsd-base-kernconf base)) + (make-flags . ,(freebsd-base-make-flags base)))) + +(define (freebsd-native-plan base extra-fields) + (append (freebsd-base-native-plan base) extra-fields)) + +(define (freebsd-native-kernel-for base) (freebsd-package #:name "freebsd-native-kernel" - #:version freebsd-release + #:version (freebsd-base-version-label base) #:build-system 'freebsd-kernel-build-system #:home-page "https://www.freebsd.org/" #:synopsis "Native Fruix-managed FreeBSD kernel artifact" #:description - "FreeBSD-specific package definition that builds a kernel from /usr/src and -stages the resulting boot/kernel tree as a real Fruix store artifact. This is -the first native replacement for the earlier host-copy kernel package." + "FreeBSD-specific package definition that builds a kernel from a declared +FreeBSD base input and stages the resulting boot/kernel tree as a real Fruix +store artifact." #:license 'bsd-2 #:install-plan - '((source-root . "/usr/src") - (target . "amd64") - (target-arch . "amd64") - (kernconf . "GENERIC") - (make-flags . ("__MAKE_CONF=/dev/null" - "SRCCONF=/dev/null" - "SRC_ENV_CONF=/dev/null" - "MK_DEBUG_FILES=no" - "MK_TESTS=no"))))) + (freebsd-native-plan base '()))) -(define freebsd-native-world +(define (freebsd-native-world-for base) (freebsd-package #:name "freebsd-native-world" - #:version freebsd-release + #:version (freebsd-base-version-label base) #:build-system 'freebsd-world-build-system #:home-page "https://www.freebsd.org/" #:synopsis "Native Fruix-managed FreeBSD world artifact" #:description "FreeBSD-specific package definition that builds and installs a broad -native world from /usr/src into a real Fruix store artifact. It still keeps a -large cross-section of boot and runtime files together and now serves as the -broad source artifact that later native runtime/boot splits derive from." +native world from a declared FreeBSD base input into a real Fruix store +artifact." #:license 'bsd-2 #:install-plan - '((source-root . "/usr/src") - (target . "amd64") - (target-arch . "amd64") - (kernconf . "GENERIC") - (make-flags . ("__MAKE_CONF=/dev/null" - "SRCCONF=/dev/null" - "SRC_ENV_CONF=/dev/null" - "MK_DEBUG_FILES=no" - "MK_TESTS=no")) - (prune-paths . ("usr/share/doc" - "usr/share/examples" - "usr/share/info" - "usr/share/man" - "usr/tests"))))) + (freebsd-native-plan base + `((prune-paths . ,default-native-world-prune-paths))))) -(define freebsd-native-runtime +(define (freebsd-native-runtime-for base) (freebsd-package #:name "freebsd-native-runtime" - #:version freebsd-release + #:version (freebsd-base-version-label base) #:build-system 'freebsd-world-build-system #:home-page "https://www.freebsd.org/" #:synopsis "Native Fruix-managed FreeBSD runtime slice" #:description "FreeBSD-specific package definition that stages a runtime-focused slice of -installworld/distribution from /usr/src. It removes the boot tree and obvious -development-oriented paths so the validated Fruix guest can use an explicit -native runtime output rather than reusing the broader native world artifact for -both boot and runtime roles." +installworld/distribution from a declared FreeBSD base input." #:license 'bsd-2 #:install-plan - '((source-root . "/usr/src") - (target . "amd64") - (target-arch . "amd64") - (kernconf . "GENERIC") - (make-flags . ("__MAKE_CONF=/dev/null" - "SRCCONF=/dev/null" - "SRC_ENV_CONF=/dev/null" - "MK_DEBUG_FILES=no" - "MK_TESTS=no")) - (prune-paths . ("boot" - "rescue" - "usr/include" - "usr/lib/debug" - "usr/lib32" - "usr/obj" - "usr/src" - "usr/share/doc" - "usr/share/examples" - "usr/share/info" - "usr/share/man" - "usr/share/mk" - "usr/tests"))))) + (freebsd-native-plan base + `((prune-paths . ,default-native-runtime-prune-paths))))) -(define freebsd-native-bootloader +(define (freebsd-native-bootloader-for base) (freebsd-package #:name "freebsd-native-bootloader" - #:version freebsd-release + #:version (freebsd-base-version-label base) #:build-system 'freebsd-world-build-system #:home-page "https://www.freebsd.org/" #:synopsis "Native Fruix-managed FreeBSD boot asset slice" #:description "FreeBSD-specific package definition that stages only the loader and boot -support assets needed by the validated Fruix image path. It is the narrower -native replacement for using the broad native world output as a temporary -boot-source artifact." +support assets needed by the validated Fruix image path from a declared +FreeBSD base input." #:license 'bsd-2 #:install-plan - '((source-root . "/usr/src") - (target . "amd64") - (target-arch . "amd64") - (kernconf . "GENERIC") - (make-flags . ("__MAKE_CONF=/dev/null" - "SRCCONF=/dev/null" - "SRC_ENV_CONF=/dev/null" - "MK_DEBUG_FILES=no" - "MK_TESTS=no")) - (keep-paths . ("boot/loader" - "boot/loader.efi" - "boot/device.hints" - "boot/defaults" - "boot/lua"))))) + (freebsd-native-plan base + `((keep-paths . ,default-native-bootloader-keep-paths))))) -(define freebsd-native-headers +(define (freebsd-native-headers-for base) (freebsd-package #:name "freebsd-native-headers" - #:version freebsd-release + #:version (freebsd-base-version-label base) #:build-system 'freebsd-world-build-system #:home-page "https://www.freebsd.org/" #:synopsis "Native Fruix-managed FreeBSD headers slice" #:description "FreeBSD-specific package definition that stages the userland header set and -build-system support files from installworld/distribution so development -profiles can depend on an explicit headers artifact rather than on the runtime -slice." +build-system support files from installworld/distribution for a declared +FreeBSD base input." #:license 'bsd-2 #:install-plan - '((source-root . "/usr/src") - (target . "amd64") - (target-arch . "amd64") - (kernconf . "GENERIC") - (make-flags . ("__MAKE_CONF=/dev/null" - "SRCCONF=/dev/null" - "SRC_ENV_CONF=/dev/null" - "MK_DEBUG_FILES=no" - "MK_TESTS=no")) - (keep-paths . ("usr/include" - "usr/share/mk"))))) + (freebsd-native-plan base + `((keep-paths . ,default-native-headers-keep-paths))))) + +(define freebsd-native-kernel + (freebsd-native-kernel-for %default-freebsd-base)) + +(define freebsd-native-world + (freebsd-native-world-for %default-freebsd-base)) + +(define freebsd-native-runtime + (freebsd-native-runtime-for %default-freebsd-base)) + +(define freebsd-native-bootloader + (freebsd-native-bootloader-for %default-freebsd-base)) + +(define freebsd-native-headers + (freebsd-native-headers-for %default-freebsd-base)) (define (freebsd-native-build-package? package) (not (not (memq (freebsd-package-build-system package) @@ -681,12 +743,12 @@ slice." (fourth-wave . (freebsd-kernel-headers freebsd-clang-toolchain)) (fifth-wave . (freebsd-gmake freebsd-autotools freebsd-openssl freebsd-zlib freebsd-sh freebsd-bash)))) -(define %freebsd-native-system-packages - (list freebsd-native-runtime)) +(define (freebsd-native-system-packages-for base) + (list (freebsd-native-runtime-for base))) -(define %freebsd-native-development-profile-packages - (list freebsd-native-runtime - freebsd-native-headers +(define (freebsd-native-development-profile-packages-for base) + (list (freebsd-native-runtime-for base) + (freebsd-native-headers-for base) freebsd-clang-toolchain freebsd-gmake freebsd-autotools @@ -695,6 +757,12 @@ slice." freebsd-sh freebsd-bash)) +(define %freebsd-native-system-packages + (freebsd-native-system-packages-for %default-freebsd-base)) + +(define %freebsd-native-development-profile-packages + (freebsd-native-development-profile-packages-for %default-freebsd-base)) + (define %freebsd-core-packages %freebsd-host-staged-core-packages) (define %freebsd-development-profile-packages %freebsd-host-staged-development-profile-packages) (define %freebsd-system-packages %freebsd-host-staged-system-packages) diff --git a/modules/fruix/system/freebsd.scm b/modules/fruix/system/freebsd.scm index 997b667..b1843b2 100644 --- a/modules/fruix/system/freebsd.scm +++ b/modules/fruix/system/freebsd.scm @@ -35,6 +35,7 @@ operating-system operating-system? operating-system-host-name + operating-system-freebsd-base operating-system-kernel operating-system-bootloader operating-system-base-packages @@ -96,11 +97,12 @@ (make-file-system device mount-point type options needed-for-boot?)) (define-record-type - (make-operating-system host-name kernel bootloader base-packages users groups + (make-operating-system host-name freebsd-base kernel bootloader base-packages users groups file-systems services loader-entries rc-conf-entries init-mode ready-marker root-authorized-keys) operating-system? (host-name operating-system-host-name) + (freebsd-base operating-system-freebsd-base) (kernel operating-system-kernel) (bootloader operating-system-bootloader) (base-packages operating-system-base-packages) @@ -116,6 +118,7 @@ (define* (operating-system #:key (host-name "fruix-freebsd") + (freebsd-base %default-freebsd-base) (kernel freebsd-kernel) (bootloader freebsd-bootloader) (base-packages %freebsd-system-packages) @@ -160,7 +163,7 @@ (init-mode 'freebsd-init+rc.d-shepherd) (ready-marker "/var/lib/fruix/ready") (root-authorized-keys '())) - (make-operating-system host-name kernel bootloader base-packages users groups + (make-operating-system host-name freebsd-base kernel bootloader base-packages users groups file-systems services loader-entries rc-conf-entries init-mode ready-marker root-authorized-keys)) @@ -304,9 +307,16 @@ (kernconf-sha256 . ,(file-hash kernconf-path)) (make-flags . ,make-flags)))) +(define (native-build-declared-base plan) + `((name . ,(build-plan-ref plan 'base-name "default")) + (version-label . ,(build-plan-ref plan 'base-version-label freebsd-release)) + (release . ,(build-plan-ref plan 'base-release freebsd-release)) + (branch . ,(build-plan-ref plan 'base-branch "unknown")))) + (define (native-build-manifest-string package input-paths) (let* ((plan (freebsd-package-install-plan package)) (common (native-build-common-manifest plan)) + (declared-base (native-build-declared-base plan)) (keep-paths (build-plan-ref plan 'keep-paths '())) (prune-paths (build-plan-ref plan 'prune-paths '()))) (string-append @@ -314,7 +324,9 @@ "version=" (freebsd-package-version package) "\n" "build-system=" (symbol->string (freebsd-package-build-system package)) "\n" "inputs=" (string-join input-paths ",") "\n" - "native-build-common=\n" + "declared-base=\n" + (object->string declared-base) + "\nnative-build-common=\n" (object->string common) "\nkeep-paths=\n" (object->string keep-paths) @@ -466,6 +478,7 @@ (let ((plan (freebsd-package-install-plan package))) `((package . ,(freebsd-package-name package)) (version . ,(freebsd-package-version package)) + (declared-base . ,(native-build-declared-base plan)) (build-system . ,(freebsd-package-build-system package)) (source-root . ,(assoc-ref common 'source-root)) (source-tree-sha256 . ,(assoc-ref common 'source-tree-sha256)) @@ -669,6 +682,17 @@ (define (package-names packages) (map freebsd-package-name packages)) +(define (freebsd-base-spec base) + `((name . ,(freebsd-base-name base)) + (version-label . ,(freebsd-base-version-label base)) + (release . ,(freebsd-base-release base)) + (branch . ,(freebsd-base-branch base)) + (source-root . ,(freebsd-base-source-root base)) + (target . ,(freebsd-base-target base)) + (target-arch . ,(freebsd-base-target-arch base)) + (kernconf . ,(freebsd-base-kernconf base)) + (make-flags . ,(freebsd-base-make-flags base)))) + (define (duplicate-elements values) (let loop ((rest values) (seen '()) (duplicates '())) (match rest @@ -680,6 +704,7 @@ (define (validate-operating-system os) (let* ((host-name (operating-system-host-name os)) + (base (operating-system-freebsd-base os)) (users (operating-system-users os)) (groups (operating-system-groups os)) (file-systems (operating-system-file-systems os)) @@ -689,6 +714,8 @@ (init-mode (operating-system-init-mode os))) (when (string-null? host-name) (error "operating-system host-name must not be empty")) + (unless (freebsd-base? base) + (error "operating-system freebsd-base must be a record")) (let ((dups (duplicate-elements user-names))) (unless (null? dups) (error "duplicate user names in operating-system" dups))) @@ -1196,6 +1223,7 @@ "etc/shells" "etc/motd" "etc/ttys" + "metadata/freebsd-base.scm" "metadata/host-base-provenance.scm" "metadata/store-layout.scm" "activate" @@ -1241,6 +1269,7 @@ (define (operating-system-closure-spec os) (validate-operating-system os) `((host-name . ,(operating-system-host-name os)) + (freebsd-base . ,(freebsd-base-spec (operating-system-freebsd-base os))) (kernel-package . ,(freebsd-package-name (operating-system-kernel os))) (bootloader-package . ,(freebsd-package-name (operating-system-bootloader os))) (base-package-count . ,(length (operating-system-base-packages os))) @@ -1355,11 +1384,14 @@ store-classification)))) (fruix-runtime-stores (list guile-store guile-extra-store shepherd-store)) (metadata-files - `(("metadata/host-base-provenance.scm" + `(("metadata/freebsd-base.scm" + . ,(object->string (freebsd-base-spec (operating-system-freebsd-base os)))) + ("metadata/host-base-provenance.scm" . ,(object->string (host-freebsd-provenance))) ("metadata/store-layout.scm" . ,(object->string - `((host-base-store-count . ,(length host-base-stores)) + `((freebsd-base . ,(freebsd-base-spec (operating-system-freebsd-base os))) + (host-base-store-count . ,(length host-base-stores)) (host-base-stores . ,host-base-stores) (native-base-store-count . ,(length native-base-stores)) (native-base-stores . ,native-base-stores) @@ -1433,6 +1465,7 @@ (host-base-stores . ,host-base-stores) (native-base-stores . ,native-base-stores) (fruix-runtime-stores . ,fruix-runtime-stores) + (freebsd-base-file . ,(string-append closure-path "/metadata/freebsd-base.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")) (generated-files . ,(map car generated-files)) @@ -1519,6 +1552,7 @@ (root-partition-label "fruix-root") (serial-console "comconsole")) `((host-name . ,(operating-system-host-name os)) + (freebsd-base . ,(freebsd-base-spec (operating-system-freebsd-base os))) (boot-mode . ,boot-mode) (image-format . ,image-format) (partition-scheme . ,partition-scheme) @@ -1698,6 +1732,7 @@ (host-base-stores . ,(assoc-ref closure 'host-base-stores)) (native-base-stores . ,(assoc-ref closure 'native-base-stores)) (fruix-runtime-stores . ,(assoc-ref closure 'fruix-runtime-stores)) + (freebsd-base-file . ,(assoc-ref closure 'freebsd-base-file)) (host-base-provenance-file . ,(assoc-ref closure 'host-base-provenance-file)) (store-layout-file . ,(assoc-ref closure 'store-layout-file)) (image-spec . ,image-spec) diff --git a/scripts/fruix.scm b/scripts/fruix.scm index acbe66f..43fe5a3 100644 --- a/scripts/fruix.scm +++ b/scripts/fruix.scm @@ -2,6 +2,7 @@ !# (use-modules (fruix system freebsd) + (fruix packages freebsd) (ice-9 format) (ice-9 match) (srfi srfi-1) @@ -174,6 +175,7 @@ Options:\n\ (host-base-stores (assoc-ref result 'host-base-stores)) (native-base-stores (assoc-ref result 'native-base-stores)) (fruix-runtime-stores (assoc-ref result 'fruix-runtime-stores)) + (base (operating-system-freebsd-base os)) (host-provenance (call-with-input-file (assoc-ref result 'host-base-provenance-file) read))) (emit-metadata `((action . "build") @@ -181,6 +183,15 @@ Options:\n\ (system_variable . ,resolved-symbol) (store_dir . ,store-dir) (closure_path . ,closure-path) + (freebsd_base_name . ,(freebsd-base-name base)) + (freebsd_base_version_label . ,(freebsd-base-version-label base)) + (freebsd_base_release . ,(freebsd-base-release base)) + (freebsd_base_branch . ,(freebsd-base-branch base)) + (freebsd_base_source_root . ,(freebsd-base-source-root base)) + (freebsd_base_target . ,(freebsd-base-target base)) + (freebsd_base_target_arch . ,(freebsd-base-target-arch base)) + (freebsd_base_kernconf . ,(freebsd-base-kernconf base)) + (freebsd_base_file . ,(assoc-ref result 'freebsd-base-file)) (ready_marker . ,(operating-system-ready-marker os)) (kernel_store . ,(assoc-ref result 'kernel-store)) (bootloader_store . ,(assoc-ref result 'bootloader-store)) @@ -234,12 +245,22 @@ Options:\n\ (host-base-stores (assoc-ref result 'host-base-stores)) (native-base-stores (assoc-ref result 'native-base-stores)) (fruix-runtime-stores (assoc-ref result 'fruix-runtime-stores)) + (base (operating-system-freebsd-base os)) (host-provenance (call-with-input-file (assoc-ref result 'host-base-provenance-file) read))) (emit-metadata `((action . "image") (os_file . ,os-file) (system_variable . ,resolved-symbol) (store_dir . ,store-dir) + (freebsd_base_name . ,(freebsd-base-name base)) + (freebsd_base_version_label . ,(freebsd-base-version-label base)) + (freebsd_base_release . ,(freebsd-base-release base)) + (freebsd_base_branch . ,(freebsd-base-branch base)) + (freebsd_base_source_root . ,(freebsd-base-source-root base)) + (freebsd_base_target . ,(freebsd-base-target base)) + (freebsd_base_target_arch . ,(freebsd-base-target-arch base)) + (freebsd_base_kernconf . ,(freebsd-base-kernconf base)) + (freebsd_base_file . ,(assoc-ref result 'freebsd-base-file)) (disk_capacity . ,(assoc-ref image-spec 'disk-capacity)) (root_size . ,(assoc-ref image-spec 'root-size)) (image_store_path . ,(assoc-ref result 'image-store-path)) diff --git a/tests/system/phase15-declarative-base-pid1-operating-system.scm.in b/tests/system/phase15-declarative-base-pid1-operating-system.scm.in new file mode 100644 index 0000000..8d8fe98 --- /dev/null +++ b/tests/system/phase15-declarative-base-pid1-operating-system.scm.in @@ -0,0 +1,83 @@ +(use-modules (fruix system freebsd) + (fruix packages freebsd)) + +(define phase15-base + (freebsd-base + #:name "__BASE_NAME__" + #:version-label "__BASE_VERSION_LABEL__" + #:release "__BASE_RELEASE__" + #:branch "__BASE_BRANCH__" + #:source-root "/usr/src" + #:target "amd64" + #:target-arch "amd64" + #:kernconf "GENERIC")) + +(define phase15-operating-system + (operating-system + #:host-name "fruix-freebsd" + #:freebsd-base phase15-base + #:kernel (freebsd-native-kernel-for phase15-base) + #:bootloader (freebsd-native-bootloader-for phase15-base) + #:base-packages (freebsd-native-system-packages-for phase15-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__"))) diff --git a/tests/system/run-phase15-declarative-base-build.sh b/tests/system/run-phase15-declarative-base-build.sh new file mode 100755 index 0000000..b4e6618 --- /dev/null +++ b/tests/system/run-phase15-declarative-base-build.sh @@ -0,0 +1,180 @@ +#!/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/phase15-declarative-base-pid1-operating-system.scm.in} +system_name=${SYSTEM_NAME:-phase15-operating-system} +store_dir=${STORE_DIR:-/frx/store} +base_name=${BASE_NAME:-stable-default} +base_version_label=${BASE_VERSION_LABEL:-15.0-STABLE-declarative} +base_release=${BASE_RELEASE:-15.0-STABLE} +base_branch=${BASE_BRANCH:-stable/15} +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 "$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-phase15-declarative-build.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 + +phase15_os_file=$workdir/phase15-declarative-base-operating-system.scm +build_out=$workdir/build.txt +metadata_file=$workdir/phase15-declarative-base-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|__ROOT_AUTHORIZED_KEY__|$root_authorized_key|g" \ + "$os_template" > "$phase15_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 "$fruix_cmd" system build "$phase15_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_kernconf_out=$(sed -n 's/^freebsd_base_kernconf=//p' "$build_out") +freebsd_base_file=$(sed -n 's/^freebsd_base_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_base_kernconf_out" = GENERIC ] || { echo "unexpected freebsd base kernconf: $freebsd_base_kernconf_out" >&2; exit 1; } +[ -f "$freebsd_base_file" ] || { echo "missing freebsd base file: $freebsd_base_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 "version-label . \"$base_version_label\"" "$path" >/dev/null || { + echo "native build info missing declared version label in $path" >&2 + exit 1 + } + grep -F "branch . \"$base_branch\"" "$path" >/dev/null || { + echo "native build info missing declared branch in $path" >&2 + exit 1 + } +done + +grep -F "(name . \"$base_name\")" "$freebsd_base_file" >/dev/null || { + echo "freebsd base file missing name" >&2 + exit 1 +} +grep -F "(version-label . \"$base_version_label\")" "$freebsd_base_file" >/dev/null || { + echo "freebsd base file missing version label" >&2 + exit 1 +} +grep -F "(branch . \"$base_branch\")" "$store_layout_file" >/dev/null || { + echo "store layout file missing declared base branch" >&2 + exit 1 +} +grep -F "(freebsd-base" "$closure_path/parameters.scm" >/dev/null || { + echo "closure parameters do not record the freebsd base declaration" >&2 + exit 1 +} + +closure_base=$(basename "$closure_path") +cat >"$metadata_file" <