changeset 351: |
770f2d03efd8 |
parent: |
87546048623e
|
child: |
840cce757946 |
author: |
Richard Westhaver <ellis@rwest.io> |
date: |
Tue, 14 May 2024 13:53:07 -0400 |
permissions: |
-rw-r--r-- |
description: |
homer push/pull |
1 ;;; homer.lisp --- homectl utility 6 (:use :cl :std :log :sxp :rdb :skel :packy :cli :obj/id :krypt :vc) 7 (:export :main :home-config)) 9 (in-package :bin/homer) 10 (defvar *user* (sb-posix:getenv "USER")) 11 (defvar *user-homedir* (user-homedir-pathname)) 12 (defvar *default-user-homerc* (merge-pathnames ".homerc" *user-homedir*)) 13 (declaim (type home-config *home-config*)) 14 (defvar *home-config*) 16 (defclass home-config (sxp id) 17 ((user :initform *user* :initarg :user :type string) 18 (path :initform nil :initarg :path :type (or pathname null)) 19 (src ::initform nil :initarg :src :type (or null pathname vc-repo)) 20 (skel :initform (load-user-skelrc) :initarg :skel :type (or null pathname sk-user-config)) 21 (krypt :initform (load-kryptrc) :initarg :krypt :type (or null pathname krypt-config)) 22 (packy :initform nil :initarg :packy :type (or null pathname pk-user-config)) 23 (mail :initarg :mail :type pathname) 24 (shell :initarg :shell :type (or pathname shell-user-config)) 25 (editor :initarg :editor :type (or pathname editor-user-config)) 26 (wm :initarg :wm :type (or pathname wm-user-config)) 27 (browser :initarg :browser :type (or pathname browser-user-config)))) 30 (defmethod print-object ((self home-config) stream) 31 (print-unreadable-object (self stream :type t) 32 (format stream "~S ~A" :id (format-sxhash (id self))))) 34 (defun find-homer-symbol (s) 35 (find-symbol* (symbol-name s) :homer nil)) 37 (defmethod load-ast ((self home-config)) 38 (with-slots (ast) self 40 ;; ast is valid, modify object, set ast nil 42 (sb-int:doplist (k v) ast 43 (when-let ((s (find-homer-symbol k))) ;; needs to be correct package 44 (setf (slot-value self s) v))) 47 ;; invalid ast, signal error 48 (error 'sxp-syntax-error)))) 51 (defmethod build-ast ((self home-config) &key (nullp nil) (exclude '(ast id))) 59 (defun load-homerc (&optional (file *default-user-homerc*)) 60 "Load a homerc configuration from FILE. Defaults to ~/.homerc." 61 (unless (null (probe-file file)) 62 (let ((form (file-read-forms file))) 63 (setq *home-config* (load-ast (make-instance 'home-config :ast form :path file :id (sxhash form)))) 64 (with-slots (src) *home-config* 66 (setf src (pathname src)) 67 (if-let ((homer (sb-posix:getenv "HOMER"))) 68 (setf src (pathname homer)) 69 (error "missing HOMER directory"))))))) 72 (defopt homer-help (print-help $cli)) 73 (defopt homer-version (print-version $cli)) 74 (defopt homer-log-level (when $val (setq *log-level* :debug))) 77 (describe *home-config*)) 79 (defun mtime (path) (sb-posix:stat-mtime (sb-posix:stat path))) 81 (defun compare-to-home (src) 82 "Compare a SRC path to what is stored in the user's home. Return a cons with 83 the last modified timestamp of each file (SRC . HOME) or NIL." 84 (let* ((name (enough-namestring src)) 85 (home (merge-pathnames name (user-homedir-pathname))) 87 (m2 (when (probe-file home) (mtime home))) 93 (cons status (cons src home)))) 95 (defprompt homer-check "install file? [y/n]: ") 97 (defun homer-ask (form) 98 (let ((home (cddr form)) 100 (let ((input (homer-check-prompt))) 101 (unless (or (zerop (length input)) 102 (not (char= (aref input 0) #\y))) 103 (uiop:copy-file src home))))) 105 (defun homer-status (file) 106 (let ((form (compare-to-home file))) 109 (:new (println (format nil ":NEW ~A" (cdr form)))) 110 (:pull (println (format nil ":PULL ~A" (cadr form)))) 111 (:push (println (format nil ":PUSH ~A" (cddr form)))) 115 (with-slots (src) *home-config* 116 (if-let ((src (probe-file src))) 117 (let ((*default-pathname-defaults* src)) 118 (mapcar #'homer-status 120 *default-pathname-defaults* 121 (nconc *hidden-paths* (list "stash" "store" "readme.org" ".hgignore"))))) 122 (error 'file-error :pathname src)))) 124 (defun homer-maybe-push (file) 125 (let ((form (compare-to-home file))) 128 (println (format nil ":PUSH ~A" (cddr form))) 129 (uiop:copy-file (cddr form) (cadr form)))) 132 (defun homer-maybe-pull (file) 133 (let ((form (compare-to-home file))) 136 (println (format nil ":PUSH ~A" (cddr form))) 137 (uiop:copy-file (cadr form) (cddr form)))) 141 (with-slots (src) *home-config* 142 (if-let ((src (probe-file src))) 143 (let ((*default-pathname-defaults* src)) 144 (mapc #'homer-maybe-push 145 (find-files src (nconc *hidden-paths* (list "stash" "store" "readme.org" ".hgignore"))))) 146 (error 'file-error :pathname src)))) 149 (with-slots (src) *home-config* 150 (if-let ((src (probe-file src))) 151 (let ((*default-pathname-defaults* src)) 152 (mapc #'homer-maybe-pull 153 (find-files src (nconc *hidden-paths* (list "stash" "store" "readme.org" ".hgignore"))))) 154 (error 'file-error :pathname src)))) 156 (defcmd homer-install) 162 :description "user home manager" 165 (:name "level" :global t :description "set the log level" :thunk homer-log-level) 166 (:name "help" :global t :description "print help" :thunk homer-help) 167 (:name "version" :global t :description "print version" :thunk homer-version)) 169 (:name show :thunk homer-show) 170 (:name check :thunk homer-check) 171 (:name push :thunk homer-push) 172 (:name pull :thunk homer-pull))) 175 (let ((*log-level* :info)) 176 (with-cli (opts cmds args) $cli 182 (let ((*print-readably* t)) 184 (sb-ext:exit :code 0)))