git.fiddlerwoaroof.com
Browse code

feat: add a git-repository class

Ed L authored on 15/11/2020 19:03:49
Showing 1 changed files
... ...
@@ -10,6 +10,8 @@
10 10
 
11 11
 (defclass repository ()
12 12
   ((%root :initarg :root :reader root)))
13
+(defclass git-repository (repository)
14
+  ())
13 15
 
14 16
 (defclass git-object ()
15 17
   ())
... ...
@@ -39,13 +41,51 @@
39 41
     ("ofs-delta" :ofs-delta)
40 42
     ("ref-delta" :ref-delta)))
41 43
 
42
-(defgeneric repository (root)
44
+(define-condition alts-fallthrough (error)
45
+  ((%fallthrough-message :initarg :fallthrough-message :reader fallthrough-message)
46
+   (%args :initarg :args :reader args))
47
+  (:report (lambda (c s)
48
+             (format s "~a ~s"
49
+                     (fallthrough-message c)
50
+                     (args c)))))
51
+
52
+;; TODO: figure out how to handle ambiguity? restarts?
53
+(define-method-combination alts (&key fallthrough-message) ((methods *))
54
+  (:arguments arg)
55
+  (progn
56
+    (mapc (serapeum:op
57
+            (let ((qualifiers (method-qualifiers _1)))
58
+              (unless (and (eql 'alts (car qualifiers))
59
+                           (if (null (cdr qualifiers))
60
+                               t
61
+                               (and (symbolp (cadr qualifiers))
62
+                                    (null (cddr qualifiers)))))
63
+                (invalid-method-error _1 "invalid qualifiers: ~s" qualifiers))))
64
+          methods)
65
+    `(or ,@(mapcar (serapeum:op `(call-method ,_1))
66
+                   methods)
67
+         (error 'alts-fallthrough
68
+                :fallthrough-message ,fallthrough-message
69
+                :args ,arg))))
70
+
71
+(defgeneric resolve-repository (object)
72
+  (:documentation "resolve an OBJECT to a repository implementation")
73
+  (:method-combination alts :fallthrough-message "failed to resolve repository"))
74
+
75
+(defmethod resolve-repository alts :git ((root pathname))
76
+  (alexandria:when-let ((root (probe-file root)))
77
+    (let* ((git-dir (merge-pathnames (make-pathname :directory '(:relative ".git"))
78
+                                     root)))
79
+      (when (probe-file git-dir)
80
+        (fw.lu:new 'git-repository root)))))
81
+
82
+(defgeneric repository (object)
83
+  (:documentation "get the repository for an object")
84
+  (:method ((root pathname))
85
+    (resolve-repository root))
43 86
   (:method ((root string))
44 87
     (let ((root (parse-namestring root)))
45
-      (repository root)))
46
-  (:method ((root pathname))
47
-    (let ((root (truename root)))
48
-      (fw.lu:new 'repository root))))
88
+      (repository root))))
49 89
 
50 90
 (defun get-local-branches (root)
51 91
   (append (get-local-unpacked-branches root)