git.fiddlerwoaroof.com
Raw Blame History
(in-package :fwoar.cl-git)

(defvar *git-repository* nil
  "The git repository path for porcelain commands to operate on.")
(defvar *git-encoding* :utf-8
  "The encoding to use when parsing git objects")

(defun git:in-repository (root)
  (setf *git-repository*
        (truename root)))

(defun git:show-repository ()
  *git-repository*)

(defun in-git-package (symbol)
  (intern (symbol-name symbol)
          :git))

(defmacro git:git (&rest commands)
  `(uiop:nest ,@(reverse
                 (mapcar (serapeum:op
                           (typecase _1
                             (string `(identity ,_1))
                             (list (case (in-git-package (car _1))
                                     (git::unwrap `(uiop:nest (car)
                                                              (mapcar ,@(cdr _1))))
                                     (t (cons (in-git-package (car _1)) 
                                              (cdr _1)))))))
                         commands))))

(defun git::<<= (fun &rest args)
  (apply #'mapcan fun args))

(defun git::map (fun &rest args)
  (apply #'mapcar fun args))

(defun git:show (object)
  (babel:octets-to-string
   (coerce (extract-object-next (object (repository *git-repository*)
                                        object))
           '(vector serapeum:octet))
   :encoding *git-encoding*))

(defun git:contents (object)
  (git:show object))

(defstruct (tree-entry (:type vector))
  te-name te-mode te-id)

(defun git:tree (commit)
  (cadr (fw.lu:v-assoc "tree"
                       (nth-value 1 (parse-commit commit))
                       :test 'equal)))

(defun git::filter-tree (name-pattern tree)
  #+lispworks
  (declare (notinline serapeum:string-prefix-p))
  (let* ((lines (fwoar.string-utils:split #\newline tree))
         (columns (map 'list
                       (serapeum:op
                         (coerce (fwoar.string-utils:split #\tab _)
                                 'simple-vector))
                       lines)))
    (remove-if-not (serapeum:op
                     (cl-ppcre:scan name-pattern _ ))
                   columns
                   :key #'tree-entry-te-name)))

(defun git:branch (&optional (branch :master))
  #+lispworks
  (declare (notinline serapeum:assocadr))
  (let ((branches (branches (repository *git-repository*))))
    (nth-value 0 (serapeum:assocadr (etypecase branch
                                      (string branch)
                                      (keyword (string-downcase branch)))
                                    branches
                                    :test 'equal))))

(defun git:branches ()
  (branches (repository *git-repository*)))

(defun git:commit-parents (commit)
  (map 'list #'cadr
       (remove-if-not (serapeum:op
                        (string= "parent" _))
                      (nth-value 1
                                 (fwoar.cl-git::parse-commit
                                  (git:show commit)))
                      :key #'car)))