Subject: bug#78542: [Security] hash locking needed for tree-sitter downloads

From: Juri Linkov <[email-masked]>
Date: Thu, 19 Jun 2025 20:54:08 +0300

> +            (if commit
> +                ;; Force blobless full clone to be able later
> +                ;; to checkout a commit (bug#78542).
> +                (let ((treesit--install-language-grammar-blobless t)
> +                      (treesit--install-language-grammar-full-clone t))
> +                  (treesit--git-clone-repo url revision workdir))
> +              (treesit--git-clone-repo url revision workdir)))

Since with this change it's possible to specify the commit,
let's also improve the format of the source list.
Currently adding a commit to the list requires
prefixing it with four nils:

  (treesit--install-language-grammar-1
   (locate-user-emacs-file "tree-sitter") 'json
   "https://github.com/tree-sitter/tree-sitter-json"
   nil nil nil nil "4d770d3")

The following patch introduces an alternative format
using keywords, e.g.:

  (treesit--install-language-grammar-1
   (locate-user-emacs-file "tree-sitter") 'json
   "https://github.com/tree-sitter/tree-sitter-json"
   :commit "4d770d3")

diff --git a/lisp/treesit.el b/lisp/treesit.el
index 353e991ec20..fedcb6ed1e9 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -4998,7 +4998,7 @@ treesit-language-source-alist
 
 The value should be an alist where each element has the form
 
-    (LANG . (URL REVISION SOURCE-DIR CC C++ COMMIT [KEYWORD VALUE]...))
+    (LANG . (URL REVISION SOURCE-DIR CC C++ COMMIT))
 
 Only LANG and URL are mandatory.  LANG is the language symbol.
 URL is the URL of the grammar's Git repository or a directory
@@ -5015,8 +5015,17 @@ treesit-language-source-alist
 CC and C++ are C and C++ compilers, defaulting to \"cc\" and
 \"c++\", respectively.
 
+Another way to specify optional data is to use keywords:
+
+    (LANG . (URL [KEYWORD VALUE]...))
+
 The currently supported keywords:
 
+`:revision' is the same as REVISION above.
+`:source-dir' is the same as SOURCE-DIR above.
+`:cc' is the same as CC above.
+`:c++' is the same as C++ above.
+`:commit' is the same as COMMIT above.
 `:copy-queries' when non-nil specifies whether to copy the files
 in the \"queries\" directory from the source directory to the
 installation directory.")
@@ -5203,7 +5212,7 @@ treesit--git-clone-repo
     (apply #'treesit--call-process-signal args)))
 
 (defun treesit--install-language-grammar-1
-    (out-dir lang url &optional revision source-dir cc c++ commit &rest args)
+    (out-dir lang url &rest args)
   "Compile and install a tree-sitter language grammar library.
 
 OUT-DIR is the directory to put the compiled library file.  If it
@@ -5211,8 +5220,7 @@ treesit--install-language-grammar-1
 configuration directory is used (and automatically created if it
 does not exist).
 
-For LANG, URL, REVISION, SOURCE-DIR, GRAMMAR-DIR, CC, C++, COMMIT, see
-`treesit-language-source-alist'.
+For ARGS, see `treesit-language-source-alist'.
 
 Return the git revision of the installed grammar.  The revision is
 generated by \"git describe\".  It only works when
@@ -5225,13 +5233,25 @@ treesit--install-language-grammar-1
          (workdir (if url-is-dir
                       maybe-repo-dir
                     (expand-file-name "repo")))
-         copy-queries version)
+         version
+         revision source-dir cc c++ commit copy-queries)
 
     ;; Process the keyword args.
     (while (keywordp (car args))
       (pcase (pop args)
-        (:copy-queries (setq copy-queries (pop args)))
-        (_ (pop args))))
+        (:revision     (setq revision     (pop args)))
+        (:source-dir   (setq source-dir   (pop args)))
+        (:cc           (setq cc           (pop args)))
+        (:c++          (setq c++          (pop args)))
+        (:commit       (setq commit       (pop args)))
+        (:copy-queries (setq copy-queries (pop args)))))
+
+    ;; Old positional convention for backward-compatibility:
+    (unless revision   (setq revision   (nth 0 args)))
+    (unless source-dir (setq source-dir (nth 1 args)))
+    (unless cc         (setq cc         (nth 2 args)))
+    (unless c++        (setq c++        (nth 3 args)))
+    (unless commit     (setq commit     (nth 4 args)))
 
     (unwind-protect
         (with-temp-buffer