微调:`set-process-sentinel` | `set-process-filter` | `启动process`

时间:2014-04-23 07:37:33

标签: emacs elisp

互联网上很少涉及这个问题中涉及的所有三个功能的例子,即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-listerase-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)
    )))))))))))

3 个答案:

答案 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))