diff options
| author | Stefan Monnier | 2000-03-11 03:51:31 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2000-03-11 03:51:31 +0000 |
| commit | 5b467bf4e2787e3290280cadbae9e915df88dacd (patch) | |
| tree | 83e838669d3052e213f8f518602bae5ec0cf0a15 /lisp/pcvs-parse.el | |
| parent | afa18a4e5d28a418fa9374c96be75a8e20f5fe08 (diff) | |
| download | emacs-5b467bf4e2787e3290280cadbae9e915df88dacd.tar.gz emacs-5b467bf4e2787e3290280cadbae9e915df88dacd.zip | |
*** empty log message ***
Diffstat (limited to 'lisp/pcvs-parse.el')
| -rw-r--r-- | lisp/pcvs-parse.el | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/lisp/pcvs-parse.el b/lisp/pcvs-parse.el new file mode 100644 index 00000000000..b65f8d2eb60 --- /dev/null +++ b/lisp/pcvs-parse.el | |||
| @@ -0,0 +1,478 @@ | |||
| 1 | ;;; pcvs-parse.el --- The CVS output parser | ||
| 2 | |||
| 3 | ;; Copyright (C) 1991-2000 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Stefan Monnier <monnier@cs.yale.edu> | ||
| 6 | ;; Keywords: pcl-cvs | ||
| 7 | ;; Version: $Name: $ | ||
| 8 | ;; Revision: $Id: pcl-cvs-parse.el,v 1.41 2000/03/05 21:32:21 monnier Exp $ | ||
| 9 | |||
| 10 | ;; This file is part of GNU Emacs. | ||
| 11 | |||
| 12 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 13 | ;; it under the terms of the GNU General Public License as published by | ||
| 14 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 15 | ;; any later version. | ||
| 16 | |||
| 17 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | ;; GNU General Public License for more details. | ||
| 21 | |||
| 22 | ;; You should have received a copy of the GNU General Public License | ||
| 23 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 24 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 25 | ;; Boston, MA 02111-1307, USA. | ||
| 26 | |||
| 27 | ;;; Commentary: | ||
| 28 | |||
| 29 | |||
| 30 | ;;; Code: | ||
| 31 | |||
| 32 | (eval-when-compile (require 'cl)) | ||
| 33 | |||
| 34 | (require 'pcvs-util) | ||
| 35 | (require 'pcvs-info) | ||
| 36 | |||
| 37 | ;; imported from pcvs.el | ||
| 38 | (defvar cvs-execute-single-dir) | ||
| 39 | |||
| 40 | ;; parse vars | ||
| 41 | |||
| 42 | (defcustom cvs-update-prog-output-skip-regexp "$" | ||
| 43 | "*A regexp that matches the end of the output from all cvs update programs. | ||
| 44 | That is, output from any programs that are run by CVS (by the flag -u | ||
| 45 | in the `modules' file - see cvs(5)) when `cvs update' is performed should | ||
| 46 | terminate with a line that this regexp matches. It is enough that | ||
| 47 | some part of the line is matched. | ||
| 48 | |||
| 49 | The default (a single $) fits programs without output." | ||
| 50 | :group 'pcl-cvs | ||
| 51 | :type '(regexp :value "$")) | ||
| 52 | |||
| 53 | (defcustom cvs-parse-ignored-messages | ||
| 54 | '("Executing ssh-askpass to query the password.*$" | ||
| 55 | ".*Remote host denied X11 forwarding.*$") | ||
| 56 | "*A list of regexps matching messages that should be ignored by the parser. | ||
| 57 | Each regexp should match a whole set of lines and should hence be terminated | ||
| 58 | by `$'." | ||
| 59 | :group 'pcl-cvs | ||
| 60 | :type '(repeat regexp)) | ||
| 61 | |||
| 62 | ;; a few more defvars just to shut up the compiler | ||
| 63 | (defvar cvs-start) | ||
| 64 | (defvar cvs-current-dir) | ||
| 65 | (defvar cvs-current-subdir) | ||
| 66 | (defvar dont-change-disc) | ||
| 67 | |||
| 68 | ;;;; The parser | ||
| 69 | |||
| 70 | (defconst cvs-parse-known-commands | ||
| 71 | '("status" "add" "commit" "update" "remove" "checkout" "ci") | ||
| 72 | "List of CVS commands whose output is understood by the parser.") | ||
| 73 | |||
| 74 | (defun cvs-parse-buffer (parse-spec dont-change-disc &optional subdir) | ||
| 75 | "Parse current buffer according to PARSE-SPEC. | ||
| 76 | PARSE-SPEC is a function of no argument advancing the point and returning | ||
| 77 | either a fileinfo or t (if the matched text should be ignored) or | ||
| 78 | nil if it didn't match anything. | ||
| 79 | DONT-CHANGE-DISC just indicates whether the command was changing the disc | ||
| 80 | or not (useful to tell the difference btween `cvs-examine' and `cvs-update' | ||
| 81 | ouytput. | ||
| 82 | The path names should be interpreted as relative to SUBDIR (defaults | ||
| 83 | to the `default-directory'). | ||
| 84 | Return a list of collected entries, or t if an error occured." | ||
| 85 | (goto-char (point-min)) | ||
| 86 | (let ((fileinfos ()) | ||
| 87 | (cvs-current-dir "") | ||
| 88 | (case-fold-search nil) | ||
| 89 | (cvs-current-subdir (or subdir ""))) | ||
| 90 | (while (not (or (eobp) (eq fileinfos t))) | ||
| 91 | (let ((ret (cvs-parse-run-table parse-spec))) | ||
| 92 | (cond | ||
| 93 | ;; it matched a known information message | ||
| 94 | ((cvs-fileinfo-p ret) (push ret fileinfos)) | ||
| 95 | ;; it didn't match anything at all (impossible) | ||
| 96 | ((and (consp ret) (cvs-fileinfo-p (car ret))) | ||
| 97 | (setq fileinfos (append ret fileinfos))) | ||
| 98 | ((null ret) (setq fileinfos t)) | ||
| 99 | ;; it matched something that should be ignored | ||
| 100 | (t nil)))) | ||
| 101 | (nreverse fileinfos))) | ||
| 102 | |||
| 103 | |||
| 104 | ;; All those parsing macros/functions should return a success indicator | ||
| 105 | (defsubst cvs-parse-msg () (buffer-substring cvs-start (1- (point)))) | ||
| 106 | |||
| 107 | ;;(defsubst COLLECT (exp) (push exp *result*)) | ||
| 108 | ;;(defsubst PROG (e) t) | ||
| 109 | ;;(defmacro SEQ (&rest seqs) (cons 'and seqs)) | ||
| 110 | |||
| 111 | (defmacro cvs-match (re &rest matches) | ||
| 112 | "Try to match RE and extract submatches. | ||
| 113 | If RE matches, advance the point until the line after the match and | ||
| 114 | then assign the variables as specified in MATCHES (via `setq')." | ||
| 115 | (cons 'cvs-do-match | ||
| 116 | (cons re (mapcar (lambda (match) | ||
| 117 | `(cons ',(first match) ,(second match))) | ||
| 118 | matches)))) | ||
| 119 | |||
| 120 | (defun cvs-do-match (re &rest matches) | ||
| 121 | "Internal function for the `cvs-match' macro. | ||
| 122 | Match RE and if successful, execute MATCHES." | ||
| 123 | ;; Is it a match? | ||
| 124 | (when (looking-at re) | ||
| 125 | (goto-char (match-end 0)) | ||
| 126 | ;; Skip the newline (unless we already are at the end of the buffer). | ||
| 127 | (when (and (eolp) (< (point) (point-max))) (forward-char)) | ||
| 128 | ;; assign the matches | ||
| 129 | (dolist (match matches t) | ||
| 130 | (let ((val (cdr match))) | ||
| 131 | (set (car match) (if (integerp val) (match-string val) val)))))) | ||
| 132 | |||
| 133 | (defmacro cvs-or (&rest alts) | ||
| 134 | "Try each one of the ALTS alternatives until one matches." | ||
| 135 | `(let ((-cvs-parse-point (point))) | ||
| 136 | ,(cons 'or | ||
| 137 | (mapcar (lambda (es) | ||
| 138 | `(or ,es (ignore (goto-char -cvs-parse-point)))) | ||
| 139 | alts)))) | ||
| 140 | (def-edebug-spec cvs-or t) | ||
| 141 | |||
| 142 | ;; This is how parser tables should be executed | ||
| 143 | (defun cvs-parse-run-table (parse-spec) | ||
| 144 | "Run PARSE-SPEC and provide sensible default behavior." | ||
| 145 | (unless (bolp) (forward-line 1)) ;this should never be needed | ||
| 146 | (let ((cvs-start (point))) | ||
| 147 | (cvs-or | ||
| 148 | (funcall parse-spec) | ||
| 149 | |||
| 150 | (dolist (re cvs-parse-ignored-messages) | ||
| 151 | (when (cvs-match re) (return t))) | ||
| 152 | |||
| 153 | ;; This is a parse error. Create a message-type fileinfo. | ||
| 154 | (and | ||
| 155 | (cvs-match ".*$") | ||
| 156 | (cvs-create-fileinfo 'MESSAGE cvs-current-dir " " | ||
| 157 | (concat " Parser Error: '" (cvs-parse-msg) "'") | ||
| 158 | :subtype 'ERROR))))) | ||
| 159 | |||
| 160 | |||
| 161 | (defun cvs-parsed-fileinfo (type path &optional directory &rest keys) | ||
| 162 | "Create a fileinfo. | ||
| 163 | TYPE can either be a type symbol or a cons of the form (TYPE . SUBTYPE). | ||
| 164 | PATH is the filename. | ||
| 165 | DIRECTORY influences the way PATH is interpreted: | ||
| 166 | - if it's a string, it denotes the directory in which PATH (which should then be | ||
| 167 | a plain file name with no directory component) resides. | ||
| 168 | - if it's nil, the PATH should not be trusted: if it has a directory | ||
| 169 | component, use it, else, assume it is relative to the current directory. | ||
| 170 | - else, the PATH should be trusted to be relative to the root | ||
| 171 | directory (i.e. if there is no directory component, it means the file | ||
| 172 | is inside the main directory). | ||
| 173 | The remaining KEYS are passed directly to `cvs-create-fileinfo'." | ||
| 174 | (let ((dir directory) | ||
| 175 | (file path)) | ||
| 176 | ;; only trust the directory if it's a string | ||
| 177 | (unless (stringp directory) | ||
| 178 | ;; else, if the directory is true, the path should be trusted | ||
| 179 | (setq dir (or (file-name-directory path) (if directory ""))) | ||
| 180 | (setq file (file-name-nondirectory path))) | ||
| 181 | |||
| 182 | (let ((type (if (consp type) (car type) type)) | ||
| 183 | (subtype (if (consp type) (cdr type)))) | ||
| 184 | (when dir (setq cvs-current-dir dir)) | ||
| 185 | (apply 'cvs-create-fileinfo type | ||
| 186 | (concat cvs-current-subdir (or dir cvs-current-dir)) | ||
| 187 | file (cvs-parse-msg) :subtype subtype keys)))) | ||
| 188 | |||
| 189 | |||
| 190 | ;;;; CVS Process Parser Tables: | ||
| 191 | ;;;; | ||
| 192 | ;;;; The table for status and update could actually be merged since they | ||
| 193 | ;;;; don't conflict. But they don't overlap much either. | ||
| 194 | |||
| 195 | (defun cvs-parse-table () | ||
| 196 | "Table of message objects for `cvs-parse-process'." | ||
| 197 | (let (c file dir path type base-rev subtype) | ||
| 198 | (cvs-or | ||
| 199 | |||
| 200 | (cvs-parse-status) | ||
| 201 | (cvs-parse-merge) | ||
| 202 | (cvs-parse-commit) | ||
| 203 | |||
| 204 | ;; this is not necessary because the fileinfo merging will remove | ||
| 205 | ;; such duplicate info and luckily the second info is the one we want. | ||
| 206 | ;; (and (cvs-match "M \\(.*\\)$" (path 1)) | ||
| 207 | ;; (cvs-parse-merge path)) | ||
| 208 | |||
| 209 | ;; Normal file state indicator. | ||
| 210 | (and | ||
| 211 | (cvs-match "\\([MARCUPNJ?]\\) \\(.*\\)$" (c 1) (path 2)) | ||
| 212 | ;; M: The file is modified by the user, and untouched in the repository. | ||
| 213 | ;; A: The file is "cvs add"ed, but not "cvs ci"ed. | ||
| 214 | ;; R: The file is "cvs remove"ed, but not "cvs ci"ed. | ||
| 215 | ;; C: Conflict | ||
| 216 | ;; U: The file is copied from the repository. | ||
| 217 | ;; P: The file was patched from the repository. | ||
| 218 | ;; ?: Unknown file. | ||
| 219 | (let ((code (aref c 0))) | ||
| 220 | (cvs-parsed-fileinfo (case code | ||
| 221 | (?M 'MODIFIED) | ||
| 222 | (?A 'ADDED) | ||
| 223 | (?R 'REMOVED) | ||
| 224 | (?? 'UNKNOWN) | ||
| 225 | (?C 'CONFLICT) ;(if dont-change-disc 'NEED-MERGE | ||
| 226 | (?J 'NEED-MERGE) ;not supported by standard CVS | ||
| 227 | ((?U ?P) | ||
| 228 | (if dont-change-disc | ||
| 229 | 'NEED-UPDATE | ||
| 230 | (cons 'UP-TO-DATE | ||
| 231 | (if (eq code ?U) 'UPDATED 'PATCHED))))) | ||
| 232 | path 'trust))) | ||
| 233 | |||
| 234 | (and | ||
| 235 | (cvs-match "pcl-cvs: descending directory \\(.*\\)$" (dir 1)) | ||
| 236 | (setq cvs-current-subdir dir)) | ||
| 237 | |||
| 238 | ;; A special cvs message | ||
| 239 | (and | ||
| 240 | (cvs-match "cvs[.ex]* [a-z]+: ") | ||
| 241 | (cvs-or | ||
| 242 | |||
| 243 | ;; CVS is descending a subdirectory | ||
| 244 | ;; (status says `examining' while update says `updating') | ||
| 245 | (and | ||
| 246 | (cvs-match "\\(Examining\\|Updating\\) \\(.*\\)$" (dir 2)) | ||
| 247 | (let ((dir (if (string= "." dir) "" (file-name-as-directory dir)))) | ||
| 248 | (cvs-parsed-fileinfo 'DIRCHANGE "." dir))) | ||
| 249 | |||
| 250 | ;; [-n update] A new (or pruned) directory appeared but isn't traversed | ||
| 251 | (and | ||
| 252 | (cvs-match "New directory `\\(.*\\)' -- ignored$" (dir 1)) | ||
| 253 | (cvs-parsed-fileinfo 'MESSAGE " " (file-name-as-directory dir))) | ||
| 254 | |||
| 255 | ;; File removed, since it is removed (by third party) in repository. | ||
| 256 | (and | ||
| 257 | (cvs-or | ||
| 258 | (cvs-match "warning: \\(.*\\) is not (any longer) pertinent$" (file 1)) | ||
| 259 | (cvs-match "\\(.*\\) is no longer in the repository$" (file 1))) | ||
| 260 | (cvs-parsed-fileinfo 'DEAD file)) | ||
| 261 | |||
| 262 | ;; [add] | ||
| 263 | (and | ||
| 264 | (cvs-or | ||
| 265 | (cvs-match "scheduling file `\\(.*\\)' for addition.*$" (path 1)) | ||
| 266 | (cvs-match "re-adding file \\(.*\\) (in place of .*)$" (path 1))) | ||
| 267 | (cvs-parsed-fileinfo 'ADDED path)) | ||
| 268 | |||
| 269 | ;; [add] this will also show up as a `U <file>' | ||
| 270 | (and | ||
| 271 | (cvs-match "\\(.*\\), version \\(.*\\), resurrected$" | ||
| 272 | (path 1) (base-rev 2)) | ||
| 273 | (cvs-parsed-fileinfo '(UP-TO-DATE . RESURRECTED) path nil | ||
| 274 | :base-rev base-rev)) | ||
| 275 | |||
| 276 | ;; [remove] | ||
| 277 | (and | ||
| 278 | (cvs-match "removed `\\(.*\\)'$" (path 1)) | ||
| 279 | (cvs-parsed-fileinfo 'DEAD path)) | ||
| 280 | |||
| 281 | ;; [remove,merge] | ||
| 282 | (and | ||
| 283 | (cvs-match "scheduling `\\(.*\\)' for removal$" (file 1)) | ||
| 284 | (cvs-parsed-fileinfo 'REMOVED file)) | ||
| 285 | |||
| 286 | ;; [update] File removed by you, but not cvs rm'd | ||
| 287 | (and | ||
| 288 | (cvs-match "warning: \\(.*\\) was lost$" (path 1)) | ||
| 289 | (cvs-match (concat "U " (regexp-quote path) "$")) | ||
| 290 | (cvs-parsed-fileinfo (if dont-change-disc | ||
| 291 | 'MISSING | ||
| 292 | '(UP-TO-DATE . UPDATED)) | ||
| 293 | path)) | ||
| 294 | |||
| 295 | ;; Mode conflicts (rather than contents) | ||
| 296 | (and | ||
| 297 | (cvs-match "conflict: ") | ||
| 298 | (cvs-or | ||
| 299 | (cvs-match "removed \\(.*\\) was modified by second party$" | ||
| 300 | (path 1) (subtype 'REMOVED)) | ||
| 301 | (cvs-match "\\(.*\\) created independently by second party$" | ||
| 302 | (path 1) (subtype 'ADDED)) | ||
| 303 | (cvs-match "\\(.*\\) is modified but no longer in the repository$" | ||
| 304 | (path 1) (subtype 'MODIFIED))) | ||
| 305 | (cvs-match (concat "C " (regexp-quote path))) | ||
| 306 | (cvs-parsed-fileinfo (cons 'CONFLICT subtype) path)) | ||
| 307 | |||
| 308 | ;; Messages that should be shown to the user | ||
| 309 | (and | ||
| 310 | (cvs-or | ||
| 311 | (cvs-match "move away \\(.*\\); it is in the way$" (file 1)) | ||
| 312 | (cvs-match "warning: new-born \\(.*\\) has disappeared$" (file 1)) | ||
| 313 | (cvs-match "sticky tag .* for file `\\(.*\\)' is not a branch$" | ||
| 314 | (file 1))) | ||
| 315 | (cvs-parsed-fileinfo 'MESSAGE file)) | ||
| 316 | |||
| 317 | ;; File unknown. | ||
| 318 | (and (cvs-match "use `.+ add' to create an entry for \\(.*\\)$" (path 1)) | ||
| 319 | (cvs-parsed-fileinfo 'UNKNOWN path)) | ||
| 320 | |||
| 321 | ;; We use cvs-execute-multi-dir but cvs can't handle it | ||
| 322 | ;; Probably because the cvs-client can but the cvs-server can't | ||
| 323 | (and (cvs-match ".* files with '?/'? in their name.*$") | ||
| 324 | (not cvs-execute-single-dir) | ||
| 325 | (setq cvs-execute-single-dir t) | ||
| 326 | (cvs-create-fileinfo | ||
| 327 | 'MESSAGE "" " " | ||
| 328 | "*** Add (setq cvs-execute-single-dir t) to your .emacs *** | ||
| 329 | See the FAQ file or the variable's documentation for more info.")) | ||
| 330 | |||
| 331 | ;; Cvs waits for a lock. Ignored: already handled by the process filter | ||
| 332 | (cvs-match "\\[..:..:..\\] \\(waiting for\\|obtained\\) .*lock in .*$") | ||
| 333 | ;; File you removed still exists. Ignore (will be noted as removed). | ||
| 334 | (cvs-match ".* should be removed and is still there$") | ||
| 335 | ;; just a note | ||
| 336 | (cvs-match "use '.+ commit' to \\sw+ th\\sw+ files? permanently$") | ||
| 337 | ;; [add,status] followed by a more complete status description anyway | ||
| 338 | (cvs-match "nothing known about .*$") | ||
| 339 | ;; [update] problem with patch | ||
| 340 | (cvs-match "checksum failure after patch to .*; will refetch$") | ||
| 341 | (cvs-match "refetching unpatchable files$") | ||
| 342 | ;; [commit] | ||
| 343 | (cvs-match "Rebuilding administrative file database$") | ||
| 344 | |||
| 345 | ;; CVS is running a *info program. | ||
| 346 | (and | ||
| 347 | (cvs-match "Executing.*$") | ||
| 348 | ;; Skip by any output the program may generate to stdout. | ||
| 349 | ;; Note that pcl-cvs will get seriously confused if the | ||
| 350 | ;; program prints anything to stderr. | ||
| 351 | (re-search-forward cvs-update-prog-output-skip-regexp)))) | ||
| 352 | |||
| 353 | (and | ||
| 354 | (cvs-match "cvs[.ex]* \\[[a-z]+ aborted\\]:.*$") | ||
| 355 | (cvs-parsed-fileinfo 'MESSAGE "")) | ||
| 356 | |||
| 357 | ;; sadly you can't do much with these since the path is in the repository | ||
| 358 | (cvs-match "Directory .* added to the repository$") | ||
| 359 | ))) | ||
| 360 | |||
| 361 | |||
| 362 | (defun cvs-parse-merge () | ||
| 363 | (let (path base-rev head-rev handled type) | ||
| 364 | ;; A merge (maybe with a conflict). | ||
| 365 | (and | ||
| 366 | (cvs-match "RCS file: .*$") | ||
| 367 | ;; Squirrel away info about the files that were retrieved for merging | ||
| 368 | (cvs-match "retrieving revision \\([0-9.]+\\)$" (base-rev 1)) | ||
| 369 | (cvs-match "retrieving revision \\([0-9.]+\\)$" (head-rev 1)) | ||
| 370 | (cvs-match "Merging differences between [0-9.]+ and [0-9.]+ into \\(.*\\)$" | ||
| 371 | (path 1)) | ||
| 372 | |||
| 373 | ;; eat up potential conflict warnings | ||
| 374 | (cvs-or (cvs-match "\\(rcs\\)?merge:?\\( warning\\)?: \\(overlaps\\|conflicts\\) \\(or other problems \\)?during merge$" (type 'CONFLICT)) t) | ||
| 375 | (cvs-or | ||
| 376 | (and | ||
| 377 | (cvs-match "cvs[.ex]* [a-z]+: ") | ||
| 378 | (cvs-or | ||
| 379 | (cvs-match "conflicts found in \\(.*\\)$" (path 1) (type 'CONFLICT)) | ||
| 380 | (cvs-match "could not merge .*$") | ||
| 381 | (cvs-match "restoring \\(.*\\) from backup file .*$" (path 1)))) | ||
| 382 | t) | ||
| 383 | |||
| 384 | ;; Is it a succesful merge? | ||
| 385 | ;; Figure out result of merging (ie, was there a conflict?) | ||
| 386 | (let ((qfile (regexp-quote path))) | ||
| 387 | (cvs-or | ||
| 388 | ;; Conflict | ||
| 389 | (and | ||
| 390 | (cvs-match (concat "C \\(.*" qfile "\\)$") (path 1) (type 'CONFLICT)) | ||
| 391 | ;; C might be followed by a "suprious" U for non-mergeable files | ||
| 392 | (cvs-or (cvs-match (concat "U \\(.*" qfile "\\)$")) t)) | ||
| 393 | ;; Successful merge | ||
| 394 | (cvs-match (concat "M \\(.*" qfile "\\)$") (path 1)) | ||
| 395 | ;; The file already contained the modifications | ||
| 396 | (cvs-match (concat "^\\(.*" qfile | ||
| 397 | "\\) already contains the differences between .*$") | ||
| 398 | (path 1) (type '(UP-TO-DATE . MERGED))) | ||
| 399 | t) | ||
| 400 | (cvs-parsed-fileinfo (if dont-change-disc 'NEED-MERGE | ||
| 401 | (or type '(MODIFIED . MERGED))) path nil | ||
| 402 | :merge (cons base-rev head-rev)))))) | ||
| 403 | |||
| 404 | (defun cvs-parse-status () | ||
| 405 | (let (nofile path base-rev head-rev type) | ||
| 406 | (and | ||
| 407 | (cvs-match | ||
| 408 | "===================================================================$") | ||
| 409 | (cvs-match "File: \\(no file \\)?\\(.*[^ \t]\\)[ \t]+Status: " | ||
| 410 | (nofile 1) (path 2)) | ||
| 411 | (cvs-or | ||
| 412 | (cvs-match "Needs \\(Checkout\\|Patch\\)$" | ||
| 413 | (type (if nofile 'MISSING 'NEED-UPDATE))) | ||
| 414 | (cvs-match "Up-to-date$" | ||
| 415 | (type (if nofile '(UP-TO-DATE . REMOVED) 'UP-TO-DATE))) | ||
| 416 | (cvs-match ".*[Cc]onflict.*$" (type 'CONFLICT)) | ||
| 417 | (cvs-match "Locally Added$" (type 'ADDED)) | ||
| 418 | (cvs-match "Locally Removed$" (type 'REMOVED)) | ||
| 419 | (cvs-match "Locally Modified$" (type 'MODIFIED)) | ||
| 420 | (cvs-match "Needs Merge$" (type 'NEED-MERGE)) | ||
| 421 | (cvs-match "Unknown$" (type 'UNKNOWN))) | ||
| 422 | (cvs-match "$") | ||
| 423 | (cvs-or | ||
| 424 | (cvs-match " *Version:[ \t]*\\([0-9.]+\\).*$" (base-rev 1)) | ||
| 425 | ;; NOTE: there's no date on the end of the following for server mode... | ||
| 426 | (cvs-match " *Working revision:[ \t]*-?\\([0-9.]+\\).*$" (base-rev 1)) | ||
| 427 | ;; Let's not get all worked up if the format changes a bit | ||
| 428 | (cvs-match " *Working revision:.*$")) | ||
| 429 | (cvs-or | ||
| 430 | (cvs-match " *RCS Version:[ \t]*\\([0-9.]+\\)[ \t]*.*$" (head-rev 1)) | ||
| 431 | (cvs-match " *Repository revision:[ \t]*\\([0-9.]+\\)[ \t]*\\(.*\\)$" | ||
| 432 | (head-rev 1)) | ||
| 433 | (cvs-match " *Repository revision:.*")) | ||
| 434 | (cvs-or | ||
| 435 | (and;;sometimes those fields are missing | ||
| 436 | (cvs-match " *Sticky Tag:[ \t]*\\(.*\\)$") ; FIXME: use it | ||
| 437 | (cvs-match " *Sticky Date:[ \t]*\\(.*\\)$") ; FIXME: use it | ||
| 438 | (cvs-match " *Sticky Options:[ \t]*\\(.*\\)$")) ; FIXME: use it | ||
| 439 | t) | ||
| 440 | (cvs-match "$") | ||
| 441 | ;; ignore the tags-listing in the case of `status -v' | ||
| 442 | (cvs-or (cvs-match " *Existing Tags:\n\\(\t.*\n\\)*$") t) | ||
| 443 | (cvs-parsed-fileinfo type path nil | ||
| 444 | :base-rev base-rev | ||
| 445 | :head-rev head-rev)))) | ||
| 446 | |||
| 447 | (defun cvs-parse-commit () | ||
| 448 | (let (path base-rev subtype) | ||
| 449 | (cvs-or | ||
| 450 | |||
| 451 | (and | ||
| 452 | (cvs-match "\\(Checking in\\|Removing\\) \\(.*\\);$" (path 2)) | ||
| 453 | (cvs-match ".*,v <-- .*$") | ||
| 454 | (cvs-or | ||
| 455 | ;; deletion | ||
| 456 | (cvs-match "new revision: delete; previous revision: \\([0-9.]*\\)$" | ||
| 457 | (subtype 'REMOVED) (base-rev 1)) | ||
| 458 | ;; addition | ||
| 459 | (cvs-match "initial revision: \\([0-9.]*\\)$" | ||
| 460 | (subtype 'ADDED) (base-rev 1)) | ||
| 461 | ;; update | ||
| 462 | (cvs-match "new revision: \\([0-9.]*\\); previous revision: .*$" | ||
| 463 | (subtype 'COMMITTED) (base-rev 1))) | ||
| 464 | (cvs-match "done$") | ||
| 465 | ;; it's important here not to rely on the default directory management | ||
| 466 | ;; because `cvs commit' might begin by a series of Examining messages | ||
| 467 | ;; so the processing of the actual checkin messages might begin with | ||
| 468 | ;; a `current-dir' set to something different from "" | ||
| 469 | (cvs-parsed-fileinfo (cons 'UP-TO-DATE subtype) path 'trust | ||
| 470 | :base-rev base-rev)) | ||
| 471 | |||
| 472 | ;; useless message added before the actual addition: ignored | ||
| 473 | (cvs-match "RCS file: .*\ndone$")))) | ||
| 474 | |||
| 475 | |||
| 476 | (provide 'pcvs-parse) | ||
| 477 | |||
| 478 | ;;; pcl-cvs-parse.el ends here | ||