diff options
| -rw-r--r-- | lisp/vc-cvs.el | 129 |
1 files changed, 110 insertions, 19 deletions
diff --git a/lisp/vc-cvs.el b/lisp/vc-cvs.el index 4fcba6a07e1..ab69de81d77 100644 --- a/lisp/vc-cvs.el +++ b/lisp/vc-cvs.el | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | ;; Author: FSF (see vc.el for full credits) | 5 | ;; Author: FSF (see vc.el for full credits) |
| 6 | ;; Maintainer: Andre Spiegel <spiegel@gnu.org> | 6 | ;; Maintainer: Andre Spiegel <spiegel@gnu.org> |
| 7 | 7 | ||
| 8 | ;; $Id: vc-cvs.el,v 1.53 2003/04/05 15:51:14 spiegel Exp $ | 8 | ;; $Id: vc-cvs.el,v 1.54 2003/04/19 22:40:18 monnier Exp $ |
| 9 | 9 | ||
| 10 | ;; This file is part of GNU Emacs. | 10 | ;; This file is part of GNU Emacs. |
| 11 | 11 | ||
| @@ -81,15 +81,24 @@ This is only meaningful if you don't use the implicit checkout model | |||
| 81 | :version "21.1" | 81 | :version "21.1" |
| 82 | :group 'vc) | 82 | :group 'vc) |
| 83 | 83 | ||
| 84 | (defcustom vc-cvs-stay-local t | 84 | (defcustom vc-cvs-stay-local '(except "^\\(localhost\\)$") |
| 85 | "*Non-nil means use local operations when possible for remote repositories. | 85 | "*Non-nil means use local operations when possible for remote repositories. |
| 86 | This avoids slow queries over the network and instead uses heuristics | 86 | This avoids slow queries over the network and instead uses heuristics |
| 87 | and past information to determine the current status of a file. | 87 | and past information to determine the current status of a file. |
| 88 | The value can also be a regular expression to match against the host name | 88 | The value can also be a regular expression or list of regular |
| 89 | of a repository; then VC only stays local for hosts that match it." | 89 | expressions to match against the host name of a repository; then VC |
| 90 | only stays local for hosts that match it. | ||
| 91 | This is useful in a setup, where most CVS servers should be contacted | ||
| 92 | directly, and only a few CVS servers cannot be reached easily. | ||
| 93 | For the opposite scenario, when only a few CVS servers are to be | ||
| 94 | queried directly, a list of regular expressions can be specified, | ||
| 95 | whose first element is the symbol `except'." | ||
| 90 | :type '(choice (const :tag "Always stay local" t) | 96 | :type '(choice (const :tag "Always stay local" t) |
| 91 | (string :tag "Host regexp") | 97 | (const :tag "Don't stay local" nil) |
| 92 | (const :tag "Don't stay local" nil)) | 98 | (list :format "\nExamine hostname and %v" :tag "Examine hostname ..." |
| 99 | (set :format "%v" :inline t (const :format "%t" :tag "don't" except)) | ||
| 100 | (regexp :format " stay local,\n%t: %v" :tag "if it matches") | ||
| 101 | (repeat :format "%v%i\n" :inline t (regexp :tag "or")))) | ||
| 93 | :version "21.1" | 102 | :version "21.1" |
| 94 | :group 'vc) | 103 | :group 'vc) |
| 95 | 104 | ||
| @@ -715,7 +724,8 @@ and that it passes `vc-cvs-global-switches' to it before FLAGS." | |||
| 715 | flags)))) | 724 | flags)))) |
| 716 | 725 | ||
| 717 | (defun vc-cvs-stay-local-p (file) | 726 | (defun vc-cvs-stay-local-p (file) |
| 718 | "Return non-nil if VC should stay local when handling FILE." | 727 | "Return non-nil if VC should stay local when handling FILE. |
| 728 | See `vc-cvs-stay-local'." | ||
| 719 | (if vc-cvs-stay-local | 729 | (if vc-cvs-stay-local |
| 720 | (let* ((dirname (if (file-directory-p file) | 730 | (let* ((dirname (if (file-directory-p file) |
| 721 | (directory-file-name file) | 731 | (directory-file-name file) |
| @@ -726,18 +736,99 @@ and that it passes `vc-cvs-global-switches' to it before FLAGS." | |||
| 726 | (vc-file-setprop | 736 | (vc-file-setprop |
| 727 | dirname 'vc-cvs-stay-local-p | 737 | dirname 'vc-cvs-stay-local-p |
| 728 | (when (file-readable-p rootname) | 738 | (when (file-readable-p rootname) |
| 729 | (with-temp-buffer | 739 | (with-temp-buffer |
| 730 | (vc-insert-file rootname) | 740 | (vc-insert-file rootname) |
| 731 | (goto-char (point-min)) | 741 | (goto-char (point-min)) |
| 732 | (if (looking-at "\\([^:]*\\):") | 742 | (looking-at "\\([^\n]*\\)") |
| 733 | (if (not (stringp vc-cvs-stay-local)) | 743 | (let* ((cvs-root-members |
| 734 | 'yes | 744 | (vc-cvs-parse-root (match-string 1))) |
| 735 | (let ((hostname (match-string 1))) | 745 | (hostname (nth 2 cvs-root-members))) |
| 736 | (if (string-match vc-cvs-stay-local hostname) | 746 | (if (not hostname) |
| 737 | 'yes | 747 | 'no |
| 738 | 'no))) | 748 | (let ((stay-local t) rx) |
| 739 | 'no)))))))) | 749 | (cond |
| 740 | (if (eq prop 'yes) t nil)))) | 750 | ;; vc-cvs-stay-local: rx |
| 751 | ((stringp vc-cvs-stay-local) | ||
| 752 | (setq rx vc-cvs-stay-local)) | ||
| 753 | ;; vc-cvs-stay-local: '( [except] rx ... ) | ||
| 754 | ((consp vc-cvs-stay-local) | ||
| 755 | (setq rx (mapconcat | ||
| 756 | (function | ||
| 757 | (lambda (elt) | ||
| 758 | elt)) | ||
| 759 | (if (not (eq (car vc-cvs-stay-local) | ||
| 760 | 'except)) | ||
| 761 | vc-cvs-stay-local | ||
| 762 | (setq stay-local nil) | ||
| 763 | (cdr vc-cvs-stay-local)) | ||
| 764 | "\\|")))) | ||
| 765 | (if (not rx) | ||
| 766 | 'yes | ||
| 767 | (if (not (string-match rx hostname)) | ||
| 768 | (setq stay-local (not stay-local))) | ||
| 769 | (if stay-local | ||
| 770 | 'yes | ||
| 771 | 'no)))))))))))) | ||
| 772 | (if (eq prop 'yes) t nil)))) | ||
| 773 | |||
| 774 | (defun vc-cvs-parse-root ( root ) | ||
| 775 | "Split CVS ROOT specification string into a list of fields. | ||
| 776 | A CVS root specification of the form | ||
| 777 | [:METHOD:][[USER@]HOSTNAME:]/path/to/repository | ||
| 778 | is converted to a normalized record with the following structure: | ||
| 779 | \(METHOD USER HOSTNAME CVS-ROOT). | ||
| 780 | The default METHOD for a CVS root of the form | ||
| 781 | /path/to/repository | ||
| 782 | is `local'. | ||
| 783 | The default METHOD for a CVS root of the form | ||
| 784 | [USER@]HOSTNAME:/path/to/repository | ||
| 785 | is `ext'. | ||
| 786 | For an empty string, nil is returned (illegal CVS root)." | ||
| 787 | ;; Split CVS root into colon separated fields (0-4). | ||
| 788 | ;; The `x:' makes sure, that leading colons are not lost; | ||
| 789 | ;; `HOST:/PATH' is then different from `:METHOD:/PATH'. | ||
| 790 | (let* ((root-list (cdr (split-string (concat "x:" root) ":"))) | ||
| 791 | (len (length root-list)) | ||
| 792 | ;; All syntactic varieties will get a proper METHOD. | ||
| 793 | (root-list | ||
| 794 | (cond | ||
| 795 | ((= len 0) | ||
| 796 | ;; Invalid CVS root | ||
| 797 | nil) | ||
| 798 | ((= len 1) | ||
| 799 | ;; Simple PATH => method `local' | ||
| 800 | (cons "local" | ||
| 801 | (cons nil root-list))) | ||
| 802 | ((= len 2) | ||
| 803 | ;; [USER@]HOST:PATH => method `ext' | ||
| 804 | (and (not (equal (car root-list) "")) | ||
| 805 | (cons "ext" root-list))) | ||
| 806 | ((= len 3) | ||
| 807 | ;; :METHOD:PATH | ||
| 808 | (cons (cadr root-list) | ||
| 809 | (cons nil (cddr root-list)))) | ||
| 810 | (t | ||
| 811 | ;; :METHOD:[USER@]HOST:PATH | ||
| 812 | (cdr root-list))))) | ||
| 813 | (if root-list | ||
| 814 | (let ((method (car root-list)) | ||
| 815 | (uhost (or (cadr root-list) "")) | ||
| 816 | (root (nth 2 root-list)) | ||
| 817 | user host) | ||
| 818 | ;; Split USER@HOST | ||
| 819 | (if (string-match "\\(.*\\)@\\(.*\\)" uhost) | ||
| 820 | (setq user (match-string 1 uhost) | ||
| 821 | host (match-string 2 uhost)) | ||
| 822 | (setq host uhost)) | ||
| 823 | ;; Remove empty HOST | ||
| 824 | (and (equal host "") | ||
| 825 | (setq host)) | ||
| 826 | ;; Fix windows style CVS root `:local:C:\\project\\cvs\\some\\dir' | ||
| 827 | (and host | ||
| 828 | (equal method "local") | ||
| 829 | (setq root (concat host ":" root) host)) | ||
| 830 | ;; Normalize CVS root record | ||
| 831 | (list method user host root))))) | ||
| 741 | 832 | ||
| 742 | (defun vc-cvs-parse-status (&optional full) | 833 | (defun vc-cvs-parse-status (&optional full) |
| 743 | "Parse output of \"cvs status\" command in the current buffer. | 834 | "Parse output of \"cvs status\" command in the current buffer. |