diff --git a/dash-docs.el b/dash-docs.el index 10f11ae..55750fe 100644 --- a/dash-docs.el +++ b/dash-docs.el @@ -104,7 +104,6 @@ the default except when using Emacs 27. For more information see https://github.com/magit/ghub/issues/81 and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34341.") - (defun dash-docs-docset-path (docset) "Return the full path of the directory for DOCSET." (let* ((base (dash-docs-docsets-path)) @@ -145,9 +144,10 @@ If there are errors, print them in `dash-docs-debugging-buffer'" (with-output-to-string (let ((error-file (when dash-docs-enable-debugging (make-temp-file "dash-docs-errors-file")))) - (call-process "sqlite3" nil (list standard-output error-file) nil - ;; args for sqlite3: - "-list" "-init" "''" db-path sql) + (apply + 'call-process "sqlite3" nil (list standard-output error-file) nil + ;; args for sqlite3: + (dash-docs-get-sqlite-args db-path sql)) ;; display errors, stolen from emacs' `shell-command` function (when (and error-file (file-exists-p error-file)) @@ -165,6 +165,43 @@ If there are errors, print them in `dash-docs-debugging-buffer'" (display-buffer (current-buffer)))) (delete-file error-file)))))) +(defun dash-docs-get-sqlite-args (db-path sql) + "Return SQLite args to run the SQL command in the db at DB-PATH. + +These args depend on the SQLite version. +" + ;; To avoid any initialization when SQLite runs the command, use the init + ;; option. For SQLite versions older than 3.34.0, you would use arguments + ;; "-init ''" to do so. As of that version, SQLite reports the error that file + ;; '' doesn't exist and you need to pass the null device instead. For those + ;; versions, you also have to provide argument "-batch" to avoid the output of + ;; status information. + (if (version< dash-docs-sqlite-version "3.34.0") + `("-list" "-init" "''" ,db-path ,sql) + `("-list" "-init" ,null-device "-batch" ,db-path ,sql))) + +(defun dash-docs-extract-sqlite-version (sqlite-version-output) + "Extract the SQLite version from SQLITE-VERSION-OUTPUT. +SQLITE-VERSION-OUTPUT is the output of a call to \"sqlite3 +--version\" as a list of strings. If this function cannot parse +that output, it returns \"0.0.0\", which serves as the (fake) +oldest version of SQLite." + (let ((oldest-sqlite-version "0.0.0")) + (if (>= (length sqlite-version-output) 1) + (let ((sqlite-version-string (car sqlite-version-output))) + (if (string-match + "^\\([[:digit:]]+[.][[:digit:]]+[.][[:digit:]]+\\) [[:digit:]]\\{4\\}-" + sqlite-version-string) + (match-string 1 sqlite-version-string) + oldest-sqlite-version)) + oldest-sqlite-version))) + +(defvar dash-docs-sqlite-version + (dash-docs-extract-sqlite-version (process-lines "sqlite3" "--version")) + "Version of available sqlite3 binary. +This version string is retrieved by executing \"sqlite3 +--version\" and parsing its output.") + (defun dash-docs-parse-sql-results (sql-result-string) "Parse SQL-RESULT-STRING splitting it by newline and '|' chars." (mapcar (lambda (x) (split-string x "|" t)) diff --git a/test/dash-docs-test.el b/test/dash-docs-test.el index f921b2f..c510d5d 100644 --- a/test/dash-docs-test.el +++ b/test/dash-docs-test.el @@ -166,4 +166,31 @@ (provide 'dash-docs-test) +;;;; dash-docs-get-sqlite-args + +(ert-deftest dash-docs-sqlite-args-with-old-version-is-backward-compatible() + (let ((dash-docs-sqlite-version "3.33.0")) + (let ((actual-result (dash-docs-get-sqlite-args "/path/to/db" "SELECT ..."))) + (should (equal '("-list" "-init" "''" "/path/to/db" "SELECT ...") actual-result))))) + +(ert-deftest dash-docs-sqlite-args-with-newer-version-uses-different-init() + (let ((dash-docs-sqlite-version "3.34.0") (null-device "/dev/null")) + (let ((actual-result (dash-docs-get-sqlite-args "/path/to/db" "SELECT ..."))) + (should (equal '("-list" "-init" "/dev/null" "-batch" "/path/to/db" "SELECT ...") actual-result))))) + +(ert-deftest dash-docs-sqlite-args-with-newer-version-uses-different-init-and-null-device() + ;; null-device "NUL" is used by Windows + (let ((dash-docs-sqlite-version "3.34.0") (null-device "NUL")) + (let ((actual-result (dash-docs-get-sqlite-args "/path/to/db" "SELECT ..."))) + (should (equal '("-list" "-init" "NUL" "-batch" "/path/to/db" "SELECT ...") actual-result))))) + +(ert-deftest dash-docs-extract-sqlite-version-using-valid-output() + (let ((dash-docs-sqlite-version "3.34.0")) + (let ((sqlite-version-output '("3.34.0 2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b"))) + (should (equal "3.34.0" (dash-docs-extract-sqlite-version sqlite-version-output)))))) + +(ert-deftest dash-docs-extract-sqlite-version-using-empty-output() + (let ((sqlite-version-output ())) + (should (equal "0.0.0" (dash-docs-extract-sqlite-version sqlite-version-output))))) + ;;; dash-docs-test ends here