Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fine-tuning: `set-process-sentinel` | `set-process-filter` | `start-process`

Tags:

emacs

elisp

There are very few examples on the internet involving all three of the functions at issue in this question -- i.e., set-process-sentinel; set-process-filter; and start-process.

I've tried a few different methods of fine-tuning the the processes in an effort to force process number 1 (push) to finish prior to the commencement of process number 2 (push). In all of my attempts, the second process always runs and finishes before I have finished entering my password for process number 1. Process number 2 has a password stored in the osxkeychain.

The first method I tried was with Magit, both synchronous and asynchronous processes. The second method I tried was with using the function while . . . to search the list of remotes in the buffer containing said list. The third attempt is listed below -- it uses a list of remotes that is created at the outset of the function and then mapcars down the list to push with Git.

Any ideas on how to better control process number 1 (push) so that it successfully finishes prior the commencement of process number 2 (push) would be greatly appreciated.

It is not the end of the world that process number 2 starts and finishes too early, but it is a matter of learning how to take control over Emacs processes -- rather than the processes taking control of me.


EDIT (April 23, 2014):  Added a doc-string. Revised handling of buffer *REMOTES* -- i.e., kill-local-variable 'git-remote-list and erase-buffer now works correctly by using 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)
    )))))))))))
like image 424
lawlist Avatar asked Dec 26 '22 10:12

lawlist


1 Answers

The approach that springs to mind is simply to make each call to start-process dependent on the sentinel for the previous process.

In essence, generate a queue of things you want to do, trigger the processing of the first queue item, and let each sentinel trigger start the process for the next queue item (if any) once its own process has completed.

like image 108
phils Avatar answered May 23 '23 06:05

phils