Initial implementation of vc-git.
authorChris Hanson <org/chris-hanson/cph>
Mon, 22 Jun 2009 07:28:39 +0000 (00:28 -0700)
committerChris Hanson <org/chris-hanson/cph>
Mon, 22 Jun 2009 07:28:39 +0000 (00:28 -0700)
src/edwin/decls.scm
src/edwin/ed-ffi.scm
src/edwin/edwin.ldr
src/edwin/edwin.pkg
src/edwin/vc-git.scm [new file with mode: 0644]
src/edwin/vc-rcs.scm

index ffb3803f0335c816f6f4169a1ab9e175892b6e88..cd9a2ba0c84c1cb00012de15411f66cccb408e7e 100644 (file)
@@ -225,10 +225,11 @@ USA.
                "undo"
                "unix"
                "vc"
-               "vc-rcs"
+               "vc-bzr"
                "vc-cvs"
+               "vc-git"
+               "vc-rcs"
                "vc-svn"
-               "vc-bzr"
                "verilog"
                "vhdl"
                "webster"
index 5b745b2d3ff9827547d9bea9f0a3ae05d601bcfa..c1a1571a8f532331b65d7f221a6ddd1c73cecc16 100644 (file)
@@ -1,6 +1,6 @@
 #| -*-Scheme-*-
 
-$Id: ed-ffi.scm,v 1.59 2008/01/30 20:02:00 cph Exp $
+$Id$
 
 Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
     1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
@@ -177,6 +177,11 @@ USA.
     ("utils"   (edwin))
     ("utlwin"  (edwin window))
     ("vc"      (edwin vc))
+    ("vc-bzr"  (edwin vc))
+    ("vc-cvs"  (edwin vc))
+    ("vc-git"  (edwin vc))
+    ("vc-rcs"  (edwin vc))
+    ("vc-svn"  (edwin vc))
     ("verilog" (edwin verilog))
     ("vhdl"    (edwin vhdl))
     ("webster" (edwin))
index 2c6bc9d40ec09894cf58c59be7a2fecbad4cc277..667257595d1a548d1bb7b257fe3424bc2fc9bcdc 100644 (file)
@@ -258,6 +258,7 @@ USA.
        (load "vc-cvs" (->environment '(EDWIN VC)))
        (load "vc-svn" (->environment '(EDWIN VC)))
        (load "vc-bzr" (->environment '(EDWIN VC)))
+       (load "vc-git" (->environment '(EDWIN VC)))
        (load "wincom" environment)
        (load "scrcom" environment)
        (load "modefs" environment)
index 46f6fd092a95d78e11aca6e6dc47c767661f2961..3c5d4f888c7bfab8b683cff1200fe3b19bcf8a8f 100644 (file)
@@ -1441,7 +1441,8 @@ USA.
         "vc-rcs"
         "vc-cvs"
         "vc-svn"
-        "vc-bzr")
+        "vc-bzr"
+        "vc-git")
   (parent (edwin))
   (export (edwin)
          edwin-command$vc-diff
@@ -1457,6 +1458,7 @@ USA.
          edwin-command$vc-version-diff
          edwin-command$vc-version-other-window
          edwin-mode$vc-log
+         edwin-variable$git-diff-switches
          edwin-variable$vc-checkin-hooks
          edwin-variable$vc-checkout-carefully
          edwin-variable$vc-command-messages
diff --git a/src/edwin/vc-git.scm b/src/edwin/vc-git.scm
new file mode 100644 (file)
index 0000000..5156290
--- /dev/null
@@ -0,0 +1,257 @@
+#| -*-Scheme-*-
+
+$Id$
+
+Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+    1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+    2006, 2007, 2008 Massachusetts Institute of Technology
+
+This file is part of MIT/GNU Scheme.
+
+MIT/GNU Scheme 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 2 of the License, or (at
+your option) any later version.
+
+MIT/GNU Scheme 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 MIT/GNU Scheme; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+USA.
+
+|#
+
+;;;; Version Control: git
+
+(declare (usual-integrations))
+\f
+(define vc-type:git
+  (make-vc-type 'GIT "git" "\$Id\$"))
+
+(define-vc-type-operation 'RELEASE vc-type:git
+  (lambda ()
+    (and (= 0 (vc-run-command #f '() "git" "--version"))
+        (let ((m (buffer-start (get-vc-command-buffer))))
+          (re-match-forward "git version \\(.+\\)$"
+                            m
+                            (line-end m 0)))
+        (extract-string (re-match-start 1) (re-match-end 1)))))
+
+(define-vc-type-operation 'CONTROL-DIRECTORY vc-type:git
+  (lambda (directory)
+    (let ((cd (subdirectory-pathname directory ".git")))
+      (if (file-directory? cd)
+         cd
+         'SEARCH-PARENT))))
+
+(define-vc-type-operation 'FIND-MASTER vc-type:git
+  (lambda (workfile control-dir)
+    (and (%git-workfile-versioned? workfile)
+        (make-vc-master vc-type:git
+                        (merge-pathnames "description" control-dir)
+                        workfile))))
+
+(define-vc-type-operation 'VALID? vc-type:git
+  (lambda (master)
+    (%git-workfile-versioned? (vc-master-workfile master))))
+
+(define-vc-type-operation 'DEFAULT-REVISION vc-type:git
+  (lambda (master)
+    master
+    #f))
+
+(define-vc-type-operation 'WORKFILE-REVISION vc-type:git
+  (lambda (master)
+    (let ((result
+          (%git-run-command (vc-master-workfile master)
+                            "symbolic-ref" "HEAD")))
+      (and result
+          (let ((regs
+                 (re-string-match "^\\(refs/heads/\\)?\\(.+\\)$" result)))
+            (if regs
+                (re-match-extract result regs 2)
+                result))))))
+
+(define-vc-type-operation 'LOCKING-USER vc-type:git
+  (lambda (master revision)
+    revision                           ;ignore
+    ;; The workfile is "locked" if it is modified.
+    ;; We consider the workfile's owner to be the locker.
+    (and (%git-workfile-modified? (vc-master-workfile master))
+        (unix/uid->string
+         (file-attributes/uid
+          (file-attributes (vc-master-workfile master)))))))
+
+(define-vc-type-operation 'WORKFILE-MODIFIED? vc-type:git
+  (lambda (master)
+    (%git-workfile-modified? (vc-master-workfile master))))
+\f
+(define-vc-type-operation 'NEXT-ACTION vc-type:git
+  (lambda (master)
+    (let ((status (%git-workfile-status (vc-master-workfile master))))
+      (case status
+       ((UNVERSIONED UNKNOWN) #f)
+       ((UNMODIFIED)
+        (if (vc-workfile-buffer-modified? master)
+            'CHECKIN
+            'UNMODIFIED))
+       ((ADDED COPIED DELETED MODIFIED RENAMED TYPE-CHANGED) 'CHECKIN)
+       ((UNMERGED) 'PENDING-MERGE)
+       (else (error "Unknown git status type:" status))))))
+
+(define-vc-type-operation 'KEEP-WORKFILES? vc-type:git
+  (lambda (master)
+    master
+    #t))
+
+(define-vc-type-operation 'WORKFILE-STATUS-STRING vc-type:git
+  (lambda (master)
+    (let ((status (%git-workfile-status (vc-master-workfile master))))
+      (if (eq? status 'UNMODIFIED)
+         #f
+         (symbol->string status)))))
+
+(define-vc-type-operation 'REGISTER vc-type:git
+  (lambda (workfile revision comment keep?)
+    revision comment keep?
+    (with-vc-command-message workfile "Registering"
+      (lambda ()
+       (vc-run-command workfile '() "git" "add" "--"
+                       (file-pathname workfile))))))
+
+(define-vc-type-operation 'CHECKOUT vc-type:git
+  (lambda (master revision lock? output-file)
+    lock?
+    (let ((workfile (file-pathname (vc-master-workfile master))))
+      (with-vc-command-message master "Checking out"
+       (lambda ()
+         (cond (output-file
+                (delete-file-no-errors output-file)
+                (vc-run-shell-command master '() "git" "show"
+                                      (string-append
+                                       (or revision "HEAD")
+                                       ":"
+                                       (enough-namestring
+                                        workfile
+                                        (directory-pathname
+                                         (vc-master-pathname master))))
+                                      ">"
+                                      output-file))
+               (else
+                (vc-run-command master '() "git" "checkout"
+                                (or revision "HEAD")
+                                "--" workfile))))))))
+
+(define-vc-type-operation 'CHECKIN vc-type:git
+  (lambda (master revision comment keep?)
+    revision keep?
+    (with-vc-command-message master "Checking in"
+      (lambda ()
+       (vc-run-command master '() "git" "commit"
+                       "--message" comment
+                       (file-pathname (vc-master-workfile master)))))))
+\f
+(define-vc-type-operation 'REVERT vc-type:git
+  (lambda (master)
+    (with-vc-command-message master "Reverting"
+      (lambda ()
+       (vc-run-command master '() "git" "checkout" "HEAD"
+                       "--" (file-pathname (vc-master-workfile master)))))))
+
+(define-vc-type-operation 'STEAL vc-type:git
+  (lambda (master revision)
+    master revision
+    (error "There are no git locks to steal.")))
+
+(define-vc-type-operation 'DIFF vc-type:git
+  (lambda (master rev1 rev2 simple?)
+    (if (and rev1 rev2)
+       (vc-run-command master (get-vc-diff-options simple?)
+                       "git" "diff-tree"
+                       "--exit-code" "-p"
+                       (and (not simple?)
+                            (ref-variable git-diff-switches
+                                          (vc-workfile-buffer master #f)))
+                       rev1 rev2
+                       "--" (file-pathname (vc-master-workfile master)))
+       (vc-run-command master (get-vc-diff-options simple?)
+                       "git" "diff-index"
+                       "--exit-code" "-p"
+                       (and (not simple?)
+                            (ref-variable git-diff-switches
+                                          (vc-workfile-buffer master #f)))
+                       (or rev1 "HEAD")
+                       "--" (file-pathname (vc-master-workfile master))))
+    (> (buffer-length (get-vc-diff-buffer simple?)) 0)))
+
+(define-variable git-diff-switches
+  "A list of strings specifying switches to pass to the `git diff' command."
+  '()
+  list-of-strings?)
+
+(define-vc-type-operation 'PRINT-LOG vc-type:git
+  (lambda (master)
+    (vc-run-command master '() "git" "log" "--follow" "--name-status"
+                   "--" (file-pathname (vc-master-workfile master)))))
+
+(define-vc-type-operation 'CHECK-LOG-ENTRY vc-type:git
+  (lambda (master log-buffer)
+    master log-buffer
+    unspecific))
+
+(define-vc-type-operation 'CHECK-HEADERS vc-type:git
+  (lambda (master buffer)
+    master buffer
+    #f))
+\f
+(define (%git-workfile-status workfile)
+  (if (%git-run-command workfile "add" "--refresh" "--"
+                       (file-namestring workfile))
+      (let ((result
+            (%git-run-command workfile "diff-index" "-z" "HEAD" "--"
+                              (file-namestring workfile))))
+       (cond ((not result) 'UNKNOWN)
+             ((string-null? result) 'UNMODIFIED)
+             (else
+              (let ((regs
+                     (re-string-match
+                      "^:[0-7]+ [0-7]+ [0-9a-f]+ [0-9a-f]+ \\(.\\)[0-9]*\000"
+                      result)))
+                (and regs
+                     (let ((status
+                            (string-ref (re-match-extract result regs 1)
+                                        0)))
+                       (case status
+                         ((#\A) 'ADDED)
+                         ((#\C) 'COPIED)
+                         ((#\D) 'DELETED)
+                         ((#\M) 'MODIFIED)
+                         ((#\R) 'RENAMED)
+                         ((#\T) 'TYPE-CHANGED)
+                         ((#\U) 'UNMERGED)
+                         (else (error "Unknown status:" status)))))))))
+      'UNVERSIONED))
+
+(define (%git-workfile-versioned? workfile)
+  (not (memq (%git-workfile-status workfile) '(UNKNOWN UNVERSIONED))))
+
+(define (%git-workfile-modified? workfile)
+  (not (eq? (%git-workfile-status workfile) 'UNMODIFIED)))
+
+(define (%git-run-command workfile command . args)
+  (let ((directory (directory-pathname workfile)))
+    (let ((program (os/find-program "git" directory #!default #f)))
+      (and program
+          (let ((port (open-output-string)))
+            (let ((status
+                   (run-synchronous-subprocess
+                    program
+                    (cons command args)
+                    'output port
+                    'working-directory directory)))
+              (and (eqv? status 0)
+                   (get-output-string port))))))))
\ No newline at end of file
index 0bc8b6f3ea99478e4fb10ae277062b3c1a790b88..037e4d1ac61b01a1558508e689a1c07fff8db6da 100644 (file)
@@ -190,6 +190,9 @@ USA.
   (lambda (directory)
     (let ((cd (rcs-directory directory)))
       (and (file-directory? cd)
+          (any (lambda (pathname)
+                 (string-suffix? ",v" (file-namestring pathname)))
+               (directory-read cd))
           cd))))
 
 (define-vc-type-operation 'REGISTER vc-type:rcs