Skip to content

Commit

Permalink
[Fix #1044] Prefer call-process to shell-command-to-string (#1045)
Browse files Browse the repository at this point in the history
This change makes it so that a direct `call-process` invocation is used
when it is possible to determine what binary should be used for the
command. This avoids the cost of shell startup time that is incurred
when `shell-command-to-string` is invoked instead.
  • Loading branch information
colonelpanic8 authored and bbatsov committed Sep 26, 2016
1 parent 78ee7e3 commit ee5ce8d
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 6 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/elpa
/.elpa
/.cask
*.elc
*~
[#]*[#]
/TAGS
/TAGS
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@
* [#576](https://github.com/bbatsov/projectile/issues/576): `projectile-replace` stomps regular expressions.
* [#957](https://github.com/bbatsov/projectile/pull/957): When opening a specified file from the terminal, do not error inside of `projectile-cache-current-file`.
* [#984](https://github.com/bbatsov/projectile/pull/984): Error when a project is a symlink that changes target.

* [#1013](https://github.com/bbatsov/projectile/issues/1013): `projectile-project-buffer-p` may return incorrect result on Windows.
* [#1044](https://github.com/bbatsov/projectile/issues/1044): Replace `shell-command-to-string` invocations with `call-process` invocations where possible to avoid shell startup cost.

## 0.13.0 (2015-10-21)

Expand Down
3 changes: 2 additions & 1 deletion Cask
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
(development
(depends-on "noflet")
(depends-on "helm")
(depends-on "ag"))
(depends-on "ag")
(depends-on "el-mock"))
29 changes: 25 additions & 4 deletions projectile.el
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@
;;; Code:

(require 'cl-lib)
(require 'thingatpt)
(require 'ibuffer)
(require 'ibuf-ext)
(require 'compile)
(require 'eshell)
(require 'grep)
(require 'ibuf-ext)
(require 'ibuffer)
(require 'thingatpt)

(eval-when-compile
(defvar ag-ignore-list)
Expand Down Expand Up @@ -1075,9 +1076,29 @@ they are excluded from the results of this function."
(when cmd
(projectile-files-via-ext-command cmd))))

(defun projectile-call-process-to-string (program &rest args)
"Invoke the executable PROGRAM with ARGS and return the output as a string."
(with-temp-buffer
(apply 'call-process program nil (current-buffer) nil args)
(buffer-string)))

(defun projectile-shell-command-to-string (command)
"Try to run COMMAND without actually using a shell and return the output.
The function `eshell-search-path' will be used to search the PATH
environment variable for an appropriate executable using the text
occuring before the first space. If no executable is found,
fallback to `shell-command-to-string'"
(cl-destructuring-bind
(the-command . args) (split-string command " ")
(let ((binary-path (eshell-search-path the-command)))
(if binary-path
(apply 'projectile-call-process-to-string binary-path args)
(shell-command-to-string command)))))

(defun projectile-files-via-ext-command (command)
"Get a list of relative file names in the project root by executing COMMAND."
(split-string (shell-command-to-string command) "\0" t))
(split-string (projectile-shell-command-to-string command) "\0" t))

(defun projectile-index-directory (directory patterns progress-reporter)
"Index DIRECTORY taking into account PATTERNS.
Expand Down
21 changes: 21 additions & 0 deletions test/projectile-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,27 @@
(should (equal (list (expand-file-name "vendor/client-submodule/" project))
(projectile-get-all-sub-projects project)))))))

(ert-deftest projectile-test-projectile-shell-command-to-string-fallback ()
(let ((command "command arg1 arg2")
(command-path "/path/to/command")
shell-command-args call-process-args)
(noflet ((shell-command-to-string (&rest args)
(setq shell-command-args args))
(call-process (&rest args)
(setq call-process-args args)))
(noflet ((eshell-search-path (_command) nil))
(projectile-shell-command-to-string command)
(should (equal shell-command-args (list command)))
(should (equal call-process-args nil)))
(setq shell-command-args nil
call-process-args nil)
(noflet ((eshell-search-path (_command-name) command-path))
(projectile-shell-command-to-string command)
(should (equal shell-command-args nil))
(should (equal (car call-process-args) command-path))
(should (equal (-slice call-process-args 4)
(cdr (split-string command " "))))))))

;; Local Variables:
;; indent-tabs-mode: nil
;; End:

0 comments on commit ee5ce8d

Please sign in to comment.