Skip to content

Commit

Permalink
Support space and backslash characters in runfile filenames.
Browse files Browse the repository at this point in the history
Bazel supports them with bazelbuild/bazel#23331.

Step 2: support them for manifest-based runfiles.
  • Loading branch information
phst committed Oct 8, 2024
1 parent a944e73 commit 9a2070d
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 9 deletions.
13 changes: 11 additions & 2 deletions elisp/runfiles/runfiles-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,17 @@
"phst_rules_elisp/elisp/runfiles/test-manifest"))
(runfiles (elisp/runfiles/make :manifest manifest
:directory "/invalid/")))
(should (equal (elisp/runfiles/rlocation "testäα𝐴🐈'.txt" runfiles)
"/:/runfiles/testäα𝐴🐈'.txt"))))
(pcase-dolist (`(,source ,target)
'(("testäα𝐴🐈'.txt"
"/:/runfiles/testäα𝐴🐈'.txt")
("target-with-space"
"/:/runfiles/with space\\and backslash")
("target-with-newline"
"/:/runfiles/with\nnewline\\and backslash")
("source with space,\nnewline,\\and backslash"
"/:/runfiles/with space,\nnewline,\\and backslash")))
(ert-info (source :prefix "Source: ")
(should (equal (elisp/runfiles/rlocation source runfiles) target))))))

(ert-deftest elisp/runfiles/make/empty-file ()
(let* ((manifest (elisp/runfiles/rlocation
Expand Down
32 changes: 25 additions & 7 deletions elisp/runfiles/runfiles.el
Original file line number Diff line number Diff line change
Expand Up @@ -501,13 +501,31 @@ Return an object of type ‘elisp/runfiles/runfiles--manifest’."
;; Perform the same parsing as
;; https://github.com/bazelbuild/bazel/blob/6.4.0/tools/cpp/runfiles/runfiles_src.cc#L241.
(while (not (eobp))
(pcase (buffer-substring-no-properties (point) (line-end-position))
((rx bos (let key (+ (not (any ?\n ?\s))))
?\s (let value (* nonl)) eos)
;; Runfiles are always local, so quote them unconditionally.
(puthash key (if (string-empty-p value) :empty (concat "/:" value))
manifest))
(other (signal 'elisp/runfiles/syntax-error (list filename other))))
(let ((line (buffer-substring-no-properties
(point) (line-end-position)))
(escaped (eql (following-char) ?\s)))
(cl-flet* ((syntax-error ()
(signal 'elisp/runfiles/syntax-error
(list filename line)))
(unescape (string &rest other)
(let ((pairs `(,@other ("\\n" . "\n") ("\\b" . "\\"))))
(replace-regexp-in-string
(rx ?\\ (? anychar))
(lambda (seq)
(or (cdr (assoc seq pairs)) (syntax-error)))
string :fixedcase :literal))))
(pcase (if escaped (substring-no-properties line 1) line)
((rx bos (let key (+ (not (any ?\n ?\s))))
?\s (let value (* nonl)) eos)
(when escaped
(cl-callf unescape key '("\\s" . " "))
(cl-callf unescape value))
(puthash key
;; Runfiles are always local, so quote them
;; unconditionally.
(if (string-empty-p value) :empty (concat "/:" value))
manifest))
(_ (syntax-error)))))
(forward-line)))
(elisp/runfiles/manifest--make filename manifest)))

Expand Down
3 changes: 3 additions & 0 deletions elisp/runfiles/test-manifest
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
__init__.py
foo/bar runfiles/foo/bar
testäα𝐴🐈'.txt /runfiles/testäα𝐴🐈'.txt
target-with-space /runfiles/with space\and backslash
target-with-newline /runfiles/with\nnewline\band backslash
source\swith\sspace,\nnewline,\band\sbackslash /runfiles/with space,\nnewline,\band backslash

0 comments on commit 9a2070d

Please sign in to comment.