# HG changeset patch # User Andr Spiegel # Date 1051102165 0 # Node ID 01d84e9d30e0ccf148fb2ddbf002d8d881f2d2fd # Parent c475369e69952839f6ad705c89cb24c26d2fc165 Patch by Wolfgang Scherer (vc-cvs-stay-local): Allow lists of host regexps. (vc-cvs-stay-local-p): Handle them. (vc-cvs-parse-root): New function, used by the above. diff -r c475369e6995 -r 01d84e9d30e0 lisp/vc-cvs.el --- a/lisp/vc-cvs.el Tue Apr 22 19:03:18 2003 +0000 +++ b/lisp/vc-cvs.el Wed Apr 23 12:49:25 2003 +0000 @@ -5,7 +5,7 @@ ;; Author: FSF (see vc.el for full credits) ;; Maintainer: Andre Spiegel -;; $Id: vc-cvs.el,v 1.53 2003/04/05 15:51:14 spiegel Exp $ +;; $Id: vc-cvs.el,v 1.54 2003/04/19 22:40:18 monnier Exp $ ;; This file is part of GNU Emacs. @@ -81,15 +81,24 @@ :version "21.1" :group 'vc) -(defcustom vc-cvs-stay-local t +(defcustom vc-cvs-stay-local '(except "^\\(localhost\\)$") "*Non-nil means use local operations when possible for remote repositories. This avoids slow queries over the network and instead uses heuristics and past information to determine the current status of a file. -The value can also be a regular expression to match against the host name -of a repository; then VC only stays local for hosts that match it." +The value can also be a regular expression or list of regular +expressions to match against the host name of a repository; then VC +only stays local for hosts that match it. +This is useful in a setup, where most CVS servers should be contacted +directly, and only a few CVS servers cannot be reached easily. +For the opposite scenario, when only a few CVS servers are to be +queried directly, a list of regular expressions can be specified, +whose first element is the symbol `except'." :type '(choice (const :tag "Always stay local" t) - (string :tag "Host regexp") - (const :tag "Don't stay local" nil)) + (const :tag "Don't stay local" nil) + (list :format "\nExamine hostname and %v" :tag "Examine hostname ..." + (set :format "%v" :inline t (const :format "%t" :tag "don't" except)) + (regexp :format " stay local,\n%t: %v" :tag "if it matches") + (repeat :format "%v%i\n" :inline t (regexp :tag "or")))) :version "21.1" :group 'vc) @@ -715,7 +724,8 @@ flags)))) (defun vc-cvs-stay-local-p (file) - "Return non-nil if VC should stay local when handling FILE." + "Return non-nil if VC should stay local when handling FILE. +See `vc-cvs-stay-local'." (if vc-cvs-stay-local (let* ((dirname (if (file-directory-p file) (directory-file-name file) @@ -726,18 +736,99 @@ (vc-file-setprop dirname 'vc-cvs-stay-local-p (when (file-readable-p rootname) - (with-temp-buffer - (vc-insert-file rootname) - (goto-char (point-min)) - (if (looking-at "\\([^:]*\\):") - (if (not (stringp vc-cvs-stay-local)) - 'yes - (let ((hostname (match-string 1))) - (if (string-match vc-cvs-stay-local hostname) - 'yes - 'no))) - 'no)))))))) - (if (eq prop 'yes) t nil)))) + (with-temp-buffer + (vc-insert-file rootname) + (goto-char (point-min)) + (looking-at "\\([^\n]*\\)") + (let* ((cvs-root-members + (vc-cvs-parse-root (match-string 1))) + (hostname (nth 2 cvs-root-members))) + (if (not hostname) + 'no + (let ((stay-local t) rx) + (cond + ;; vc-cvs-stay-local: rx + ((stringp vc-cvs-stay-local) + (setq rx vc-cvs-stay-local)) + ;; vc-cvs-stay-local: '( [except] rx ... ) + ((consp vc-cvs-stay-local) + (setq rx (mapconcat + (function + (lambda (elt) + elt)) + (if (not (eq (car vc-cvs-stay-local) + 'except)) + vc-cvs-stay-local + (setq stay-local nil) + (cdr vc-cvs-stay-local)) + "\\|")))) + (if (not rx) + 'yes + (if (not (string-match rx hostname)) + (setq stay-local (not stay-local))) + (if stay-local + 'yes + 'no)))))))))))) + (if (eq prop 'yes) t nil)))) + +(defun vc-cvs-parse-root ( root ) + "Split CVS ROOT specification string into a list of fields. +A CVS root specification of the form + [:METHOD:][[USER@]HOSTNAME:]/path/to/repository +is converted to a normalized record with the following structure: + \(METHOD USER HOSTNAME CVS-ROOT). +The default METHOD for a CVS root of the form + /path/to/repository +is `local'. +The default METHOD for a CVS root of the form + [USER@]HOSTNAME:/path/to/repository +is `ext'. +For an empty string, nil is returned (illegal CVS root)." + ;; Split CVS root into colon separated fields (0-4). + ;; The `x:' makes sure, that leading colons are not lost; + ;; `HOST:/PATH' is then different from `:METHOD:/PATH'. + (let* ((root-list (cdr (split-string (concat "x:" root) ":"))) + (len (length root-list)) + ;; All syntactic varieties will get a proper METHOD. + (root-list + (cond + ((= len 0) + ;; Invalid CVS root + nil) + ((= len 1) + ;; Simple PATH => method `local' + (cons "local" + (cons nil root-list))) + ((= len 2) + ;; [USER@]HOST:PATH => method `ext' + (and (not (equal (car root-list) "")) + (cons "ext" root-list))) + ((= len 3) + ;; :METHOD:PATH + (cons (cadr root-list) + (cons nil (cddr root-list)))) + (t + ;; :METHOD:[USER@]HOST:PATH + (cdr root-list))))) + (if root-list + (let ((method (car root-list)) + (uhost (or (cadr root-list) "")) + (root (nth 2 root-list)) + user host) + ;; Split USER@HOST + (if (string-match "\\(.*\\)@\\(.*\\)" uhost) + (setq user (match-string 1 uhost) + host (match-string 2 uhost)) + (setq host uhost)) + ;; Remove empty HOST + (and (equal host "") + (setq host)) + ;; Fix windows style CVS root `:local:C:\\project\\cvs\\some\\dir' + (and host + (equal method "local") + (setq root (concat host ":" root) host)) + ;; Normalize CVS root record + (list method user host root))))) (defun vc-cvs-parse-status (&optional full) "Parse output of \"cvs status\" command in the current buffer.