branch: externals/vc-jj commit 6b7aea27312df164c44f191514267aea86c1e20d Author: Rudi Schlatte <r...@constantly.at> Commit: Rudi Schlatte <r...@constantly.at>
Avoid modifying fileset expressions in vc-jj-do-command vc-do-command normalizes its filename arguments, but we already converted them to jujutsu fileset expressions; pass them at the end of the flags argument instead. Fixes #38 --- vc-jj-tests.el | 47 ++++++++++++++++++++++++++++++++++------------- vc-jj.el | 51 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 66 insertions(+), 32 deletions(-) diff --git a/vc-jj-tests.el b/vc-jj-tests.el index e4f1145f84..1cabdca062 100644 --- a/vc-jj-tests.el +++ b/vc-jj-tests.el @@ -149,19 +149,25 @@ is needed." (ert-deftest vc-jj-ignore () (vc-jj-test-with-repo repo - (write-region "xxx" nil "root-ignored.txt") - (make-directory "subdir") - (write-region "xxx" nil "subdir/subdir-ignored.txt") - (should (eq (vc-jj-state "root-ignored.txt") 'added)) - (should (eq (vc-jj-state "subdir/subdir-ignored.txt") 'added)) - (vc-jj-ignore "root-ignored.txt") - (vc-jj-ignore "subdir/subdir-ignored.txt") - (should (eq (vc-jj-state "root-ignored.txt") 'ignored)) - (should (eq (vc-jj-state "subdir/subdir-ignored.txt") 'ignored)) - (vc-jj-ignore "root-ignored.txt" nil t) - (vc-jj-ignore "subdir/subdir-ignored.txt" nil t) - (should (eq (vc-jj-state "root-ignored.txt") 'added)) - (should (eq (vc-jj-state "subdir/subdir-ignored.txt") 'added)))) + (let (gitignore-buffer) + (unwind-protect + (progn + (setq gitignore-buffer (find-file ".gitignore")) + (write-region "xxx" nil "root-ignored.txt") + (make-directory "subdir") + (write-region "xxx" nil "subdir/subdir-ignored.txt") + (should (eq (vc-jj-state "root-ignored.txt") 'added)) + (should (eq (vc-jj-state "subdir/subdir-ignored.txt") 'added)) + (vc-jj-ignore "root-ignored.txt") + (vc-jj-ignore "subdir/subdir-ignored.txt") + (should (eq (vc-jj-state "root-ignored.txt") 'ignored)) + (should (eq (vc-jj-state "subdir/subdir-ignored.txt") 'ignored)) + (vc-jj-ignore "root-ignored.txt" nil t) + (vc-jj-ignore "subdir/subdir-ignored.txt" nil t) + (should (eq (vc-jj-state "root-ignored.txt") 'added)) + (should (eq (vc-jj-state "subdir/subdir-ignored.txt") 'added))) + (when (buffer-live-p gitignore-buffer) + (kill-buffer gitignore-buffer)))))) (ert-deftest vc-jj-list-files () (vc-jj-test-with-repo repo @@ -189,5 +195,20 @@ is needed." (should (equal (vc-jj-dir-status-files (expand-file-name "subdir/" repo) nil (lambda (x y) x)) '(("conflicted.txt" conflict))))))) +(ert-deftest vc-jj-funky-filename () + ;; https://codeberg.org/emacs-jj-vc/vc-jj.el/issues/38 + (vc-jj-test-with-repo repo + (write-region "Hello" nil "TEST=TEST.txt") + (write-region "Hello" nil "with'apostrophe.txt") + (write-region "Hello" nil "with\"quotation.txt") + (should (eq (vc-jj-state "TEST=TEST.txt") 'added)) + (should (eq (vc-jj-state "with'apostrophe.txt") 'added)) + (should (eq (vc-jj-state "with\"quotation.txt") 'added)) + (should (seq-set-equal-p + (vc-jj-dir-status-files repo nil (lambda (x y) x)) + '(("TEST=TEST.txt" added) + ("with'apostrophe.txt" added) + ("with\"quotation.txt" added)))))) + (provide 'vc-jj-tests) ;;; vc-jj-tests.el ends here diff --git a/vc-jj.el b/vc-jj.el index d778c6d05e..91f387fb16 100644 --- a/vc-jj.el +++ b/vc-jj.el @@ -95,6 +95,17 @@ If nil, use the value of `vc-diff-switches'. If t, use no switches." (string :tag "Argument String") (repeat :tag "Argument List" :value ("") string))) +(defun vc-jj--filename-to-fileset (filename &optional root) + "Convert FILENAME to a JJ fileset expression. +If ROOT is given, the result is relative to the repository root, +otherwise it is relative to the current directory." + (if root + (concat "root-file:\"" + (string-replace "\"" "\\\"" (file-relative-name filename root)) + "\"") + (concat "cwd-file:\"" + (string-replace "\"" "\\\"" (file-relative-name filename)) "\""))) + (defun vc-jj-command (buffer okstatus file-or-list &rest flags) "Execute `vc-jj-program', notifying the user and checking for errors. @@ -115,11 +126,17 @@ the command line before the filename(s). Return the return value of the command in the synchronous case, and the process object in the asynchronous case." - (apply #'vc-do-command (or buffer "*vc*") okstatus vc-jj-program - file-or-list - (if (stringp vc-jj-global-switches) - (cons vc-jj-global-switches flags) - (append vc-jj-global-switches flags)))) + (let* ((filesets (mapcar #'vc-jj--filename-to-fileset + (if (listp file-or-list) file-or-list (list file-or-list)))) + (global-switches (if (stringp vc-jj-global-switches) + (list vc-jj-global-switches) + vc-jj-global-switches))) + (apply #'vc-do-command (or buffer "*vc*") okstatus vc-jj-program + ;; Note that we pass NIL for FILE-OR-LIST to avoid + ;; vc-do-command mangling of filenames; we pass the fileset + ;; expressions in ARGS instead. + nil + (append global-switches flags filesets)))) ;;;###autoload (defun vc-jj-registered (file) ;;;###autoload "Return non-nil if FILE is registered with jj." @@ -128,17 +145,14 @@ process object in the asynchronous case." ;;;###autoload (progn ;;;###autoload (load "vc-jj" nil t) ;;;###autoload (vc-jj-registered file)))) - (defun vc-jj-registered (file) "Check whether FILE is registered with jj." - (when (executable-find vc-jj-program) - (unless (not (file-exists-p default-directory)) - (with-demoted-errors "Error: %S" - (when-let* ((default-directory (vc-jj-root file)) - (relative (file-relative-name file))) - (with-temp-buffer - (and (= 0 (vc-jj-command t 0 file "file" "list" "--")) - (not (= (point-min) (point-max)))))))))) + (and-let* ((vc-jj-program (executable-find vc-jj-program)) + (default-directory (vc-jj-root file))) + (with-temp-buffer + (and (= 0 (call-process vc-jj-program nil (list t nil) nil + "file" "list" "--" (vc-jj--filename-to-fileset file))) + (/= (point-min) (point-max)))))) (defun vc-jj-state (file) "JJ implementation of `vc-state' for FILE." @@ -331,8 +345,8 @@ self.immutable(), \"\\n\" (defun vc-jj-checkin (files comment &optional _rev) "Run \"jj commit\" with supplied FILES and COMMENT." (setq comment (replace-regexp-in-string "\\`Summary: " "" comment)) - (let ((args (append (vc-switches 'jj 'checkin) (list "--")))) - (apply #'vc-jj-command nil 0 files "commit" "-m" comment args))) + (let ((args (append (vc-switches 'jj 'checkin) (list "commit" "-m" comment)))) + (apply #'vc-jj-command nil 0 files args))) (defun vc-jj-find-revision (file rev buffer) "Read revision REV of FILE into BUFFER and return the buffer." @@ -344,13 +358,12 @@ self.immutable(), \"\\n\" If REV is not specified, revert the file as with `vc-jj-revert'." ;; TODO: check that this does the right thing: if REV is not ;; specified, should we revert or leave FILE unchanged? - (let ((args (append (and rev (list "--from" rev)) - (list "--")))) + (let ((args (append (and rev (list "--from" rev))))) (apply #'vc-jj-command nil 0 file "restore" args))) (defun vc-jj-revert (file &optional _contents-done) "Restore FILE to the state from its parent(s), via \"jj restore\"." - (vc-jj-command nil 0 file "restore" "--")) + (vc-jj-command nil 0 file "restore")) (defun vc-jj-print-log (files buffer &optional _shortlog start-revision limit) "Print commit log associated with FILES into specified BUFFER."