store: centralize Fruix path naming

This commit is contained in:
2026-04-05 08:58:40 +02:00
parent 9dae4e5c84
commit 4975084baa
5 changed files with 109 additions and 22 deletions

View File

@@ -197,6 +197,51 @@ So if you come from Guix, assume that Fruix now has:
- explicit generation metadata roots - explicit generation metadata roots
- a real but still modest installed-system switch/rollback UX - a real but still modest installed-system switch/rollback UX
## 7. Fruix keeps Guix-like store semantics, but not Guix/Nix hash-prefix machinery exactly
Fruix still uses immutable store paths under:
- `/frx/store`
and it still treats a store path as a deployment identity boundary.
But Fruix now intentionally differs from Guix/Nix in how the visible store-path prefix is constructed.
Current Fruix policy is:
- centralize store-path naming behind shared helpers
- hash a small semantic identity record rather than copying Nix's historical path-hash formula exactly
- include at least:
- object kind
- logical/display name
- output name
- payload or manifest identity
- hash-scheme version marker
- truncate the visible SHA-256 prefix to **160 bits**
- render that visible prefix as **40 hex characters**
Why Fruix does this instead of copying Guix/Nix exactly:
- the main goal was shorter store prefixes, not Nix compatibility for its own sake
- distinct outputs should have distinct identities because `out`, `lib`, `debug`, and `doc` are semantically different artifacts
- Fruix wanted one central policy point that can be swapped later without touching every materializer again
- Fruix did **not** want to inherit Nix's legacy details unless they provide clear value here
- custom base32 alphabet and bit ordering
- compressed/XOR-folded path hashes
- exact historical `output:out` / `source` path-hash conventions
So compared with Guix:
- the important semantic property is the same:
- different store objects should get different immutable identities
- the exact printable prefix algorithm is intentionally simpler in Fruix today
For Guix-familiar operators, the practical takeaway is:
- still think of `/frx/store/...` paths as immutable deployment identities
- do **not** assume Fruix store prefixes are byte-for-byte comparable to Guix/Nix ones
- expect Fruix to prefer a simpler, centralized naming policy unless exact Guix/Nix behavior becomes necessary later
## Where Fruix is intentionally trying to improve on Guix's representation ## Where Fruix is intentionally trying to improve on Guix's representation
Fruix is not trying to improve on Guix's core semantics. Guix already got those right. Fruix is not trying to improve on Guix's core semantics. Guix already got those right.

View File

@@ -364,11 +364,11 @@
(cached (hash-ref cache cache-key #f))) (cached (hash-ref cache cache-key #f)))
(if cached (if cached
cached cached
(let* ((hash (sha256-string manifest)) (let* ((display-name (string-append (freebsd-package-name prepared-package)
(output-path (string-append store-dir "/" hash "-"
(freebsd-package-name prepared-package)
"-" "-"
(freebsd-package-version prepared-package)))) (freebsd-package-version prepared-package)))
(output-path (make-store-path store-dir display-name manifest
#:kind 'freebsd-package)))
(unless (file-exists? output-path) (unless (file-exists? output-path)
(case (freebsd-package-build-system prepared-package) (case (freebsd-package-build-system prepared-package)
((copy-build-system) ((copy-build-system)
@@ -454,8 +454,9 @@
(define* (materialize-prefix source-path name version store-dir #:key (extra-files '())) (define* (materialize-prefix source-path name version store-dir #:key (extra-files '()))
(let* ((manifest (prefix-manifest-string source-path extra-files)) (let* ((manifest (prefix-manifest-string source-path extra-files))
(hash (sha256-string manifest)) (display-name (string-append name "-" version))
(output-path (string-append store-dir "/" hash "-" name "-" version))) (output-path (make-store-path store-dir display-name manifest
#:kind 'prefix)))
(unless (file-exists? output-path) (unless (file-exists? output-path)
(mkdir-p output-path) (mkdir-p output-path)
(for-each (lambda (entry) (for-each (lambda (entry)

View File

@@ -172,9 +172,10 @@
"\n") "\n")
"\nreferences=\n" "\nreferences=\n"
(string-join references "\n"))) (string-join references "\n")))
(hash (sha256-string manifest)) (display-name (string-append "fruix-system-"
(closure-path (string-append store-dir "/" hash "-fruix-system-" (operating-system-host-name os)))
(operating-system-host-name os)))) (closure-path (make-store-path store-dir display-name manifest
#:kind 'operating-system)))
(unless (file-exists? closure-path) (unless (file-exists? closure-path)
(mkdir-p closure-path) (mkdir-p closure-path)
(mkdir-p (string-append closure-path "/boot/kernel")) (mkdir-p (string-append closure-path "/boot/kernel"))
@@ -870,9 +871,10 @@
"\nstore-items=\n" "\nstore-items=\n"
(string-join store-items "\n") (string-join store-items "\n")
"\n")) "\n"))
(hash (sha256-string manifest)) (display-name (string-append "fruix-bhyve-image-"
(image-store-path (string-append store-dir "/" hash "-fruix-bhyve-image-"
(operating-system-host-name os))) (operating-system-host-name os)))
(image-store-path (make-store-path store-dir display-name manifest
#:kind 'bhyve-image))
(disk-image (string-append image-store-path "/disk.img")) (disk-image (string-append image-store-path "/disk.img"))
(esp-image (string-append image-store-path "/esp.img")) (esp-image (string-append image-store-path "/esp.img"))
(root-image (string-append image-store-path "/root.ufs"))) (root-image (string-append image-store-path "/root.ufs")))
@@ -1024,9 +1026,10 @@
"\ninstall-metadata=\n" "\ninstall-metadata=\n"
(object->string install-metadata) (object->string install-metadata)
"\n")) "\n"))
(hash (sha256-string manifest)) (display-name (string-append "fruix-installer-image-"
(image-store-path (string-append store-dir "/" hash "-fruix-installer-image-"
(operating-system-host-name installer-os))) (operating-system-host-name installer-os)))
(image-store-path (make-store-path store-dir display-name manifest
#:kind 'installer-image))
(disk-image (string-append image-store-path "/disk.img")) (disk-image (string-append image-store-path "/disk.img"))
(esp-image (string-append image-store-path "/esp.img")) (esp-image (string-append image-store-path "/esp.img"))
(root-image (string-append image-store-path "/root.ufs"))) (root-image (string-append image-store-path "/root.ufs")))
@@ -1329,9 +1332,10 @@
"\ninstall-metadata=\n" "\ninstall-metadata=\n"
(object->string install-metadata) (object->string install-metadata)
"\n")) "\n"))
(hash (sha256-string manifest)) (display-name (string-append "fruix-installer-iso-"
(iso-store-path (string-append store-dir "/" hash "-fruix-installer-iso-"
(operating-system-host-name installer-os))) (operating-system-host-name installer-os)))
(iso-store-path (make-store-path store-dir display-name manifest
#:kind 'installer-iso))
(iso-image (string-append iso-store-path "/installer.iso")) (iso-image (string-append iso-store-path "/installer.iso"))
(boot-efi-image (string-append iso-store-path "/efiboot.img")) (boot-efi-image (string-append iso-store-path "/efiboot.img"))
(root-image (string-append iso-store-path "/root.img"))) (root-image (string-append iso-store-path "/root.img")))

View File

@@ -150,9 +150,10 @@
(effective-source (assoc-ref resolution 'effective-source)) (effective-source (assoc-ref resolution 'effective-source))
(identity (assoc-ref resolution 'identity)) (identity (assoc-ref resolution 'identity))
(manifest (freebsd-source-manifest source effective-source identity)) (manifest (freebsd-source-manifest source effective-source identity))
(hash (sha256-string manifest)) (display-name (string-append "freebsd-source-"
(output-path (string-append store-dir "/" hash "-freebsd-source-"
(safe-name-fragment (freebsd-source-name source)))) (safe-name-fragment (freebsd-source-name source))))
(output-path (make-store-path store-dir display-name manifest
#:kind 'freebsd-source))
(info-file (string-append output-path "/.freebsd-source-info.scm")) (info-file (string-append output-path "/.freebsd-source-info.scm"))
(cache-path (assoc-ref resolution 'cache-path)) (cache-path (assoc-ref resolution 'cache-path))
(populate-tree (assoc-ref resolution 'populate-tree))) (populate-tree (assoc-ref resolution 'populate-tree)))

View File

@@ -14,6 +14,8 @@
safe-command-output safe-command-output
write-file write-file
sha256-string sha256-string
store-hash-string
make-store-path
file-hash file-hash
directory-entries directory-entries
path-signature path-signature
@@ -68,6 +70,40 @@
(write-file tmp text) (write-file tmp text)
(command-output "sha256" "-q" tmp))) (command-output "sha256" "-q" tmp)))
(define store-hash-visible-length 40)
(define store-hash-scheme-version "1")
(define (store-identity-field value)
(cond ((symbol? value)
(symbol->string value))
((string? value)
value)
(else
(object->string value))))
(define* (store-hash-string payload #:key (kind 'item) name (output "out"))
(let* ((identity `((scheme . "fruix-store-path")
(version . ,store-hash-scheme-version)
(kind . ,(store-identity-field kind))
(name . ,(store-identity-field (or name "")))
(output . ,(store-identity-field output))
(payload . ,payload)))
(digest (sha256-string (object->string identity))))
(string-take digest store-hash-visible-length)))
(define* (make-store-path store-dir display-name payload
#:key
(kind 'item)
name
(output "out"))
(string-append store-dir "/"
(store-hash-string payload
#:kind kind
#:name (or name display-name)
#:output output)
"-"
display-name))
(define (file-hash path) (define (file-hash path)
(command-output "sha256" "-q" path)) (command-output "sha256" "-q" path))