git.fiddlerwoaroof.com
Browse code

feat: store hash in commits

Edward Langley authored on 22/10/2023 09:08:28
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