]> git.eshelyaron.com Git - emacs.git/commitdiff
Support a local repo as URL in 'treesit-language-source-alist'
authorKonstantin Kharlamov <Hi-Angel@yandex.ru>
Fri, 19 Jan 2024 07:33:47 +0000 (10:33 +0300)
committerEshel Yaron <me@eshelyaron.com>
Wed, 31 Jan 2024 20:09:33 +0000 (21:09 +0100)
Sometimes people may need to bisect to find specific revision
in a grammar library's repo.  In this case they'd want to point
the URL to the local repo to avoid cloning it on every rebuild.
So add support for a directory instead of URL in
'treesit-language-source-alist'.
* lisp/treesit.el (treesit--install-language-grammar-1): Test
if URL is a local directory.  Then if it is, avoid cloning the
repo and removing the path on success.
(treesit--git-clone-repo): Factor out the code for cloning to
a separate function.
(treesit--git-checkout-branch): A helper to checkout the
revision for cases where we didn't clone the repo but want it
to point the revision.  (Bug#68579)

(cherry picked from commit 54c6588952b469df8d7983b6735461f542cd806e)

etc/NEWS
lisp/treesit.el

index 8b7d445b39b171fd6b662427e0dd87cec9a64ec4..34e38129c7303c5ee15b0a48afd03fcfc168de64 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2009,6 +2009,14 @@ The 'test' parameter is omitted if it is 'eql' (the default), as is
 'data' if empty.  'rehash-size', 'rehash-threshold' and 'size' are
 always omitted, and ignored if present when the object is read back in.
 
++++
+** 'treesit-install-language-grammar' can handle local directory instead of URL.
+It is now possible to pass a directory of a local repository as URL
+inside 'treesit-language-source-alist', so that calling
+'treesit-install-language-grammar' would avoid cloning the repository.
+It may be useful, for example, for the purposes of bisecting a
+treesitter grammar.
+
 \f
 * Changes in Emacs 30.1 on Non-Free Operating Systems
 
index 89f688b61c121ffeb01f78ef7436e89843c22874..d1e0beaaac9d1c03b39a3a0dd4779af6d08e027d 100644 (file)
@@ -3417,7 +3417,8 @@ The value should be an alist where each element has the form
     (LANG . (URL REVISION SOURCE-DIR CC C++))
 
 Only LANG and URL are mandatory.  LANG is the language symbol.
-URL is the Git repository URL for the grammar.
+URL is the URL of the grammar's Git repository or a directory
+where the repository has been cloned.
 
 REVISION is the Git tag or branch of the desired version,
 defaulting to the latest default branch.
@@ -3551,6 +3552,26 @@ content as signal data, and erase buffer afterwards."
                                  (buffer-string)))
     (erase-buffer)))
 
+(defun treesit--git-checkout-branch (repo-dir revision)
+  "Checkout REVISION in a repo located in REPO-DIR."
+  (treesit--call-process-signal
+   "git" nil t nil "-C" repo-dir "checkout" revision))
+
+(defun treesit--git-clone-repo (url revision workdir)
+  "Clone repo pointed by URL at commit REVISION to WORKDIR.
+
+REVISION may be nil, in which case the cloned repo will be at its
+default branch."
+  (message "Cloning repository")
+  ;; git clone xxx --depth 1 --quiet [-b yyy] workdir
+  (if revision
+      (treesit--call-process-signal
+       "git" nil t nil "clone" url "--depth" "1" "--quiet"
+       "-b" revision workdir)
+    (treesit--call-process-signal
+     "git" nil t nil "clone" url "--depth" "1" "--quiet"
+     workdir)))
+
 (defun treesit--install-language-grammar-1
     (out-dir lang url &optional revision source-dir cc c++)
   "Install and compile a tree-sitter language grammar library.
@@ -3564,8 +3585,12 @@ For LANG, URL, REVISION, SOURCE-DIR, GRAMMAR-DIR, CC, C++, see
 `treesit-language-source-alist'.  If anything goes wrong, this
 function signals an error."
   (let* ((lang (symbol-name lang))
+         (maybe-repo-dir (expand-file-name url))
+         (url-is-dir (file-accessible-directory-p maybe-repo-dir))
          (default-directory (make-temp-file "treesit-workdir" t))
-         (workdir (expand-file-name "repo"))
+         (workdir (if url-is-dir
+                      maybe-repo-dir
+                    (expand-file-name "repo")))
          (source-dir (expand-file-name (or source-dir "src") workdir))
          (cc (or cc (seq-find #'executable-find '("cc" "gcc" "c99"))
                  ;; If no C compiler found, just use cc and let
@@ -3580,15 +3605,10 @@ function signals an error."
          (lib-name (concat "libtree-sitter-" lang soext)))
     (unwind-protect
         (with-temp-buffer
-          (message "Cloning repository")
-          ;; git clone xxx --depth 1 --quiet [-b yyy] workdir
-          (if revision
-              (treesit--call-process-signal
-               "git" nil t nil "clone" url "--depth" "1" "--quiet"
-               "-b" revision workdir)
-            (treesit--call-process-signal
-             "git" nil t nil "clone" url "--depth" "1" "--quiet"
-             workdir))
+          (if url-is-dir
+              (when revision
+                (treesit--git-checkout-branch workdir revision))
+            (treesit--git-clone-repo url revision workdir))
           ;; We need to go into the source directory because some
           ;; header files use relative path (#include "../xxx").
           ;; cd "${sourcedir}"
@@ -3635,7 +3655,9 @@ function signals an error."
             ;; Ignore errors, in case the old version is still used.
             (ignore-errors (delete-file old-fname)))
           (message "Library installed to %s/%s" out-dir lib-name))
-      (when (file-exists-p workdir)
+      ;; Remove workdir if it's not a repo owned by user and we
+      ;; managed to create it in the first place.
+      (when (and (not url-is-dir) (file-exists-p workdir))
         (delete-directory workdir t)))))
 
 ;;; Etc