summaryrefslogtreecommitdiff
path: root/src/cli.lisp
diff options
context:
space:
mode:
authorPiotr Szarmanski2023-08-03 00:31:49 +0200
committerPiotr Szarmanski2023-08-03 00:31:49 +0200
commit552dfc187707185940cb11c31e66e47ca3efacca (patch)
tree27715de1728a2d3cdd4c04af48563e620625219a /src/cli.lisp
Init.
Diffstat (limited to 'src/cli.lisp')
-rw-r--r--src/cli.lisp135
1 files changed, 135 insertions, 0 deletions
diff --git a/src/cli.lisp b/src/cli.lisp
new file mode 100644
index 0000000..2f03425
--- /dev/null
+++ b/src/cli.lisp
@@ -0,0 +1,135 @@
+(in-package :ybackup)
+
+#|
+(defun fetch-configuration ()
+ (let ((xdg (uiop:getenv "XDG_CONFIG_DIR")))
+ (if xdg
+ (setf xdg (concatenate 'string xdg "/ybackup.lisp"))
+ (setf xdg (concatenate 'string (uiop:getenv "HOME") "/.config/ybackup.lisp")))
+ (ensure-directories-exist xdg)
+ (with-open-file (file xdg :if-does-not-exist :create)
+ (uiop:with-safe-io-syntax
+ (uiop:slurp-stream-form :at nil)))))
+|#
+(opts:define-opts
+ (:name :help
+ :description "Print this text"
+ :short #\h
+ :long "help")
+ (:name :backup
+ :description "Directory to backup"
+ :short #\b
+ :long "backup"
+ :arg-parser #'identity
+ :meta-var "DIRECTORY")
+ (:name :read
+ :description "Read a backup to a directory"
+ :short #\r
+ :long "read"
+ :arg-parser #'identity
+ :meta-var "DIRECTORY")
+ (:name :list-files
+ :description "List the files in the repository."
+ :short #\l
+ :long "list")
+ (:name :file-backend
+ :description
+ "Use this for a file-based local backup. The argument is the directory that will
+contain the ERIS chunks."
+ :long "file-backend"
+ :arg-parser #'identity
+ :meta-var "DIRECTORY")
+ (:name :http-backend
+ :description
+ "Use this for an HTTP-based backup. The argument is the URL which will accept
+the ERIS chunks."
+ :long "http"
+ :arg-parser #'identity
+ :meta-var "URL")
+ (:name :backend
+ :description "An S-expression that returns a valid eris:backend object."
+ :long "backend"
+ :meta-var "SEXP"
+ :arg-parser #'read-from-string)
+ (:name :filter
+ :description
+ "A one-argument lambda S-expression that takes a filename as an argument and
+returns nil if the file is to be read or t if it is to be skipped."
+ :long "filter"
+ :meta-var "SEXP"
+ :arg-parser #'read-from-string)
+ (:name :overwrite
+ :description "Set if the program should overwrite existing files when writing from backup. "
+ :long "overwrite")
+ (:name :incremental
+ :description "Set to enable incremental backup. Requires the --repo optio.."
+ :short #\i
+ :long "incremental")
+ (:name :repo
+ :description "The file that the URN will be written or read from."
+ :long "repo"
+ :meta-var "FILE OR URN"
+ :arg-parser #'identity)
+ (:name :secret
+ :description "The secret used for encryption."
+ :long "secret"
+ :short #\s
+ :meta-var "SECRET"
+ :arg-parser #'identity)
+ (:name :metadata
+ :description "Print repository metadata when reading or listing files."
+ :long "metadata"
+ :short #\m))
+
+(defun file-or-urn-to-urn (file-or-urn)
+ (if (string-prefix-p "urn:" file-or-urn)
+ file-or-urn
+ (with-open-file (file file-or-urn :direction :input :if-does-not-exist :error)
+ (read-line file))))
+
+(defun main ()
+ (restart-case (destructuring-bind (&key help backup read list-files
+ file-backend http-backend backend
+ filter overwrite incremental repo
+ secret metadata)
+ (opts:get-opts)
+ ;; some sanity checks
+ ;; exclusive options
+ (when (or (and backup read) (and backup list-files) (and read list-files))
+ (error "Choose one of read, backup, or list."))
+ (when (or (and backend http-backend) (and backend file-backend) (and file-backend http-backend))
+ (error "Choose one backend."))
+
+ (when help
+ (opts:describe :prefix #.(format nil "ybackup version ~a" version))
+ (opts:exit))
+
+ ;; repo argument necessary except for backup
+ #|(when (and (not repo) backup)
+ (error "Please provide --repo argument."))|#
+
+ ;; don't save urns to files named urn:
+ #|(when (and backup repo (string-prefix-p "urn:" repo))
+ (error "No urns as filenames."))|#
+
+ (let ((backend
+ (cond
+ (file-backend (make-instance 'eris:file-backend :directory file-backend))
+ (http-backend (error "Unimplemented http-backend."))
+ (backend (eval backend))
+ (t (error "Choose backend.")))))
+ ;; TODO:
+ ;; ADD METADATA, SECRET HANDLING (!!!)
+
+ (cond
+ (list-files
+ (print (list-files (file-or-urn-to-urn repo) backend))
+ ())
+ (backup (let ((urn (make-backup backup backend :incremental incremental)))
+ (if repo (with-open-file (file repo :direction :output :if-does-not-exist :create
+ :if-exists :new-version)
+ (write-string urn file))
+ (princ urn))))
+ (read (read-backup (file-or-urn-to-urn repo) backend read :overwrite overwrite)))
+ (opts:exit)))
+ (exit () (opts:exit))))