991d0162 |
(in-package :fwoar.cl-git)
|
e24e2318 |
;; TODO: Update the code so this uses an object instead of a path.
(defvar *git-repository*)
(setf (documentation '*git-repository* 'variable)
"The git repository path for porcelain commands to operate on.")
|
991d0162 |
(defvar *git-encoding* :utf-8
"The encoding to use when parsing git objects")
|
bdf26afb |
(defun co.fwoar.git:in-repository (root)
|
e623be68 |
(setf *git-repository*
|
216c17e7 |
(ensure-repository
(truename root))))
|
e623be68 |
|
bdf26afb |
(defun co.fwoar.git:repository ()
|
c672c979 |
*git-repository*)
|
bdf26afb |
(defmacro co.fwoar.git:with-repository ((root) &body body)
|
216c17e7 |
`(let ((*git-repository* (ensure-repository ,root)))
|
b7df27f1 |
,@body))
|
bdf26afb |
(defun co.fwoar.git:show-repository ()
|
ad9b8a82 |
*git-repository*)
|
821ddf96 |
(defun in-git-package (symbol)
(intern (symbol-name symbol)
|
bdf26afb |
:co.fwoar.git))
|
821ddf96 |
|
71da880a |
(defun handle-list (_1)
(case (in-git-package (car _1))
|
bdf26afb |
(co.fwoar.git::unwrap `(uiop:nest (car)
(mapcar ,@(cdr _1))))
|
71da880a |
(t (cons (in-git-package (car _1))
(cdr _1)))))
|
bdf26afb |
(defun co.fwoar.git::resolve-refish (it)
|
69664515 |
(flet ((hash-p (it)
(and (> (length it) 32)
(every (serapeum:op
(digit-char-p _1 16))
it))))
(cond
|
a77dddb5 |
((block is-branch
(mapc (fw.lu:destructuring-lambda ((name hash))
(when (equal it name)
(return-from is-branch
(ensure-ref hash))))
(branches *git-repository*))
nil))
|
69664515 |
((hash-p it) (ensure-ref it)))))
|
bdf26afb |
(defmacro co.fwoar.git:git (&rest commands)
|
0b3ed859 |
`(uiop:nest ,@(reverse
|
69664515 |
(funcall (data-lens:<>1
(data-lens:over (serapeum:op
(typecase _1
(string `(identity ,_1))
(list (handle-list _1)))))
(data-lens:transform-head (serapeum:op
(etypecase _1
|
bdf26afb |
(string `(co.fwoar.git::resolve-refish ,_1))
|
69664515 |
(t _1)))))
commands))))
|
71da880a |
|
bdf26afb |
(defun co.fwoar.git::ensure-ref (it)
|
b7df27f1 |
(ensure-ref it))
|
bdf26afb |
(defun co.fwoar.git::decode (it)
|
69664515 |
(babel:octets-to-string it :encoding *git-encoding*))
|
bdf26afb |
(defun co.fwoar.git::<<= (fun &rest args)
|
821ddf96 |
(apply #'mapcan fun args))
|
bdf26afb |
(defmacro co.fwoar.git::map (fun list)
|
b7df27f1 |
(alexandria:once-only (list)
(alexandria:with-gensyms (it)
`(mapcar ,(if (consp fun)
`(lambda (,it)
(,(in-git-package (car fun))
,@(cdr fun)
,it))
`',(in-git-package fun))
,list))))
|
bdf26afb |
(defmacro co.fwoar.git::juxt (&rest args)
|
b7df27f1 |
(let ((funs (butlast args))
(arg (car (last args))))
(alexandria:once-only (arg)
`(list ,@(mapcar (lambda (f)
`(,@(alexandria:ensure-list f) ,arg))
funs)))))
|
bdf26afb |
(defmacro co.fwoar.git::pipe (&rest funs)
|
71da880a |
(let ((funs (reverse (butlast funs)))
(var (car (last funs))))
`(uiop:nest ,@(mapcar (lambda (it)
(if (consp it)
`(,(in-git-package (car it)) ,@(cdr it))
`(,(in-git-package it))))
funs)
,var)))
|
bdf26afb |
(defun co.fwoar.git::filter (fun &rest args)
|
b7df27f1 |
(apply #'remove-if-not fun args))
|
bdf26afb |
(defun co.fwoar.git::object (thing)
|
b7df27f1 |
(extract-object thing))
|
0c24c8f9 |
|
bdf26afb |
(defun co.fwoar.git:show (object)
|
69664515 |
(extract-object object))
|
e623be68 |
|
bdf26afb |
(defun co.fwoar.git:contents (object)
(co.fwoar.git:show object))
|
5cb25684 |
|
bdf26afb |
(defun co.fwoar.git:component (&rest args)
|
b7df27f1 |
(let ((component-list (butlast args))
(target (car (last args))))
(fwoar.cl-git::component component-list target)))
|
bdf26afb |
(defun co.fwoar.git:tree (commit-object)
|
b7df27f1 |
(component :tree
commit-object))
|
5cb25684 |
|
bdf26afb |
(defun co.fwoar.git::filter-tree (name-pattern tree)
|
5cb25684 |
#+lispworks
(declare (notinline serapeum:string-prefix-p))
|
1869d7ea |
(let* ((tree-entries (component :entries tree))
(scanner (cl-ppcre:create-scanner name-pattern)))
|
5cb25684 |
(remove-if-not (serapeum:op
|
1869d7ea |
(cl-ppcre:scan scanner _))
tree-entries
:key #'te-name)))
|
5cb25684 |
|
bdf26afb |
(defun co.fwoar.git:branch (&optional (branch :master))
|
0b3ed859 |
#+lispworks
(declare (notinline serapeum:assocadr))
|
216c17e7 |
(let ((branches (branches *git-repository*)))
(ref *git-repository*
|
b7df27f1 |
(serapeum:assocadr (etypecase branch
(string branch)
(keyword (string-downcase branch)))
branches
:test 'equal))))
|
e623be68 |
|
bdf26afb |
(defun co.fwoar.git:branches ()
|
216c17e7 |
(branches *git-repository*))
|
e623be68 |
|
bdf26afb |
(defun co.fwoar.git::parents (commit)
|
aa622e50 |
(mapcar 'ensure-ref
(component :parents commit)))
|
bdf26afb |
(defun co.fwoar.git:commit-parents (commit)
(co.fwoar.git::parents commit))
|
961c04e3 |
|
bdf26afb |
(defun co.fwoar.git:rev-list (ref-id &optional (limit nil limit-p))
|
961c04e3 |
"Return the commits reachable from the ref."
|
2d105ecd |
(when limit-p
(rotatef ref-id limit))
|
c584afa5 |
(let ((seen (make-hash-table)))
(labels ((iterate (queue accum &optional (count 0))
(if (or (when limit-p
(= limit count))
(null queue))
accum
(destructuring-bind (next . rest) queue
(let ((parents (co.fwoar.git::parents next)))
(iterate (append rest parents)
(if (gethash next seen)
accum
(progn
(setf (gethash next seen) t)
(cons next accum)))
(1+ count)))))))
(iterate (list (ensure-ref ref-id))
()))))
|