Add new file sy-git.el for easier commit logging from SXEmacs
[slh] / sy-git.el
1 ;; sy-git.el --- A couple of nice git tools   -*- Emacs-Lisp -*-
2
3 ;; Copyright (C) 2015 Steve Youngs
4
5 ;; Author:     Steve Youngs <steve@sxemacs.org>
6 ;; Maintainer: Steve Youngs <steve@sxemacs.org>
7 ;; Created:    <2015-07-05>
8 ;; Time-stamp: <Sunday Jul  5, 2015 15:17:44 steve>
9 ;; Homepage:   http://git.sxemacs.org/slh
10 ;; Keywords:   git, tools, convenience
11
12 ;; This file is part of SLH (Steve's Lisp Hacks).
13
14 ;; Redistribution and use in source and binary forms, with or without
15 ;; modification, are permitted provided that the following conditions
16 ;; are met:
17 ;;
18 ;; 1. Redistributions of source code must retain the above copyright
19 ;;    notice, this list of conditions and the following disclaimer.
20 ;;
21 ;; 2. Redistributions in binary form must reproduce the above copyright
22 ;;    notice, this list of conditions and the following disclaimer in the
23 ;;    documentation and/or other materials provided with the distribution.
24 ;;
25 ;; 3. Neither the name of the author nor the names of any contributors
26 ;;    may be used to endorse or promote products derived from this
27 ;;    software without specific prior written permission.
28 ;;
29 ;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
30 ;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31 ;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
32 ;; DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 ;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 ;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
36 ;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
37 ;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
38 ;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
39 ;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
41 ;;; Commentary:
42 ;; 
43 ;;   This is the beginnings of some convenience tools to use with git
44 ;;   from within SXEmacs.
45 ;;
46 ;;   Presently, all that is here is a 'add-log' function that
47 ;;   lets you write commit logs in a similar format to that of
48 ;;   `add-change-log-entry'.  It is globally bound to `C-x G a'.
49 ;;   See: `sy-git-add-log-entry'.
50
51 ;;; Todo:
52 ;;
53 ;;     o Implement a variation of `patch-to-change-log'
54 ;;     o Make it possible to call `sy-git-add-log-entry' from a diff.
55
56 ;;; Code:
57 (defun sy-git-check-hook (hook)
58   "Return non-nil when HOOK script exists and is usable.
59
60 By \"usable\" we mean for `sy-git-add-log-entry'."
61   (let ((hookname (file-basename hook)))
62     (when (file-exists-p hook)
63       (with-temp-buffer
64         (insert-file-contents-literally hook)
65         (goto-char (point-min))
66         (cond
67          ((equal hookname "commit-msg")
68           (re-search-forward (regexp-quote "sed -i '/^#/d'") nil t))
69          ((equal hookname "post-commit")
70           (re-search-forward (regexp-quote "rm -f ${LOG}") nil t))
71          (t nil))))))
72
73 (defun sy-git-add-log-entry (&optional newlog)
74   "*A wrapper for `add-change-log-entry'.
75
76 Optional prefix argument, NEWLOG, forces a new log file to be
77 created. Use this if you need to start over.
78
79 To commit your changes with the log that this function creates use:
80
81   git commit -F ++log
82
83 This function allows you to create git commit logs in a similar format
84 to that used by `add-change-log-entry'.  Some commented instructions
85 are added to the top of the log which you should either delete yourself
86 prior to committing, or have a hook do it automatically \(preferred\).
87
88 Hooks: 
89 2 hooks will make using this function a lot simpler and automatic.
90 A 'commit-msg' hook, and a 'post-commit' hook.  They reside in
91 '$repo/.git/hooks/'.
92
93 Example commit-msg:
94
95   #!/bin/sh
96   # Delete lines beginning with '#'.
97   sed -i '/^#/d' \"$1\" || {
98       echo >&2 Commit aborted by commit-msg hook
99       exit 1
100   }
101   # End commit-msg
102
103 Example post-commit:
104
105   #!/bin/sh
106   # Delete log file after successful commit.
107   LOG=$(git rev-parse --show-toplevel)/++log
108   [ -f ${LOG} ] && rm -f ${LOG}
109   # End post-commit
110
111 "
112   (interactive "p")
113   (let* ((topd (substring (shell-command-to-string
114                            "git rev-parse --show-toplevel") 0 -1))
115          (logfile (expand-file-name "++log" topd))
116          (hookd (paths-construct-path `(,topd ".git" "hooks")))
117          (msg-hook (expand-file-name "commit-msg" hookd))
118          (commit-hook (expand-file-name "post-commit" hookd))
119          (add-log-full-name (substring (shell-command-to-string
120                                         "git config user.name") 0 -1))
121          (add-log-mailing-address (substring (shell-command-to-string
122                                               "git config user.email") 0 -1))
123          (add-log-keep-changes-together t)
124          (header (concat
125                   (format-time-string "%Y-%m-%d")
126                   "  "
127                   add-log-full-name "  <"
128                   add-log-mailing-address ">\n"))
129          (newhead
130           (concat
131            "# Copyright -- to fool `add-change-log-entry'
132 ### Instructions:
133 #
134 # Put your short one-line summary on the first blank line after these.
135 # Make sure that there is a blank line between your summary and the rest
136 # of your changes log.
137 #
138 ###"
139            (if (sy-git-check-hook msg-hook)
140                "\n# Lines beginning with '#' will be automatically deleted."
141              "\n# You MUST delete these lines before committing.")
142            (unless (sy-git-check-hook commit-hook)
143              "\n# No post-commit hook. Manually delete this log after you commit.")
144            "\n###"))
145          )
146     (and current-prefix-arg             ; User wants to start over
147          (file-exists-p logfile)
148          (ignore-errors
149            (delete-file logfile)))
150     ;; It is possible that the logfile is gone but the buffer is still
151     ;; active
152     (and (not (file-exists-p logfile))
153          (buffer-live-p (find-buffer-visiting logfile))
154          (kill-buffer (find-buffer-visiting logfile)))
155     (with-current-buffer (find-file-noselect logfile)
156       (save-excursion
157         (goto-char (point-min))
158         (when (re-search-forward "^# Copyright" (point-at-eol) t)
159           (replace-match "Copyright"))))
160     (add-change-log-entry nil logfile t nil)
161     (save-excursion
162       (goto-char (point-min))
163       (delete-matching-lines (regexp-quote header))
164       (when (re-search-forward "^Copyright" (point-at-eol) t)
165         (replace-match "# Copyright"))
166       (goto-char (point-min))
167       (unless (search-forward newhead nil t)
168         (insert newhead "\n\n\n")))))
169
170
171 (global-set-key [(control x) G a] #'sy-git-add-log-entry) 
172
173 (provide 'sy-git)
174 ;;; sy-git.el ends here