Browse code
feat: store hash in commits
Edward Langley authored on 22/10/2023 09:08:28
Showing 3 changed files
Showing 3 changed files
... | ... |
@@ -1,11 +1,21 @@ |
1 | 1 |
(in-package :fwoar.cl-git) |
2 | 2 |
|
3 | 3 |
(defclass git-commit () |
4 |
- ((%metadata :initarg :metadata :reader metadata) |
|
4 |
+ ((%hash :initarg :hash :reader hash) |
|
5 |
+ (%metadata :initarg :metadata :reader metadata) |
|
5 | 6 |
(%data :initarg :data :reader data))) |
6 | 7 |
|
7 |
-(defun git-commit (metadata data) |
|
8 |
- (fw.lu:new 'git-commit metadata data)) |
|
8 |
+(defmethod print-object ((o git-commit) s) |
|
9 |
+ (if *print-readably* |
|
10 |
+ (format s "#.(git-commit ~<~s~_~s~_~s~:>)" |
|
11 |
+ (list (hash o) |
|
12 |
+ (metadata o) |
|
13 |
+ (data o))) |
|
14 |
+ (print-unreadable-object (o s :type t :identity t) |
|
15 |
+ (format s "~a" (subseq (hash o) 0 6))))) |
|
16 |
+ |
|
17 |
+(defun git-commit (hash metadata data) |
|
18 |
+ (fw.lu:new 'git-commit hash metadata data)) |
|
9 | 19 |
|
10 | 20 |
(defun parse-commit (commit) |
11 | 21 |
(destructuring-bind (metadata message) |
... | ... |
@@ -15,14 +25,18 @@ |
15 | 25 |
(map 'vector (serapeum:op (partition #\space _)) |
16 | 26 |
(fwoar.string-utils:split #\newline metadata))))) |
17 | 27 |
|
18 |
-(defun make-commit (data) |
|
28 |
+(defun make-commit (data hash) |
|
19 | 29 |
(multiple-value-bind (message metadata) |
20 | 30 |
(parse-commit data) |
21 |
- (git-commit metadata message))) |
|
31 |
+ (git-commit hash metadata message))) |
|
32 |
+ |
|
33 |
+(defmethod -extract-object-of-type ((type (eql :commit)) s repository &key hash) |
|
34 |
+ (make-commit (babel:octets-to-string s :encoding *git-encoding*) |
|
35 |
+ hash)) |
|
22 | 36 |
|
23 |
-(defmethod -extract-object-of-type ((type (eql :commit)) s repository &key) |
|
24 |
- (make-commit (babel:octets-to-string s :encoding *git-encoding*))) |
|
25 | 37 |
|
38 |
+(defmethod component ((component (eql :hash)) (object git-commit)) |
|
39 |
+ (hash object)) |
|
26 | 40 |
|
27 | 41 |
(defmethod component ((component (eql :tree)) (object git-commit)) |
28 | 42 |
(ensure-ref |
... | ... |
@@ -17,11 +17,13 @@ |
17 | 17 |
2))) |
18 | 18 |
(file-position s (+ sha-offset (* 20 mid))) |
19 | 19 |
(let ((sha-at-mid (read-bytes 20 'fwoar.bin-parser:byte-array-to-hex-string s))) |
20 |
- (cond ((string< sha sha-at-mid) |
|
20 |
+ (cond ((serapeum:string-prefix-p sha sha-at-mid) |
|
21 |
+ (values mid sha-at-mid)) |
|
22 |
+ ((string< sha sha-at-mid) |
|
21 | 23 |
(find-sha-between-terms toc s start mid sha)) |
22 | 24 |
((string> sha sha-at-mid) |
23 | 25 |
(find-sha-between-terms toc s (1+ mid) end sha)) |
24 |
- (t mid)))))) |
|
26 |
+ (t (values mid sha-at-mid))))))) |
|
25 | 27 |
|
26 | 28 |
(defun find-pack-containing (pack-file id) |
27 | 29 |
(with-open-file (s (index-file pack-file) |
... | ... |
@@ -30,19 +32,21 @@ |
30 | 32 |
(toc (idx-toc s))) |
31 | 33 |
(multiple-value-bind (_ end) (edges-in-fanout toc s binary-sha) |
32 | 34 |
(declare (ignore _)) |
33 |
- (let ((midpoint (find-sha-between-terms toc s 0 end id))) |
|
35 |
+ (multiple-value-bind (midpoint sha) |
|
36 |
+ (find-sha-between-terms toc s 0 end id) |
|
34 | 37 |
(and midpoint |
35 | 38 |
(values pack-file |
36 |
- midpoint))))))) |
|
39 |
+ midpoint |
|
40 |
+ sha))))))) |
|
37 | 41 |
|
38 | 42 |
(defun find-object-in-pack-files (repo id) |
39 | 43 |
(dolist (pack-file (pack-files repo)) |
40 |
- (multiple-value-bind (pack mid) (find-pack-containing pack-file id) |
|
44 |
+ (multiple-value-bind (pack mid sha) (find-pack-containing pack-file id) |
|
41 | 45 |
(when pack |
42 | 46 |
(return-from find-object-in-pack-files |
43 |
- (values pack mid)))))) |
|
47 |
+ (values pack mid sha)))))) |
|
44 | 48 |
|
45 |
-(defun read-object-from-pack (s repository) |
|
49 |
+(defun read-object-from-pack (s repository ref) |
|
46 | 50 |
(let* ((pos (file-position s)) |
47 | 51 |
(metadata (fwoar.bin-parser:extract-high s)) |
48 | 52 |
(type (object-type->sym (get-object-type metadata))) |
... | ... |
@@ -52,31 +56,41 @@ |
52 | 56 |
(read-sequence buffer s) |
53 | 57 |
buffer) |
54 | 58 |
(chipz:decompress nil (chipz:make-dstate 'chipz:zlib) s))) |
55 |
- (object-data (extract-object-of-type type decompressed repository pos (pathname s)))) |
|
59 |
+ (object-data (extract-object-of-type type decompressed repository pos (pathname s) ref))) |
|
56 | 60 |
(list (cons :type (object-type->sym type)) |
57 | 61 |
(cons :decompressed-size size) |
58 | 62 |
(cons :object-data object-data) |
59 | 63 |
(cons :raw-data decompressed)))) |
60 | 64 |
|
61 |
-(defun extract-object-of-type (type s repository pos packfile) |
|
62 |
- (with-simple-restart (continue "Skip object of type ~s" type) |
|
65 |
+(defun extract-object-of-type (type s repository pos packfile ref) |
|
66 |
+ (with-simple-restart (continue "Skip object of type ~s at position ~d" |
|
67 |
+ type |
|
68 |
+ pos) |
|
63 | 69 |
(-extract-object-of-type (object-type->sym type) |
64 | 70 |
s |
65 | 71 |
repository |
66 | 72 |
:offset-from pos |
67 |
- :packfile packfile))) |
|
73 |
+ :packfile packfile |
|
74 |
+ :hash (ref-hash ref)))) |
|
68 | 75 |
|
69 |
-(defun extract-object-from-pack (pack obj-number) |
|
76 |
+(defun pack-offset-for-object (index-file obj-number) |
|
77 |
+ (let ((offset-offset (getf index-file |
|
78 |
+ :4-byte-offsets))) |
|
79 |
+ (+ offset-offset |
|
80 |
+ (* 4 obj-number)))) |
|
81 |
+ |
|
82 |
+(defun extract-object-from-pack (pack obj-number ref) |
|
70 | 83 |
(with-open-file (s (index-file pack) :element-type '(unsigned-byte 8)) |
71 | 84 |
(with-open-file (p (pack-file pack) :element-type '(unsigned-byte 8)) |
72 |
- (let* ((toc (idx-toc s)) |
|
73 |
- (offset-offset (getf toc :4-byte-offsets))) |
|
74 |
- (file-position s (+ offset-offset (* 4 obj-number))) |
|
75 |
- (let ((object-offset-in-pack (read-bytes 4 'fwoar.bin-parser:be->int s))) |
|
76 |
- (file-position p object-offset-in-pack) |
|
77 |
- (read-object-from-pack p (repository pack))))))) |
|
85 |
+ (file-position s (pack-offset-for-object (idx-toc s) |
|
86 |
+ obj-number)) |
|
87 |
+ (let ((object-offset-in-pack (read-bytes 4 'fwoar.bin-parser:be->int s))) |
|
88 |
+ (file-position p object-offset-in-pack) |
|
89 |
+ (read-object-from-pack p |
|
90 |
+ (repository pack) |
|
91 |
+ ref))))) |
|
78 | 92 |
|
79 |
-(defun extract-loose-object (repo file) |
|
93 |
+(defun extract-loose-object (repo file ref) |
|
80 | 94 |
(with-open-file (s file :element-type '(unsigned-byte 8)) |
81 | 95 |
(alexandria:when-let ((result (chipz:decompress nil (chipz:make-dstate 'chipz:zlib) |
82 | 96 |
s))) |
... | ... |
@@ -87,13 +101,16 @@ |
87 | 101 |
1) |
88 | 102 |
repo |
89 | 103 |
0 |
90 |
- nil))))) |
|
104 |
+ nil |
|
105 |
+ ref))))) |
|
91 | 106 |
|
92 | 107 |
(defgeneric extract-object (object) |
93 | 108 |
(:method ((object loose-ref)) |
94 | 109 |
(extract-loose-object (ref-repo object) |
95 |
- (loose-ref-file object))) |
|
110 |
+ (loose-ref-file object) |
|
111 |
+ object)) |
|
96 | 112 |
(:method ((object packed-ref)) |
97 | 113 |
(data-lens.lenses:view *object-data-lens* |
98 | 114 |
(extract-object-from-pack (packed-ref-pack object) |
99 |
- (packed-ref-offset object))))) |
|
115 |
+ (packed-ref-offset object) |
|
116 |
+ object)))) |
... | ... |
@@ -7,10 +7,10 @@ |
7 | 7 |
(truename repo))))) |
8 | 8 |
|
9 | 9 |
(defun packed-ref (repo id) |
10 |
- (multiple-value-bind (pack offset) (find-object-in-pack-files repo id) |
|
10 |
+ (multiple-value-bind (pack offset sha) (find-object-in-pack-files repo id) |
|
11 | 11 |
(when pack |
12 | 12 |
(make-instance 'packed-ref |
13 |
- :hash id |
|
13 |
+ :hash sha |
|
14 | 14 |
:repo repo |
15 | 15 |
:offset offset |
16 | 16 |
:pack pack)))) |
... | ... |
@@ -18,13 +18,14 @@ |
18 | 18 |
(defgeneric ref (repo id) |
19 | 19 |
(:documentation "Given a REPOsitory and a ref ID return the ref-id object.") |
20 | 20 |
(:method ((repo git-repository) (id string)) |
21 |
- (let ((repo-root (root-of repo))) |
|
22 |
- (or (alexandria:when-let ((object-file (loose-object repo id))) |
|
23 |
- (make-instance 'loose-ref |
|
24 |
- :repo repo-root |
|
25 |
- :hash id |
|
26 |
- :file object-file)) |
|
27 |
- (packed-ref repo id))))) |
|
21 |
+ (or (alexandria:when-let ((object-file (loose-object repo id))) |
|
22 |
+ (make-instance 'loose-ref |
|
23 |
+ :repo repo |
|
24 |
+ :hash (concatenate 'string |
|
25 |
+ (subseq id 0 2) |
|
26 |
+ (pathname-name object-file)) |
|
27 |
+ :file object-file)) |
|
28 |
+ (packed-ref repo id)))) |
|
28 | 29 |
|
29 | 30 |
(defun ensure-ref (thing &optional (repo *git-repository*)) |
30 | 31 |
(typecase thing |