Merge branch 'dev' into cl-port
This commit is contained in:
commit
04ede947b4
22
TODO.org
22
TODO.org
|
@ -936,8 +936,20 @@ The plist backend could theoretically be extended to support it, but I'd rather
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CREATED: 2022-01-08T23:32:37+0530
|
:CREATED: 2022-01-08T23:32:37+0530
|
||||||
:END:
|
:END:
|
||||||
1. [ ] default suggested input backend should be the active backend
|
1. [ ] On first launch, offer list of supported backends to migrate from
|
||||||
2. [ ] conserve file local variables prop line for text backends
|
+ Some backends may not be installed - "see MELPA for more formats"
|
||||||
|
2. [ ] Use active backend as the suggested input backend
|
||||||
|
3. [ ] Conserve file local variables prop line for text backends
|
||||||
|
|
||||||
|
** make migrate command async [33%]
|
||||||
|
:PROPERTIES:
|
||||||
|
:CREATED: 2022-04-01T18:02:03+0530
|
||||||
|
:END:
|
||||||
|
=chronometrist-migrate= / =chronometrist-to-file= can take a long time to run, freezing Emacs until completion if run synchronously.
|
||||||
|
|
||||||
|
1. [X] basic async export
|
||||||
|
2. [ ] display message on start and completion
|
||||||
|
3. [ ] test the INPUT-FILE argument
|
||||||
|
|
||||||
* STARTED Support for the Third Time System [57%] :extension:
|
* STARTED Support for the Third Time System [57%] :extension:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -1042,3 +1054,9 @@ Similar to [[#verify-command][verify command]], perhaps, but this is really abou
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CREATED: 2022-02-28T11:35:47+0530
|
:CREATED: 2022-02-28T11:35:47+0530
|
||||||
:END:
|
:END:
|
||||||
|
|
||||||
|
* User-defined categories
|
||||||
|
:PROPERTIES:
|
||||||
|
:CREATED: 2022-03-31T22:44:34+0530
|
||||||
|
:END:
|
||||||
|
A task can be part of any number of categories. A category may also contain other categories. The categories, and the total time spent on each one, could be displayed in the main view, separate from the tasks.
|
||||||
|
|
|
@ -96,7 +96,7 @@ Return the connection object from `emacsql-sqlite'."
|
||||||
(cl-defmethod chronometrist-to-file (hash-table (backend chronometrist-sqlite-backend) file)
|
(cl-defmethod chronometrist-to-file (hash-table (backend chronometrist-sqlite-backend) file)
|
||||||
(with-slots (connection) backend
|
(with-slots (connection) backend
|
||||||
(delete-file file)
|
(delete-file file)
|
||||||
(emacsql-close connection)
|
(when connection (emacsql-close connection))
|
||||||
(setf connection nil)
|
(setf connection nil)
|
||||||
(chronometrist-create-file backend file)
|
(chronometrist-create-file backend file)
|
||||||
(cl-loop for date in (sort (hash-table-keys hash-table) #'string-lessp) do
|
(cl-loop for date in (sort (hash-table-keys hash-table) #'string-lessp) do
|
||||||
|
@ -120,7 +120,10 @@ prop-id of the inserted or existing property."
|
||||||
(emacsql connection
|
(emacsql connection
|
||||||
[:insert-or-ignore-into properties [properties] :values [$s1]]
|
[:insert-or-ignore-into properties [properties] :values [$s1]]
|
||||||
props)
|
props)
|
||||||
(caar (emacsql connection [:select (funcall max prop-id) :from properties])))))
|
(caar (emacsql connection [:select [prop-id]
|
||||||
|
:from properties
|
||||||
|
:where (= properties $s1)]
|
||||||
|
props)))))
|
||||||
|
|
||||||
(defun chronometrist-sqlite-properties-to-json (plist)
|
(defun chronometrist-sqlite-properties-to-json (plist)
|
||||||
"Return PLIST as a JSON string."
|
"Return PLIST as a JSON string."
|
||||||
|
@ -156,22 +159,23 @@ s-expressions in a text column."
|
||||||
(date-unix (chronometrist-iso-to-unix (chronometrist-iso-to-date start)))
|
(date-unix (chronometrist-iso-to-unix (chronometrist-iso-to-date start)))
|
||||||
(start-unix (chronometrist-iso-to-unix start))
|
(start-unix (chronometrist-iso-to-unix start))
|
||||||
(stop-unix (and stop (chronometrist-iso-to-unix stop)))
|
(stop-unix (and stop (chronometrist-iso-to-unix stop)))
|
||||||
name-id interval-id)
|
name-id interval-id prop-id)
|
||||||
;; insert name if it does not exist
|
;; insert name if it does not exist
|
||||||
(emacsql db [:insert-or-ignore-into interval-names [name]
|
(emacsql db [:insert-or-ignore-into interval-names [name]
|
||||||
:values [$s1]]
|
:values [$s1]]
|
||||||
name)
|
name)
|
||||||
;; insert interval properties if they do not exist
|
;; insert interval properties if they do not exist
|
||||||
(chronometrist-sqlite-insert-properties backend plist)
|
(setq prop-id (chronometrist-sqlite-insert-properties backend plist))
|
||||||
;; insert interval and associate it with the date
|
;; insert interval and associate it with the date
|
||||||
(setq name-id
|
(setq name-id
|
||||||
(caar (emacsql db [:select [name-id]
|
(caar (emacsql db [:select [name-id]
|
||||||
:from interval-names
|
:from interval-names
|
||||||
:where (= name $s1)]
|
:where (= name $s1)]
|
||||||
name)))
|
name)))
|
||||||
(emacsql db [:insert-or-ignore-into intervals [name-id start-time stop-time]
|
(emacsql db [:insert-or-ignore-into intervals
|
||||||
:values [$s1 $s2 $s3]]
|
[name-id start-time stop-time prop-id]
|
||||||
name-id start-unix stop-unix)
|
:values [$s1 $s2 $s3 $s4]]
|
||||||
|
name-id start-unix stop-unix prop-id)
|
||||||
(emacsql db [:insert-or-ignore-into dates [date]
|
(emacsql db [:insert-or-ignore-into dates [date]
|
||||||
:values [$s1]] date-unix)
|
:values [$s1]] date-unix)
|
||||||
(setq date-id
|
(setq date-id
|
||||||
|
@ -201,6 +205,6 @@ s-expressions in a text column."
|
||||||
(cl-defmethod chronometrist-replace-last ((backend chronometrist-sqlite-backend) plist)
|
(cl-defmethod chronometrist-replace-last ((backend chronometrist-sqlite-backend) plist)
|
||||||
(emacsql db [:delete-from events :where ]))
|
(emacsql db [:delete-from events :where ]))
|
||||||
|
|
||||||
(provide 'chronometrist-sqlite3)
|
(provide 'chronometrist-sqlite)
|
||||||
|
|
||||||
;;; chronometrist-sqlite3.el ends here
|
;;; chronometrist-sqlite.el ends here
|
||||||
|
|
|
@ -115,29 +115,18 @@ Return the connection object from `emacsql-sqlite'."
|
||||||
finally return db)))
|
finally return db)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
** to-file :method:
|
** iso-to-unix :function:
|
||||||
#+BEGIN_SRC emacs-lisp :load no :tangle no
|
|
||||||
(cl-defmethod chronometrist-to-file (hash-table (backend chronometrist-sqlite-backend) file)
|
|
||||||
(cl-loop with db = (emacsql-sqlite file)
|
|
||||||
with count = 0
|
|
||||||
for records being the hash-values of hash-table do
|
|
||||||
(cl-loop for record in records do
|
|
||||||
(chronometrist-insert record db)
|
|
||||||
(cl-incf count)
|
|
||||||
(when (zerop (% count 5))
|
|
||||||
(message "chronometrist-migrate - %s records converted" count)))
|
|
||||||
finally return count do
|
|
||||||
(message "chronometrist-migrate - finished converting %s events." count)))
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun chronometrist-iso-to-unix (timestamp)
|
(defun chronometrist-iso-to-unix (timestamp)
|
||||||
(truncate (float-time (parse-iso8601-time-string timestamp))))
|
(truncate (float-time (parse-iso8601-time-string timestamp))))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
** to-file :method:
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
(cl-defmethod chronometrist-to-file (hash-table (backend chronometrist-sqlite-backend) file)
|
(cl-defmethod chronometrist-to-file (hash-table (backend chronometrist-sqlite-backend) file)
|
||||||
(with-slots (connection) backend
|
(with-slots (connection) backend
|
||||||
(delete-file file)
|
(delete-file file)
|
||||||
(emacsql-close connection)
|
(when connection (emacsql-close connection))
|
||||||
(setf connection nil)
|
(setf connection nil)
|
||||||
(chronometrist-create-file backend file)
|
(chronometrist-create-file backend file)
|
||||||
(cl-loop for date in (sort (hash-table-keys hash-table) #'string-lessp) do
|
(cl-loop for date in (sort (hash-table-keys hash-table) #'string-lessp) do
|
||||||
|
@ -164,7 +153,10 @@ prop-id of the inserted or existing property."
|
||||||
(emacsql connection
|
(emacsql connection
|
||||||
[:insert-or-ignore-into properties [properties] :values [$s1]]
|
[:insert-or-ignore-into properties [properties] :values [$s1]]
|
||||||
props)
|
props)
|
||||||
(caar (emacsql connection [:select (funcall max prop-id) :from properties])))))
|
(caar (emacsql connection [:select [prop-id]
|
||||||
|
:from properties
|
||||||
|
:where (= properties $s1)]
|
||||||
|
props)))))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
*** properties-to-json :function:
|
*** properties-to-json :function:
|
||||||
|
@ -209,22 +201,23 @@ s-expressions in a text column."
|
||||||
(date-unix (chronometrist-iso-to-unix (chronometrist-iso-to-date start)))
|
(date-unix (chronometrist-iso-to-unix (chronometrist-iso-to-date start)))
|
||||||
(start-unix (chronometrist-iso-to-unix start))
|
(start-unix (chronometrist-iso-to-unix start))
|
||||||
(stop-unix (and stop (chronometrist-iso-to-unix stop)))
|
(stop-unix (and stop (chronometrist-iso-to-unix stop)))
|
||||||
name-id interval-id)
|
name-id interval-id prop-id)
|
||||||
;; insert name if it does not exist
|
;; insert name if it does not exist
|
||||||
(emacsql db [:insert-or-ignore-into interval-names [name]
|
(emacsql db [:insert-or-ignore-into interval-names [name]
|
||||||
:values [$s1]]
|
:values [$s1]]
|
||||||
name)
|
name)
|
||||||
;; insert interval properties if they do not exist
|
;; insert interval properties if they do not exist
|
||||||
(chronometrist-sqlite-insert-properties backend plist)
|
(setq prop-id (chronometrist-sqlite-insert-properties backend plist))
|
||||||
;; insert interval and associate it with the date
|
;; insert interval and associate it with the date
|
||||||
(setq name-id
|
(setq name-id
|
||||||
(caar (emacsql db [:select [name-id]
|
(caar (emacsql db [:select [name-id]
|
||||||
:from interval-names
|
:from interval-names
|
||||||
:where (= name $s1)]
|
:where (= name $s1)]
|
||||||
name)))
|
name)))
|
||||||
(emacsql db [:insert-or-ignore-into intervals [name-id start-time stop-time]
|
(emacsql db [:insert-or-ignore-into intervals
|
||||||
:values [$s1 $s2 $s3]]
|
[name-id start-time stop-time prop-id]
|
||||||
name-id start-unix stop-unix)
|
:values [$s1 $s2 $s3 $s4]]
|
||||||
|
name-id start-unix stop-unix prop-id)
|
||||||
(emacsql db [:insert-or-ignore-into dates [date]
|
(emacsql db [:insert-or-ignore-into dates [date]
|
||||||
:values [$s1]] date-unix)
|
:values [$s1]] date-unix)
|
||||||
(setq date-id
|
(setq date-id
|
||||||
|
@ -272,9 +265,9 @@ s-expressions in a text column."
|
||||||
|
|
||||||
** Provide
|
** Provide
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(provide 'chronometrist-sqlite3)
|
(provide 'chronometrist-sqlite)
|
||||||
|
|
||||||
;;; chronometrist-sqlite3.el ends here
|
;;; chronometrist-sqlite.el ends here
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
* Local variables :noexport:
|
* Local variables :noexport:
|
||||||
|
|
|
@ -755,6 +755,12 @@ Value must be a keyword corresponding to a key in
|
||||||
(cl-second (alist-get chronometrist-active-backend chronometrist-backends-alist)))
|
(cl-second (alist-get chronometrist-active-backend chronometrist-backends-alist)))
|
||||||
;; active-backend:1 ends here
|
;; active-backend:1 ends here
|
||||||
|
|
||||||
|
;; [[file:chronometrist.org::*get-backend][get-backend:1]]
|
||||||
|
(defun chronometrist-get-backend (keyword)
|
||||||
|
"Return the backend object associated with KEYWORD."
|
||||||
|
(cl-second (alist-get keyword chronometrist-backends-alist)))
|
||||||
|
;; get-backend:1 ends here
|
||||||
|
|
||||||
;; [[file:chronometrist.org::*switch-backend][switch-backend:1]]
|
;; [[file:chronometrist.org::*switch-backend][switch-backend:1]]
|
||||||
(defun chronometrist-switch-backend ()
|
(defun chronometrist-switch-backend ()
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -788,8 +794,7 @@ be replaced."
|
||||||
;; register-backend:1 ends here
|
;; register-backend:1 ends here
|
||||||
|
|
||||||
;; [[file:chronometrist.org::*read-backend-name][read-backend-name:1]]
|
;; [[file:chronometrist.org::*read-backend-name][read-backend-name:1]]
|
||||||
(defun chronometrist-read-backend-name (prompt backend-alist
|
(defun chronometrist-read-backend-name (prompt backend-alist &optional predicate return-keyword)
|
||||||
&optional predicate return-keyword)
|
|
||||||
"Prompt user for a Chronometrist backend name.
|
"Prompt user for a Chronometrist backend name.
|
||||||
BACKEND-ALIST should be an alist similar to `chronometrist-backends-alist'.
|
BACKEND-ALIST should be an alist similar to `chronometrist-backends-alist'.
|
||||||
|
|
||||||
|
@ -1876,50 +1881,63 @@ Return value is either a list in the form
|
||||||
;; remove-prefix:1 ends here
|
;; remove-prefix:1 ends here
|
||||||
|
|
||||||
;; [[file:chronometrist.org::*migrate][migrate:1]]
|
;; [[file:chronometrist.org::*migrate][migrate:1]]
|
||||||
(defun chronometrist-migrate ()
|
(defun chronometrist-migrate (&optional input-backend-keyword input-file
|
||||||
"Convert from one Chronometrist backend to another."
|
output-backend-keyword output-file
|
||||||
|
&rest load-files)
|
||||||
|
"Convert from one Chronometrist backend to another.
|
||||||
|
|
||||||
|
INPUT-BACKEND-KEYWORD and OUTPUT-BACKEND-KEYWORD must be keywords
|
||||||
|
corresponding to entries in `chronometrist-backends-alist'.
|
||||||
|
|
||||||
|
INPUT-FILE and OUTPUT-FILE must be file names. INPUT-FILE must
|
||||||
|
already exist.
|
||||||
|
|
||||||
|
LOAD-FILES must be paths to Elisp files. These files are `load'ed
|
||||||
|
before conversion. They may be used to point to Chronometrist
|
||||||
|
source files to be used."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((input-backend
|
(let* ((input-backend-keyword (or input-backend-keyword
|
||||||
(chronometrist-read-backend-name "Backend to convert: "
|
(chronometrist-read-backend-name "Backend to convert: " chronometrist-backends-alist nil t)))
|
||||||
chronometrist-backends-alist))
|
(input-backend (chronometrist-get-backend input-backend-keyword))
|
||||||
(input-file-suggestion (chronometrist-backend-file input-backend))
|
(suggested-input-file (chronometrist-backend-file input-backend))
|
||||||
(input-file (read-file-name "File to convert: " nil
|
(input-file (or input-file
|
||||||
input-file-suggestion t
|
(read-file-name "File to convert: "
|
||||||
input-file-suggestion))
|
nil suggested-input-file t suggested-input-file)))
|
||||||
(output-backend (chronometrist-read-backend-name
|
(output-backend-keyword (or output-backend-keyword
|
||||||
"Backend to write: "
|
(chronometrist-read-backend-name "Backend to write: "
|
||||||
chronometrist-backends-alist
|
chronometrist-backends-alist
|
||||||
(lambda (keyword)
|
(lambda (keyword)
|
||||||
(not (equal (cl-second
|
(not (equal (cl-second
|
||||||
(alist-get keyword chronometrist-backends-alist))
|
(alist-get keyword chronometrist-backends-alist))
|
||||||
input-backend)))))
|
input-backend)))
|
||||||
(output-file-suggestion (chronometrist-backend-file output-backend))
|
t)))
|
||||||
(output-file (read-file-name "File to write: " nil nil nil
|
(output-backend (chronometrist-get-backend output-backend-keyword))
|
||||||
output-file-suggestion))
|
(suggested-output-file (chronometrist-backend-file output-backend))
|
||||||
(input-backend-name (chronometrist-remove-prefix
|
(output-file (or output-file
|
||||||
(symbol-name
|
(read-file-name "File to write: " nil nil nil suggested-output-file)))
|
||||||
(eieio-object-class-name input-backend))))
|
(input-backend-name (chronometrist-remove-prefix (symbol-name (eieio-object-class-name input-backend))))
|
||||||
(output-backend-name (chronometrist-remove-prefix
|
(output-backend-name (chronometrist-remove-prefix (symbol-name (eieio-object-class-name output-backend))))
|
||||||
(symbol-name
|
(confirm (yes-or-no-p (format "Convert %s (%s) to %s (%s)? "
|
||||||
(eieio-object-class-name output-backend))))
|
input-file input-backend-name
|
||||||
(confirm (yes-or-no-p
|
output-file output-backend-name)))
|
||||||
(format "Convert %s (%s) to %s (%s)? "
|
(confirm-overwrite (if (and confirm
|
||||||
input-file
|
(file-exists-p output-file)
|
||||||
input-backend-name
|
(not (chronometrist-file-empty-p output-file)))
|
||||||
output-file
|
(yes-or-no-p
|
||||||
output-backend-name)))
|
(format "Overwrite existing non-empty file %s ?" output-file))
|
||||||
(confirm-overwrite
|
t)))
|
||||||
(if (and confirm
|
|
||||||
(file-exists-p output-file)
|
|
||||||
(not (chronometrist-file-empty-p output-file)))
|
|
||||||
(yes-or-no-p
|
|
||||||
(format "Overwrite existing non-empty file %s ?"
|
|
||||||
output-file))
|
|
||||||
t)))
|
|
||||||
(if (and confirm confirm-overwrite)
|
(if (and confirm confirm-overwrite)
|
||||||
(chronometrist-to-file (chronometrist-backend-hash-table input-backend)
|
(start-process
|
||||||
output-backend
|
"chronometrist-migrate" (generate-new-buffer-name "chronometrist-migrate")
|
||||||
output-file)
|
"emacs" "--batch"
|
||||||
|
"--eval=(package-initialize)"
|
||||||
|
"--eval=(cl-loop for (pkg . desc) in package-alist
|
||||||
|
when (string-match-p \"^chronometrist\" (symbol-name pkg))
|
||||||
|
do (require pkg))"
|
||||||
|
(format "--eval=(cl-loop for file in (quote %S) do (load file))" load-files)
|
||||||
|
;; the hash table slot may be empty, so we generate the hash table from scratch
|
||||||
|
(format "--eval=(chronometrist-to-file (chronometrist-to-hash-table (chronometrist-get-backend %s)) (chronometrist-get-backend %s) %S)"
|
||||||
|
input-backend-keyword output-backend-keyword output-file))
|
||||||
(message "Conversion aborted."))))
|
(message "Conversion aborted."))))
|
||||||
;; migrate:1 ends here
|
;; migrate:1 ends here
|
||||||
|
|
||||||
|
|
|
@ -1410,6 +1410,13 @@ Value must be a keyword corresponding to a key in
|
||||||
(cl-second (alist-get chronometrist-active-backend chronometrist-backends-alist)))
|
(cl-second (alist-get chronometrist-active-backend chronometrist-backends-alist)))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
**** get-backend :reader:
|
||||||
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(defun chronometrist-get-backend (keyword)
|
||||||
|
"Return the backend object associated with KEYWORD."
|
||||||
|
(cl-second (alist-get keyword chronometrist-backends-alist)))
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
**** switch-backend :command:
|
**** switch-backend :command:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun chronometrist-switch-backend ()
|
(defun chronometrist-switch-backend ()
|
||||||
|
@ -1446,8 +1453,7 @@ be replaced."
|
||||||
|
|
||||||
**** read-backend-name :procedure:
|
**** read-backend-name :procedure:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun chronometrist-read-backend-name (prompt backend-alist
|
(defun chronometrist-read-backend-name (prompt backend-alist &optional predicate return-keyword)
|
||||||
&optional predicate return-keyword)
|
|
||||||
"Prompt user for a Chronometrist backend name.
|
"Prompt user for a Chronometrist backend name.
|
||||||
BACKEND-ALIST should be an alist similar to `chronometrist-backends-alist'.
|
BACKEND-ALIST should be an alist similar to `chronometrist-backends-alist'.
|
||||||
|
|
||||||
|
@ -2903,50 +2909,63 @@ We apply the same hack as in the [[hack-note-plist-group-insert][insert]] method
|
||||||
|
|
||||||
*** migrate :command:
|
*** migrate :command:
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defun chronometrist-migrate ()
|
(defun chronometrist-migrate (&optional input-backend-keyword input-file
|
||||||
"Convert from one Chronometrist backend to another."
|
output-backend-keyword output-file
|
||||||
|
&rest load-files)
|
||||||
|
"Convert from one Chronometrist backend to another.
|
||||||
|
|
||||||
|
INPUT-BACKEND-KEYWORD and OUTPUT-BACKEND-KEYWORD must be keywords
|
||||||
|
corresponding to entries in `chronometrist-backends-alist'.
|
||||||
|
|
||||||
|
INPUT-FILE and OUTPUT-FILE must be file names. INPUT-FILE must
|
||||||
|
already exist.
|
||||||
|
|
||||||
|
LOAD-FILES must be paths to Elisp files. These files are `load'ed
|
||||||
|
before conversion. They may be used to point to Chronometrist
|
||||||
|
source files to be used."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((input-backend
|
(let* ((input-backend-keyword (or input-backend-keyword
|
||||||
(chronometrist-read-backend-name "Backend to convert: "
|
(chronometrist-read-backend-name "Backend to convert: " chronometrist-backends-alist nil t)))
|
||||||
chronometrist-backends-alist))
|
(input-backend (chronometrist-get-backend input-backend-keyword))
|
||||||
(input-file-suggestion (chronometrist-backend-file input-backend))
|
(suggested-input-file (chronometrist-backend-file input-backend))
|
||||||
(input-file (read-file-name "File to convert: " nil
|
(input-file (or input-file
|
||||||
input-file-suggestion t
|
(read-file-name "File to convert: "
|
||||||
input-file-suggestion))
|
nil suggested-input-file t suggested-input-file)))
|
||||||
(output-backend (chronometrist-read-backend-name
|
(output-backend-keyword (or output-backend-keyword
|
||||||
"Backend to write: "
|
(chronometrist-read-backend-name "Backend to write: "
|
||||||
chronometrist-backends-alist
|
chronometrist-backends-alist
|
||||||
(lambda (keyword)
|
(lambda (keyword)
|
||||||
(not (equal (cl-second
|
(not (equal (cl-second
|
||||||
(alist-get keyword chronometrist-backends-alist))
|
(alist-get keyword chronometrist-backends-alist))
|
||||||
input-backend)))))
|
input-backend)))
|
||||||
(output-file-suggestion (chronometrist-backend-file output-backend))
|
t)))
|
||||||
(output-file (read-file-name "File to write: " nil nil nil
|
(output-backend (chronometrist-get-backend output-backend-keyword))
|
||||||
output-file-suggestion))
|
(suggested-output-file (chronometrist-backend-file output-backend))
|
||||||
(input-backend-name (chronometrist-remove-prefix
|
(output-file (or output-file
|
||||||
(symbol-name
|
(read-file-name "File to write: " nil nil nil suggested-output-file)))
|
||||||
(eieio-object-class-name input-backend))))
|
(input-backend-name (chronometrist-remove-prefix (symbol-name (eieio-object-class-name input-backend))))
|
||||||
(output-backend-name (chronometrist-remove-prefix
|
(output-backend-name (chronometrist-remove-prefix (symbol-name (eieio-object-class-name output-backend))))
|
||||||
(symbol-name
|
(confirm (yes-or-no-p (format "Convert %s (%s) to %s (%s)? "
|
||||||
(eieio-object-class-name output-backend))))
|
input-file input-backend-name
|
||||||
(confirm (yes-or-no-p
|
output-file output-backend-name)))
|
||||||
(format "Convert %s (%s) to %s (%s)? "
|
(confirm-overwrite (if (and confirm
|
||||||
input-file
|
(file-exists-p output-file)
|
||||||
input-backend-name
|
(not (chronometrist-file-empty-p output-file)))
|
||||||
output-file
|
(yes-or-no-p
|
||||||
output-backend-name)))
|
(format "Overwrite existing non-empty file %s ?" output-file))
|
||||||
(confirm-overwrite
|
t)))
|
||||||
(if (and confirm
|
|
||||||
(file-exists-p output-file)
|
|
||||||
(not (chronometrist-file-empty-p output-file)))
|
|
||||||
(yes-or-no-p
|
|
||||||
(format "Overwrite existing non-empty file %s ?"
|
|
||||||
output-file))
|
|
||||||
t)))
|
|
||||||
(if (and confirm confirm-overwrite)
|
(if (and confirm confirm-overwrite)
|
||||||
(chronometrist-to-file (chronometrist-backend-hash-table input-backend)
|
(start-process
|
||||||
output-backend
|
"chronometrist-migrate" (generate-new-buffer-name "chronometrist-migrate")
|
||||||
output-file)
|
"emacs" "--batch"
|
||||||
|
"--eval=(package-initialize)"
|
||||||
|
"--eval=(cl-loop for (pkg . desc) in package-alist
|
||||||
|
when (string-match-p \"^chronometrist\" (symbol-name pkg))
|
||||||
|
do (require pkg))"
|
||||||
|
(format "--eval=(cl-loop for file in (quote %S) do (load file))" load-files)
|
||||||
|
;; the hash table slot may be empty, so we generate the hash table from scratch
|
||||||
|
(format "--eval=(chronometrist-to-file (chronometrist-to-hash-table (chronometrist-get-backend %s)) (chronometrist-get-backend %s) %S)"
|
||||||
|
input-backend-keyword output-backend-keyword output-file))
|
||||||
(message "Conversion aborted."))))
|
(message "Conversion aborted."))))
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
|
Reference in New Issue