a7c6e622 |
(in-package :fwoar.cl-git)
(defparameter *object-data-lens*
(data-lens.lenses:make-alist-lens :object-data))
(defclass pack ()
((%pack :initarg :pack :reader pack-file)
|
0b3ed859 |
(%index :initarg :index :reader index-file)
(%repository :initarg :repository :reader repository)))
|
a7c6e622 |
(defclass repository ()
((%root :initarg :root :reader root)))
|
ea4edd3f |
(defclass git-repository (repository)
())
|
a7c6e622 |
(defclass git-object ()
|
489818ad |
((%hash :initarg :hash :accessor hash)))
|
a7c6e622 |
|
077088c8 |
(defgeneric object-type->sym (object-type)
|
cea280bb |
(:documentation "Canonicalizes different representations of an
object type to their symbol representation."))
(defmethod object-type->sym ((o-t symbol))
o-t)
|
077088c8 |
(defmethod object-type->sym ((object-type number))
|
a7c6e622 |
(ecase object-type
(1 :commit)
(2 :tree)
(3 :blob)
(4 :tag)
(6 :ofs-delta)
(7 :ref-delta)))
|
4cc1ee49 |
|
077088c8 |
(defmethod object-type->sym ((object-type string))
(string-case:string-case ((string-downcase object-type))
("commit" :commit)
("tree" :tree)
("blob" :blob)
("tag" :tag)
("ofs-delta" :ofs-delta)
("ref-delta" :ref-delta)))
|
a7c6e622 |
|
ea4edd3f |
(define-condition alts-fallthrough (error)
((%fallthrough-message :initarg :fallthrough-message :reader fallthrough-message)
(%args :initarg :args :reader args))
(:report (lambda (c s)
(format s "~a ~s"
(fallthrough-message c)
(args c)))))
;; TODO: figure out how to handle ambiguity? restarts?
(define-method-combination alts (&key fallthrough-message) ((methods *))
(:arguments arg)
(progn
(mapc (serapeum:op
(let ((qualifiers (method-qualifiers _1)))
(unless (and (eql 'alts (car qualifiers))
(if (null (cdr qualifiers))
t
(and (symbolp (cadr qualifiers))
(null (cddr qualifiers)))))
(invalid-method-error _1 "invalid qualifiers: ~s" qualifiers))))
methods)
`(or ,@(mapcar (serapeum:op `(call-method ,_1))
methods)
(error 'alts-fallthrough
:fallthrough-message ,fallthrough-message
:args ,arg))))
(defgeneric resolve-repository (object)
(:documentation "resolve an OBJECT to a repository implementation")
(:method-combination alts :fallthrough-message "failed to resolve repository"))
(defmethod resolve-repository alts :git ((root pathname))
(alexandria:when-let ((root (probe-file root)))
(let* ((git-dir (merge-pathnames (make-pathname :directory '(:relative ".git"))
root)))
(when (probe-file git-dir)
(fw.lu:new 'git-repository root)))))
(defgeneric repository (object)
(:documentation "get the repository for an object")
|
f5f88835 |
(:method ((root repository))
root)
|
ea4edd3f |
(:method ((root pathname))
(resolve-repository root))
|
0b3ed859 |
(:method ((root string))
|
216c17e7 |
(let ((root (parse-namestring root)))
|
ea4edd3f |
(repository root))))
|
a7c6e622 |
(defun get-local-branches (root)
(append (get-local-unpacked-branches root)
(get-local-packed-branches root)))
(defun loose-object-path (sha)
(let ((obj-path (fwoar.string-utils:insert-at 2 #\/ sha)))
(merge-pathnames obj-path ".git/objects/")))
|
0b3ed859 |
(defun pack (index pack repository)
(fw.lu:new 'pack index pack repository))
|
a7c6e622 |
|
6df34ee9 |
(defmacro with-pack-streams ((idx-sym pack-sym) pack &body body)
(alexandria:once-only (pack)
`(with-open-file (,idx-sym (index-file ,pack) :element-type 'fwoar.cl-git.types:octet)
(with-open-file (,pack-sym (pack-file ,pack) :element-type 'fwoar.cl-git.types:octet)
,@body))))
|
ee4281cb |
(defgeneric pack-files (repo)
(:method ((repo git-repository))
(mapcar (serapeum:op
(pack _1
(merge-pathnames
(make-pathname :type "pack") _1)
repo))
(uiop:directory*
(merge-pathnames ".git/objects/pack/*.idx"
(root-of repo))))))
|
846489f7 |
(defgeneric loose-object (repository id)
(:method ((repository string) id)
(when (probe-file (merge-pathnames ".git" repository))
|
bb861f9e |
(loose-object (repository repository)
id)))
|
846489f7 |
(:method ((repository pathname) id)
(when (probe-file (merge-pathnames ".git" repository))
|
bb861f9e |
(loose-object (repository repository)
id)))
|
846489f7 |
(:method ((repository repository) id)
(car
(uiop:directory*
(merge-pathnames (loose-object-path (serapeum:concat id "*"))
(root repository))))))
(defun loose-object-p (repository id)
"Is ID an ID of a loose object?"
(loose-object repository id))
|
4cc1ee49 |
(defclass git-ref ()
((%repo :initarg :repo :reader ref-repo)
(%hash :initarg :hash :reader ref-hash)))
(defclass loose-ref (git-ref)
((%file :initarg :file :reader loose-ref-file)))
(defclass packed-ref (git-ref)
((%pack :initarg :pack :reader packed-ref-pack)
(%offset :initarg :offset :reader packed-ref-offset)))
(defmethod print-object ((obj git-ref) s)
|
bb861f9e |
(print-unreadable-object (obj s :type t :identity t)
|
846489f7 |
(format s "~a of ~a"
|
bb861f9e |
(subseq (ref-hash obj) 0 6)
|
ee4281cb |
(ref-repo obj)
#+(or)
|
846489f7 |
(serapeum:string-replace (namestring (user-homedir-pathname))
|
4cc1ee49 |
(root-of (ref-repo obj))
|
846489f7 |
"~/"))))
|
489818ad |
(defmethod component ((component (eql :hash)) (object git-object))
(hash object))
|
69fc740c |
(defmethod component ((component (eql :hash)) (object git-ref))
(ref-hash object))
|