互联网上很少涉及这个问题中涉及的所有三个功能的例子,即set-process-sentinel
; set-process-filter
;和start-process
。
我尝试了一些不同的方法来微调流程,以强制流程编号1(push
)在流程编号2开始之前完成(push
) 。在我的所有尝试中,第二个进程总是在我输入进程号1的密码之前运行并完成。进程号2的密码存储在osxkeychain
中。
我尝试的第一种方法是Magit,包括同步和异步过程。我尝试的第二种方法是使用函数while . . .
来搜索包含所述列表的缓冲区中的遥控器列表。第三次尝试列在下面 - 它使用在函数开始时创建的遥控器列表,然后使用Git将列表下的mapcar
下移到push
。
关于如何更好地控制第1号进程(push
)以便在第2号进程(push
)开始之前成功完成的任何想法都将不胜感激。
第二个流程的开始和结束并不是世界末日,但这是一个学习如何控制Emacs流程的问题 - 而不是控制我的流程。
编辑(2014年4月23日):添加了文档字符串。修改后的缓冲区*REMOTES*
的处理 - 即kill-local-variable 'git-remote-list
和erase-buffer
现在可以使用with-current-buffer ...
(defvar git-remote-list nil
"List of remote locations -- e.g., lawlist_remote or github_remote.")
(make-variable-buffer-local 'git-remote-list)
(defvar git-commit-message (format "Committed -- %s" (current-time-string))
"The predetermined Git commit message.")
(make-variable-buffer-local 'git-commit-message)
(defun my-process-filter (proc string)
(when (string-match "password" string)
(process-send-string
proc
(concat (read-passwd "Password: ") "\n"))))
(defun my-process-sentinel (proc string)
(when (= 0 (process-exit-status proc))
(message "Process `%s` has finished." proc)))
(defun stage-commit-push-all ()
"This function does the following:
* Save the current working buffer if it has been modified.
* Gather a list of all remotes associated with working directory Git project.
* Stage all -- `/usr/local/git/bin/git add .`
* Commit all -- `/usr/local/git/bin/git commit -m [git-commit-message]`
* Push to all remotes: `/usr/local/git/bin/git push -v [remote] [current-branch]`
Obtaining the current branch presently requires installation of Magit."
(interactive)
(when (buffer-modified-p)
(save-buffer))
(when (get-buffer "*REMOTES*")
(with-current-buffer (get-buffer "*REMOTES*")
(kill-local-variable 'git-remote-list)
(erase-buffer)))
(set-process-sentinel
(start-process
"list-remotes"
"*REMOTES*"
"/usr/local/git/bin/git"
"remote"
"-v")
(lambda (p e) (when (= 0 (process-exit-status p))
(let* (
beg
end
git-remote-name)
(with-current-buffer (get-buffer "*REMOTES*")
(goto-char (point-max))
(while (re-search-backward "\(push\)" nil t)
(beginning-of-line 1)
(setq beg (point))
(re-search-forward "\t" nil t)
(setq end (- (point) 1))
(setq git-remote-name (buffer-substring-no-properties beg end))
(setq git-remote-list
(append (cons git-remote-name git-remote-list)))) ))
(set-process-sentinel
(start-process
"stage-all"
"*OUTPUT*"
"/usr/local/git/bin/git"
"add"
".")
(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process
"commit-all"
"*OUTPUT*"
"/usr/local/git/bin/git"
"commit"
"-m"
git-commit-message)
(lambda (p e) (when (= 0 (process-exit-status p))
(mapcar (lambda (x)
(let ((proc
(start-process
"push-process"
"*OUTPUT*"
"/usr/local/git/bin/git"
"push"
"-v"
(format "%s" x)
(magit-get-current-branch))))
(set-process-filter proc 'my-process-filter)
(set-process-sentinel proc 'my-process-sentinel) ))
(with-current-buffer (get-buffer "*REMOTES*") git-remote-list)
)))))))))))
答案 0 :(得分:3)
为了更精确地控制set-process-sentinel
| set-process-filter
| start-process
,有人可能希望考虑合并recursive-edit
以在进程待处理时暂停elisp
函数 - 并使用exit-recursive-edit
或(throw 'exit nil)
来返回控制权暂停的elisp
功能。
编辑(2014年4月23日):编辑以创建包含recursive-edit
的最小示例。将在相关主题中维护和更新工作示例:https://stackoverflow.com/a/23178396/2112489
(defun my-git-password-process-filter (proc string)
(when (string-match "password" string)
(process-send-string
proc
(concat (read-passwd "Password: ") "\n"))))
(defun my-process-sentinel (proc string)
(when (= 0 (process-exit-status proc))
(message "Process `%s` has finished pushing to `%s`." proc git-remote-name)
(throw 'exit nil)))
(defun example-using-recursive-edit ()
;;
;; For a more detailed working example, please see this related thread:
;; https://stackoverflow.com/a/23178396/2112489
;;
;; * * * REDACTED TO CREATE MINIMAL WORKING EXAMPLE * * *
;;
(set-process-sentinel
(start-process
"commit-all"
"*Messages*"
"/usr/local/git/bin/git"
"commit"
"-m"
git-commit-message)
(lambda (p e) (when (= 0 (process-exit-status p))
(mapcar (lambda (git-remote-name)
(let ((proc
(start-process
"push-process"
"*Messages*"
"/usr/local/git/bin/git"
"push"
"-v"
(format "%s" git-remote-name)
(format "%s"
(with-current-buffer (get-buffer "*REMOTES*")
git-branch-name)) )))
(set-process-filter proc 'my-git-password-process-filter)
(set-process-sentinel proc 'my-process-sentinel)
(recursive-edit) ))
(with-current-buffer (get-buffer "*REMOTES*")
git-remote-list) )))))
答案 1 :(得分:3)
让人想到的方法就是让每个start-process
的调用都依赖于前一个过程的标记。
实质上,生成一个你想要做的事情的队列,触发第一个队列项的处理,并让每个sentinel触发器在其自己的进程完成后启动下一个队列项(如果有的话)的进程。 / p>
答案 2 :(得分:2)
以下是在函数结束时抛出结果的示例,此结果取决于事先完成的过程。正如这个帖子中的另一个答案所表明的那样,使用recursive-edit
是有帮助的 - 在这种情况下,它通过阻止结果被抛出直到过程结束来解决这个难题。
此特定示例使用ls
中找到的coreutils-8.21
版本用于OSX,其中某些选项可能在其他版本中不可用。此示例还包含一个创建方法,用于使用start-process
获取绝对路径/文件名,这通常不允许使用regexp参数,例如用于获取可见和隐藏的文件。
注意:进程过滤器无法可靠地创建精确列表(包括ls
列之间的空格),但是,此解释超出了此示例的范围。另一方面,进程输出缓冲区是可靠的。 [当我有时间时,我可能会在将来某个时候提交有关过程过滤器的错误报告。]
;;; EXAMPLE: (dolist (x (create-ls-list "~/")) (message "%s" x))
(defun create-ls-list (&optional dir)
(interactive)
(let* (
result
(directory
(cond
(dir
(if (equal dir "/") nil (directory-file-name dir)))
(t
(directory-file-name default-directory))))
(output-buffer "*LS-OUTPUT*")
(ls-command (concat
;;; Some versions of `ls` do not support TIME-STYLE argument.
"/Users/HOME/.0.data/.0.emacs/.0.macports/bin/gls"
" "
"-lhd" ;; listing switches
" "
directory ;; `nil` if root "/"
"/.*" ;; hidden files
" "
directory ;; `nil` if root "/"
"/*" ;; everything except hidden fies
" "
"--time-style=\"+%m-%d-%Y %H:%M:%S\""
" "
"--group-directories-first")) )
(when (get-buffer output-buffer)
(with-current-buffer (get-buffer output-buffer)
(erase-buffer)))
(set-process-sentinel
(start-process
"ls-process"
output-buffer
"/bin/bash"
"-c"
ls-command)
(lambda (p e) (when (= 0 (process-exit-status p))
(let* (
(output-buffer (get-buffer "*LS-OUTPUT*"))
(regexp (concat
"\\(^[sldrwxt+-]+\\)" ;; 1
"\\(\s+\\)" ;; 2
"\\([0-9]+\\)" ;; 3
"\\(\s+\\)" ;; 4
"\\([a-zA-Z]+\\)" ;; 5
"\\(\s+\\)" ;; 6
"\\([a-zA-Z]+\\)" ;; 7
"\\(\s+\\)" ;; 8
"\\([0-9.kKMGT]+\\)" ;; 9
"\\(\s+\\)" ;; 10
"\\([0-9-]+\\)" ;; 11
"\\(\s+\\)" ;; 12
"\\([0-9:]+\\)" ;; 13
"\\(\s+\\)" ;; 14
"\\(.*$\\)" ))) ;; 15
(with-current-buffer output-buffer
(save-excursion
(goto-char (point-max))
(while (re-search-backward regexp nil t)
(let* (
(one (match-string 1))
(two (match-string 2))
(three (match-string 3))
(four (match-string 4))
(five (match-string 5))
(six (match-string 6))
(seven (match-string 7))
(eight (match-string 8))
(nine (match-string 9))
(ten (match-string 10))
(eleven (match-string 11))
(twelve (match-string 12))
(thirteen (match-string 13))
(fourteen (match-string 14))
(fifteen (match-string 15)) )
(push
(list
one two three four five six seven eight nine
ten eleven twelve thirteen fourteen fifteen)
result)))))
(throw 'exit nil)))))
(recursive-edit)
result))