sx-git Phase 1: blob/tree/commit/tag as content-addressed typed objects (TDD)
Objects are plain dicts over persist kv, addressed by sx1:<sha256> of the artdag/canon canonical form (sorted dict keys) — native CIDs, extensible fields participate in identity. 38/38. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
81
lib/git/object.sx
Normal file
81
lib/git/object.sx
Normal file
@@ -0,0 +1,81 @@
|
||||
; lib/git/object.sx — sx-git Phase 1: blob/tree/commit/tag as content-addressed
|
||||
; TYPED objects over the persist kv store. Identity = host digest of the
|
||||
; canonical serialization (artdag/canon: sorted dict keys, escaped strings) —
|
||||
; native CIDs, NOT git wire bytes. Objects are plain dicts: typed, extensible;
|
||||
; unknown fields round-trip and participate in the CID.
|
||||
; Requires: lib/persist/backend.sx, lib/persist/kv.sx, lib/artdag/dag.sx.
|
||||
|
||||
; ---- canonical form + content id ----
|
||||
(define git/canon (fn (obj) (artdag/canon obj)))
|
||||
|
||||
(define
|
||||
git/cid
|
||||
(fn (obj) (str "sx1:" (crypto-sha256 (artdag/canon obj)))))
|
||||
|
||||
; ---- repo handle: a persist backend + key prefix (many repos per db) ----
|
||||
(define git/repo-named (fn (db name) {:prefix name :db db}))
|
||||
(define git/repo (fn (db) (git/repo-named db "git")))
|
||||
(define git/repo-db (fn (repo) (get repo :db)))
|
||||
(define git/obj-key (fn (repo cid) (str (get repo :prefix) "/obj/" cid)))
|
||||
|
||||
; ---- constructors ----
|
||||
(define git/blob (fn (data) {:data data :type "blob"}))
|
||||
|
||||
; entries: dict of name -> entry, entry = {:kind "blob"|"tree" :cid cid ...}
|
||||
(define git/tree (fn (entries) {:type "tree" :entries entries}))
|
||||
(define git/tree-entry (fn (kind cid) {:kind kind :cid cid}))
|
||||
|
||||
; meta: open dict (:author :message :time ... anything); protected keys win
|
||||
(define git/commit (fn (tree parents meta) (merge meta {:type "commit" :tree tree :parents parents})))
|
||||
|
||||
(define git/tag (fn (target name meta) (merge meta {:name name :type "tag" :target target})))
|
||||
|
||||
; ---- predicates / accessors ----
|
||||
(define git/object-type (fn (obj) (get obj :type)))
|
||||
(define
|
||||
git/blob?
|
||||
(fn (obj) (and (dict? obj) (equal? (get obj :type) "blob"))))
|
||||
(define
|
||||
git/tree?
|
||||
(fn (obj) (and (dict? obj) (equal? (get obj :type) "tree"))))
|
||||
(define
|
||||
git/commit?
|
||||
(fn (obj) (and (dict? obj) (equal? (get obj :type) "commit"))))
|
||||
(define
|
||||
git/tag?
|
||||
(fn (obj) (and (dict? obj) (equal? (get obj :type) "tag"))))
|
||||
|
||||
(define git/blob-data (fn (obj) (get obj :data)))
|
||||
(define git/tree-entries (fn (obj) (get obj :entries)))
|
||||
(define git/tree-entry-for (fn (obj name) (get (get obj :entries) name)))
|
||||
(define
|
||||
git/tree-names
|
||||
(fn (obj) (artdag/sort-strings (keys (get obj :entries)))))
|
||||
(define git/entry-cid (fn (entry) (get entry :cid)))
|
||||
(define git/entry-kind (fn (entry) (get entry :kind)))
|
||||
(define git/commit-tree (fn (obj) (get obj :tree)))
|
||||
(define git/commit-parents (fn (obj) (get obj :parents)))
|
||||
(define git/commit-author (fn (obj) (get obj :author)))
|
||||
(define git/commit-message (fn (obj) (get obj :message)))
|
||||
(define git/tag-target (fn (obj) (get obj :target)))
|
||||
(define git/tag-name (fn (obj) (get obj :name)))
|
||||
|
||||
; ---- object store: write/read/has, keyed by cid ----
|
||||
(define
|
||||
git/write
|
||||
(fn
|
||||
(repo obj)
|
||||
(let
|
||||
((cid (git/cid obj)))
|
||||
(begin (persist/kv-put (get repo :db) (git/obj-key repo cid) obj) cid))))
|
||||
|
||||
(define
|
||||
git/read
|
||||
(fn (repo cid) (persist/kv-get (get repo :db) (git/obj-key repo cid))))
|
||||
|
||||
(define
|
||||
git/has?
|
||||
(fn (repo cid) (persist/kv-has? (get repo :db) (git/obj-key repo cid))))
|
||||
|
||||
; convenience: write a blob straight from data
|
||||
(define git/write-blob (fn (repo data) (git/write repo (git/blob data))))
|
||||
Reference in New Issue
Block a user