gnu-emacs-sources
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

cvs-to-git.el


From: Thien-Thi Nguyen
Subject: cvs-to-git.el
Date: Wed, 30 Jan 2008 13:53:34 +0100

Greetings earthlings,

It's 2008 and time to get away from CVS.  But, where to?
For me, Git is a good choice.  We'll see in another 15 years.

See also <http://www.gnuvola.org/wip/> for other bits of play
(some suitable for Emacs directly, others only (very) indirectly).

thi


___________________________________________________________________
;;; cvs-to-git.el --- Rescue a project from its CVS repo

;; Copyright (C) 2008 Thien-Thi Nguyen
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Commentary:

;; Don't let your projects rot in CVS!
;; Use `cvs-to-git' to rescue them!

;;; Code:

(defvar cvs-to-git-CVSROOT "~/cvs"
  "Repository location for \"git cvsimport -d\".")

(defvar cvs-to-git-usermap "~/.cvsps/.ttn"
  "Filename for \"git cvsimport -A\".
This file maps usernames to real names / email addresses.
Each line has the form: username=Real Name <email-address>")

(defvar cvs-to-git-finish-fixup-hook nil
  "Normal hook for `cvs-to-git-finish-fixup'.
See, for example, `cvs-to-git-ttn-fixups'.")

(defvar cvs-to-git-in-progress nil
  "List of buffers hosting a cvs-to-git session.
Internal variable; do not use.")

(defun cvs-to-git (project under)
  "Initiate a rescue for PROJECT with output dir UNDER/PROJECT.
When the \"git cvsimport\" is done, call `cvs-to-git-start-fixup'."
  (interactive "sProject: \nDUnder: ")
  (let ((newdir (expand-file-name project under)))
    (when (file-exists-p newdir)
      (error "%s exists" newdir)))
  (push (compile (format "cd %s ; git cvsimport -A %s -d %s -C %s -k -u -v %s"
                         under cvs-to-git-usermap cvs-to-git-CVSROOT
                         project project))
        cvs-to-git-in-progress)
  (add-hook 'compilation-finish-functions 'cvs-to-git-start-fixup nil t)
  (set (make-local-variable 'cvs-to-git-project) project)
  (rename-buffer (format "CVS to GIT: %s" project))
  (message "Conversion into %s started (check back later)"
           (expand-file-name project)))

(defun cvs-to-git-start-fixup (buffer happenings)
  "Prepare BUFFER for further fixups.
Change to outline mode; convert the first line into a heading;
at eob, insert HAPPENINGS as a header, insert header \"tags\"
with following lines having the form:

- CVSTAG SHA1 DATE UTCTIME

Lastly, arrange for `C-c C-c' to run `cvs-to-git-finish-fixup'."
  (when (memq buffer cvs-to-git-in-progress)
    (let ((project (symbol-value 'cvs-to-git-project))
          tags)
      (setq cvs-to-git-in-progress (delq buffer cvs-to-git-in-progress))
      (setq default-directory (file-name-as-directory
                               (expand-file-name project)))
      (outline-mode)
      (goto-char (point-min))
      (delete-region (point) (line-end-position))
      (insert "* \"git cvsimport\" output")
      (goto-char (point-max))
      (insert "\n\n\n* \"git cvsimport\" status: " happenings)
      (insert "\n\n* description (one line, goes into .git/description)\n")
      (save-excursion
        (insert "[write me]\n")
        (insert "\n\n* tags (edit first column then type C-c C-c to finish)\n")
        (setq tags (split-string (shell-command-to-string "git tag")))
        (dolist (tag tags)
          (insert "- " tag " "
                  (shell-command-to-string
                   (format "git show %s %s | sed '%s'"
                           "--pretty=format:\"foo: %H %ci%n\""
                           tag
                           "/^foo: /!d;s///;s/ +0000$//")))))
      (let ((m (copy-keymap outline-mode-map)))
        (define-key m "\C-c\C-c" 'cvs-to-git-finish-fixup)
        (use-local-map m))
      (setq buffer-read-only nil)
      (message "%s ready for fixup" buffer))))

(defun cvs-to-git-finish-fixup ()
  "Finish fixing up the Git repo (see `cvs-to-git-start-fixup').
Interpret content of section \"tags\" as lines with format:

GITTAG CVSTAG SHA1 DATE UTCTIME

In all cases, delete CVSTAG.  If GITTAG is \"-\", do nothing else.
Otherwise, tag SHA1 w/ GITTAG using the two line annotation:

DATE UTCTIME
>From CVS tag CVSTAG.

Insert tagging operation output after each line.  When done, insert
output of \"git tag -n 2\" and run-hook `cvs-to-git-finish-fixup-hook'."
  (interactive)
  (goto-char (point-max))
  (search-backward "* description")
  (write-region (line-beginning-position 2) (line-beginning-position 3)
                ".git/description")
  (search-forward "* tags")
  (forward-line 1)
  (while (< (point) (point-max))
    (let ((ls (split-string (buffer-substring
                             (point) (line-end-position)))))
      (forward-line 1)
      (unless (string= "-" (car ls))
        (with-temp-file "TMP"
          (insert (nth 3 ls) " " (nth 4 ls) "\n"
                  "From CVS tag " (nth 1 ls) ".\n"))
        (call-process "git" nil t t "tag" "-a" "-F" "TMP"
                      (nth 0 ls) (nth 2 ls)))
      (call-process "git" nil t t "tag" "-d" (nth 1 ls))))
  (when (file-exists-p "TMP")
    (delete-file "TMP"))
  (insert "\n")
  (call-process "git" nil t t "tag" "-n" "2")
  (run-hooks 'cvs-to-git-finish-fixup-hook)
  (message "%s fixup done" (current-buffer)))

(defun cvs-to-git-ttn-fixups ()
  "Do miscellaneous ttn-preferred fixups.
Specifically:
 chmod +w .git/hooks/post-commit
 git config core.filemode false
 git ls-files -z | xargs -0 chmod -w
 (create files \".git/info/attributes\"
           and \".last-release\")

This is meant to be added to `cvs-to-git-finish-fixup-hook'."
  (set-file-modes ".git/hooks/post-commit" #o755)
  (call-process "git" nil nil nil "config" "core.filemode" "false")
  (shell-command "git ls-files -z | xargs -0 chmod -w")
  (with-temp-file ".git/info/attributes"
    (insert "*.el\tdiff=lisp\n"
            "*.scm\tdiff=lisp\n"))
  (with-temp-file ".last-release"
    (shell-command "git tag -n | sort -brk 2,3 | sed 's/ .*//;1q'" t)))

(provide 'cvs-to-git)

;;; cvs-to-git.el ends here




reply via email to

[Prev in Thread] Current Thread [Next in Thread]