Mercurial > hg > xemacs-beta
comparison lisp/packages/generic-sc.el @ 155:43dd3413c7c7 r20-3b4
Import from CVS: tag r20-3b4
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:39:39 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
154:94141801dd7e | 155:43dd3413c7c7 |
---|---|
1 ;;; generic-sc.el --- generic interface to source control systems | |
2 | |
3 ;; Copyright (C) 1992, 1993, 1994, 1997 Free Software Foundation, Inc. | |
4 | |
5 ;; Author: devin@lucid.com | |
6 ;; Maintainer: Unmaintained | |
7 ;; Keywords: tools, unix | |
8 | |
9 ;; This file is part of XEmacs. | |
10 | |
11 ;; XEmacs is free software; you can redistribute it and/or modify it | |
12 ;; under the terms of the GNU General Public License as published by | |
13 ;; the Free Software Foundation; either version 2, or (at your option) | |
14 ;; any later version. | |
15 | |
16 ;; XEmacs is distributed in the hope that it will be useful, but | |
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 ;; General Public License for more details. | |
20 | |
21 ;; You should have received a copy of the GNU General Public License | |
22 ;; along with XEmacs; see the file COPYING. If not, write to the | |
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
24 ;; Boston, MA 02111-1307, USA. | |
25 | |
26 ;;; Synched up with: Not in FSF. | |
27 | |
28 ;;; Commentary: | |
29 | |
30 ;; The generic interface provide a common set of functions that can be | |
31 ;; used to interface with a source control system like SCCS, RCS or | |
32 ;; CVS. | |
33 ;; | |
34 ;; You chose which source control system to use by calling sc-mode | |
35 ;; | |
36 ;; The module is based on the sccs.el mode of Eric S. Raymond | |
37 ;; (eric@snark.thyrsus.com) which was distantly derived from an rcs | |
38 ;; mode written by Ed Simpson ({decvax, seismo}!mcnc!duke!dukecdu!evs) | |
39 ;; in years gone by and revised at MIT's Project Athena. | |
40 | |
41 ;;; Code: | |
42 | |
43 ;; This can be customized by the user | |
44 | |
45 (defgroup generic-sc nil | |
46 "Generic interface to source control systems" | |
47 :prefix "sc-" | |
48 :group 'tools) | |
49 | |
50 | |
51 (defcustom sc-diff-command '("diff") | |
52 "*The command/flags list to be used in constructing diff commands." | |
53 :type '(repeat string) | |
54 :group 'generic-sc) | |
55 | |
56 ;; Duplicated from pcl-cvs. | |
57 (defvar cvs-program "cvs" | |
58 "*The command name of the cvs program.") | |
59 | |
60 (defcustom sc-mode-expert () | |
61 "*Treat user as expert; suppress yes-no prompts on some things." | |
62 :type 'boolean | |
63 :group 'generic-sc) | |
64 | |
65 (defcustom sc-max-log-size 510 | |
66 "*Maximum allowable size of a source control log message." | |
67 :type 'integer | |
68 :group 'generic-sc) | |
69 | |
70 (defcustom sc-ccase-comment-on '(checkout checkout-dir checkin-dir rename | |
71 new-brtype new-branch checkin-merge | |
72 create-label label-sources) | |
73 "*Operations on which comments would be appreciated. | |
74 We check the values checkout, checkout-dir, checkin-dir, | |
75 rename, new-brtype, new-branch, create-label, | |
76 and label-sources as symbols." | |
77 :type '(repeat symbol) | |
78 :group 'generic-sc) | |
79 | |
80 (defvar sc-ccase-reserve nil | |
81 "Whether to reserve checkouts or not. By default, this is nil - don't. | |
82 Other values are t - do, and anything else, eg. 'ask - ask.") | |
83 | |
84 ;; default keybindings | |
85 (defvar sc-prefix-map (lookup-key global-map "\C-xv")) | |
86 (if (not (keymapp sc-prefix-map)) | |
87 (progn | |
88 (setq sc-prefix-map (make-sparse-keymap)) | |
89 (define-key global-map "\C-xv" sc-prefix-map) | |
90 (define-key sc-prefix-map "v" 'sc-next-operation) | |
91 (define-key sc-prefix-map "=" 'sc-show-changes) | |
92 (define-key sc-prefix-map "l" 'sc-show-history) | |
93 (define-key sc-prefix-map "p" 'sc-visit-previous-revision) | |
94 (define-key sc-prefix-map "u" 'sc-revert-file) | |
95 (define-key sc-prefix-map "d" 'sc-list-registered-files) | |
96 (define-key sc-prefix-map "\C-d" 'sc-update-directory) | |
97 (define-key sc-prefix-map "\C-r" 'sc-rename-file) | |
98 )) | |
99 | |
100 | |
101 ;;; The user does not change these | |
102 (defvar sc-generic-name "" | |
103 "Name of the source control system used. Is displayed in the modeline.") | |
104 | |
105 (defvar sc-mode-line-string () | |
106 "Revision number to show in the mode line") | |
107 | |
108 (defvar sc-generic-log-buf () | |
109 "Buffer for entering log message") | |
110 | |
111 (defvar sc-log-entry-keymap () | |
112 "Additional keybindings used when entering the log message") | |
113 | |
114 (defvar sc-can-hack-dir () | |
115 "Does the SC system allow users to play directly with directories") | |
116 | |
117 (defvar sc-ccase-mfs-prefixes () | |
118 "Prefixes known to the system to be MFS ... ignore all others") | |
119 | |
120 (defmacro sc-chmod (perms file) | |
121 (list 'call-process "chmod" nil nil nil perms file)) | |
122 | |
123 (defmacro error-occurred (&rest body) | |
124 (list 'condition-case nil (cons 'progn (append body '(nil))) '(error t))) | |
125 | |
126 | |
127 ;;; User level functions | |
128 (defun sc-next-operation (verbose) | |
129 "Do the next logical source-control operation on the file in the current buffer. | |
130 The current subdirectory must be under source control. | |
131 If the file is not already registered with the source control, this registers it | |
132 and checks it out. | |
133 If the file is registered and not locked by anyone, this checks it out. | |
134 If the file is registered and locked by the calling user, this pops up a | |
135 buffer for creation of a log message, then checks the file in. | |
136 A read-only copy of the changed file is left in place afterwards. | |
137 If the file is registered and locked by someone else, an error message is | |
138 returned indicating who has locked it." | |
139 (interactive "P") | |
140 (if (not buffer-file-name) | |
141 (error "There is no file associated with buffer %s" (buffer-name))) | |
142 (let* (revision | |
143 (file buffer-file-name) | |
144 (lock-info (sc-lock-info file)) | |
145 (sc-generic-log-buf | |
146 (get-buffer-create (format "*%s-Log*" sc-generic-name)))) | |
147 (if (eq lock-info 'na) | |
148 (error "The file associated with buffer %s is not registered" (buffer-name))) | |
149 | |
150 ;; if file is not registered register it and set lock-info to show it's not locked | |
151 (if (not lock-info) | |
152 (progn | |
153 (sc-register-file verbose) | |
154 (setq lock-info (list () ())))) | |
155 | |
156 (cond ((not (car lock-info)) | |
157 ;; if there is no lock on the file, assert one and get it | |
158 (sc-check-out file t) | |
159 (revert-buffer nil t) | |
160 (sc-mode-line)) | |
161 | |
162 ((and (not (equal sc-generic-name "CCase")) | |
163 (not (equal (car lock-info) (user-login-name)))) | |
164 ;; file is locked by someone else | |
165 (error "Sorry, %s has that file locked." (car lock-info))) | |
166 | |
167 (t | |
168 ;; OK, user owns the lock on the file | |
169 ;; if so, give user a chance to save before delta-ing. | |
170 (if (and (buffer-modified-p) | |
171 (or | |
172 sc-mode-expert | |
173 (y-or-n-p (format "%s has been modified. Write it out? " | |
174 (buffer-name))))) | |
175 (save-buffer)) | |
176 | |
177 (setq revision (car (cdr lock-info))) | |
178 | |
179 ;; user may want to set nonstandard parameters | |
180 (if verbose | |
181 (if (or sc-mode-expert | |
182 (y-or-n-p | |
183 (format "revision: %s Change revision level? " | |
184 revision))) | |
185 (setq revision (read-string "New revision level: ")))) | |
186 | |
187 ;; OK, let's do the delta | |
188 (let ((buffer (sc-temp-buffer))) | |
189 (if (save-window-excursion | |
190 ;; this excursion returns t if the new version was saved OK | |
191 (pop-to-buffer buffer) | |
192 (erase-buffer) | |
193 (set-buffer-modified-p nil) | |
194 (sc-log-entry-mode) | |
195 (message | |
196 "Enter log message. Type C-c C-c when done, C-c ? for help.") | |
197 (prog1 | |
198 (and (not (error-occurred (recursive-edit))) | |
199 (not (error-occurred | |
200 (sc-check-in file revision | |
201 (buffer-string))))) | |
202 (setq buffer-file-name nil) | |
203 (bury-buffer buffer))) | |
204 | |
205 ;; if the save went OK do some post-checking | |
206 (if (buffer-modified-p) | |
207 (error | |
208 "Checked-in version of file does not match buffer!") | |
209 (revert-buffer nil t) | |
210 (sc-mode-line) | |
211 (run-hooks 'sc-check-in-ok)))))))) | |
212 | |
213 (defun sc-insert-last-log () | |
214 "Insert the log message of the last check in at point." | |
215 (interactive) | |
216 (insert-buffer sc-generic-log-buf)) | |
217 | |
218 (defun sc-abort-check-in () | |
219 "Abort a source control check-in command." | |
220 (interactive) | |
221 (if (or sc-mode-expert (y-or-n-p "Really Abort Check-in? ")) | |
222 (progn | |
223 (delete-window) | |
224 (abort-recursive-edit)))) | |
225 | |
226 (defun sc-log-exit () | |
227 "Proceed with checkin with the contents of the current buffer as message." | |
228 (interactive) | |
229 (if (< (buffer-size) sc-max-log-size) | |
230 (progn | |
231 (copy-to-buffer sc-generic-log-buf (point-min) (point-max)) | |
232 (exit-recursive-edit) | |
233 (delete-window)) | |
234 (goto-char sc-max-log-size) | |
235 (error | |
236 "Log must be less than %d characters. Point is now at char %d." | |
237 sc-max-log-size (point)))) | |
238 | |
239 | |
240 ;;; Functions to look at the edit history | |
241 (defun sc-show-changes (arg) | |
242 "Compare the version being edited with the last checked-in revision. | |
243 With a prefix argument prompt for revision to compare with." | |
244 (interactive "P") | |
245 ;; check that the file is not modified | |
246 (if (and (buffer-modified-p) | |
247 (or | |
248 sc-mode-expert | |
249 (y-or-n-p (format "%s has been modified. Write it out? " | |
250 (buffer-name))))) | |
251 (save-buffer)) | |
252 (let* ((revision (and arg (read-string "Revision to compare against: "))) | |
253 (file buffer-file-name) | |
254 (name (file-name-nondirectory file)) | |
255 (old (sc-get-version-in-temp-file file revision)) | |
256 (buffer (sc-temp-buffer)) | |
257 status) | |
258 (save-excursion | |
259 (set-buffer buffer) | |
260 (erase-buffer) | |
261 (setq default-directory (file-name-directory file)) | |
262 (setq status | |
263 (apply 'call-process (car sc-diff-command) () t () | |
264 (append (cdr sc-diff-command) (list old) (list file))))) | |
265 (if (not (or (eq 0 status) (eq 1 status))) ; see man diff.1 | |
266 (progn | |
267 (display-buffer buffer) | |
268 (error "diff FAILED"))) | |
269 (delete-file old) | |
270 (save-excursion | |
271 (set-buffer buffer) | |
272 (goto-char (point-min)) | |
273 (if (equal (point-min) (point-max)) | |
274 (insert | |
275 (format "No changes to %s since last update." | |
276 (file-name-nondirectory file))) | |
277 (insert "==== Diffs for " file "\n") | |
278 (insert "==== ") | |
279 (mapcar '(lambda (i) (insert i " ")) sc-diff-command) | |
280 (insert name "<" (or revision "current") ">" " " name "\n\n"))) | |
281 (display-buffer buffer))) | |
282 | |
283 (defun sc-show-revision-changes () | |
284 "Prompt for a revision to diff against." | |
285 (interactive) | |
286 (sc-show-changes 4)) | |
287 | |
288 (defun sc-version-diff-file (file rel1 rel2) | |
289 "For FILE, report diffs between two revisions REL1 and REL2 of it." | |
290 (interactive "fFile: \nsOlder version: \nsNewer version: ") | |
291 (if (string-equal rel1 "") (setq rel1 nil)) | |
292 (if (string-equal rel2 "") (setq rel2 nil)) | |
293 (let ((buffer (sc-temp-buffer))) | |
294 (set-buffer buffer) | |
295 (erase-buffer) | |
296 (let ((v1 (sc-get-version-in-temp-file file rel1)) | |
297 (v2 (if rel2 (sc-get-version-in-temp-file file rel2) file))) | |
298 (and v1 | |
299 v2 | |
300 (unwind-protect | |
301 (apply 'call-process (car sc-diff-command) nil t t | |
302 (append (cdr sc-diff-command) (list v1) (list v2))))) | |
303 (condition-case () (delete-file v1) (error nil)) | |
304 (if rel2 | |
305 (condition-case () (delete-file v2) (error nil))) | |
306 (set-buffer-modified-p nil) | |
307 (goto-char (point-min)) | |
308 (if (equal (point-min) (point-max)) | |
309 (message | |
310 (format "No changes to %s between %s and %s." file rel1 rel2)) | |
311 (display-buffer buffer))))) | |
312 | |
313 (defun sc-show-history () | |
314 "List the edit history of the current buffer." | |
315 (interactive) | |
316 (let ((file buffer-file-name)) | |
317 (if (not file) | |
318 (error "There is no file associated with buffer %s" (buffer-name))) | |
319 (if (not (sc-lock-info file)) | |
320 (error "The file is not registered in the source control system")) | |
321 (let ((buffer (sc-temp-buffer))) | |
322 (save-excursion | |
323 (set-buffer buffer) | |
324 (erase-buffer) | |
325 (sc-history file) | |
326 (goto-char (point-min))) | |
327 (display-buffer buffer)))) | |
328 | |
329 (defun sc-visit-previous-revision (revision) | |
330 "Show a previous revision of the current file" | |
331 (interactive "sShow previous revision number: ") | |
332 (let ((file buffer-file-name)) | |
333 (if (not file) | |
334 (error "There is no file associated with buffer %s" (buffer-name))) | |
335 (let ((other-file (sc-get-version-in-temp-file file revision)) | |
336 (buffer-name (concat (file-name-nondirectory file) | |
337 "<" sc-generic-name " " revision ">"))) | |
338 (pop-to-buffer (get-buffer-create buffer-name)) | |
339 (erase-buffer) | |
340 (insert-file other-file) | |
341 ;; get the same major mode as the original file | |
342 (setq buffer-file-name file) | |
343 (normal-mode) | |
344 (setq buffer-file-name ()) | |
345 (set-buffer-modified-p ()) | |
346 (toggle-read-only) | |
347 (delete-file other-file)))) | |
348 | |
349 (defun sc-revert-file () | |
350 "Revert the current buffer's file back to the last saved version." | |
351 (interactive) | |
352 (let ((file buffer-file-name)) | |
353 (if (y-or-n-p (format "Revert file %s to last checked-in revision?" file)) | |
354 (progn | |
355 (sc-revert file) | |
356 (revert-buffer nil t) | |
357 (sc-mode-line))))) | |
358 | |
359 ;; Functions to get directory level information | |
360 | |
361 (defun sc-list-all-locked-files (arg) | |
362 "List all files currently locked under the revision control system. | |
363 With prefix arg list only the files locked by the user." | |
364 (interactive "P") | |
365 (let* ((locker (and arg (user-login-name))) | |
366 (buffer (sc-tree-walk 'sc-list-file-if-locked locker))) | |
367 (save-excursion | |
368 (set-buffer buffer) | |
369 (goto-char (point-min)) | |
370 (if (= (point-min) (point-max)) | |
371 (insert "No files locked ") | |
372 (insert "Files locked ")) | |
373 (if locker | |
374 (insert "by " locker " ")) | |
375 (insert "in " default-directory "\n\n")) | |
376 (display-buffer buffer))) | |
377 | |
378 (defun sc-list-locked-files () | |
379 "List all files currently locked by me" | |
380 (interactive) | |
381 (sc-list-all-locked-files 4)) | |
382 | |
383 (defun sc-list-registered-files () | |
384 "List all files currently registered under the revision control system." | |
385 (interactive) | |
386 (let ((buffer (sc-tree-walk 'sc-list-file))) | |
387 (save-excursion | |
388 (set-buffer buffer) | |
389 (if (= (point-min) (point-max)) | |
390 (insert "No files registered in " sc-generic-name | |
391 " in " default-directory) | |
392 (goto-char (point-min)) | |
393 (insert "Files registered in " sc-generic-name " in " default-directory | |
394 "\n\n"))) | |
395 (display-buffer buffer))) | |
396 | |
397 (defun sc-update-directory () | |
398 "Updates the current directory by getting the latest copies of the files" | |
399 (interactive) | |
400 (save-some-buffers) | |
401 (let ((buffer (sc-tree-walk 'sc-update-file))) | |
402 (save-excursion | |
403 (set-buffer buffer) | |
404 (goto-char (point-min)) | |
405 (if (= (point-min) (point-max)) | |
406 (insert "No files needed to be updated in " default-directory "\n\n") | |
407 (insert "Files updated in " default-directory "\n\n"))) | |
408 (display-buffer buffer))) | |
409 | |
410 ;; Miscellaneous other entry points | |
411 | |
412 (defun sc-register-file (verbose) | |
413 "Register the file visited by the current buffer into source control. | |
414 Prefix argument register it under an explicit revision number." | |
415 (interactive "P") | |
416 (let ((file buffer-file-name)) | |
417 (if (not file) | |
418 (error "There is no file associated with buffer %s" (buffer-name))) | |
419 (let ((lock-info (sc-lock-info file)) | |
420 (revision ())) | |
421 (if lock-info | |
422 (error "This file is already registered into %s" sc-generic-name)) | |
423 ;; propose to save the file if it's modified | |
424 (if (and (buffer-modified-p) | |
425 (or | |
426 sc-mode-expert | |
427 (y-or-n-p (format "%s has been modified. Write it out? " | |
428 (buffer-name))))) | |
429 (save-buffer)) | |
430 ;; get the revision number | |
431 (if verbose | |
432 (setq revision (read-string "Initial Revision Number: "))) | |
433 (sc-register file revision) | |
434 (revert-buffer nil t) | |
435 (sc-mode-line)))) | |
436 | |
437 (defun sc-rename-file (old new) | |
438 "Rename a file, taking its source control archive with it." | |
439 (interactive "fOld name: \nFNew name: ") | |
440 (let ((owner (sc-locking-user old))) | |
441 (if (and owner (not (string-equal owner (user-login-name)))) | |
442 (error "Sorry, %s has that file checked out" owner))) | |
443 (if sc-can-hack-dir | |
444 (rename-file old new t)) | |
445 (sc-rename old new)) | |
446 | |
447 (defun sc-rename-this-file (new) | |
448 "Rename the file of the current buffer, taking its source control archive with it" | |
449 (interactive "FNew name: ") | |
450 (if (and (buffer-modified-p) | |
451 (y-or-n-p (format "%s has been modified. Write it out? " | |
452 (buffer-name)))) | |
453 (save-buffer)) | |
454 (sc-rename-file buffer-file-name new) | |
455 (let ((old-buffer (current-buffer)) | |
456 (new-buffer (find-file-noselect new))) | |
457 (set-window-buffer (selected-window) new-buffer) | |
458 (pop-to-buffer (current-buffer)) | |
459 (bury-buffer old-buffer))) | |
460 | |
461 | |
462 ;;; Mode independent functions | |
463 ;;; All those sc-... functions FUNCALL the corresponding sc-generic-... function. | |
464 ;;; The variables are set to functions that do the SCCS, RCS or CVS commands | |
465 ;;; depending on the mode chosen. | |
466 | |
467 (defvar sc-generic-lock-info () | |
468 "Function to implement sc-lock-info") | |
469 | |
470 (defun sc-lock-info (file) | |
471 "Return a list of the current locker and current locked revision for FILE. | |
472 Returns NIL if FILE is not registered in the source control system. | |
473 Return (NIL NIL) if FILE is registered but not locked. | |
474 Return (locker revision) if file is locked." | |
475 (funcall sc-generic-lock-info file)) | |
476 | |
477 | |
478 (defvar sc-generic-register () | |
479 "Function to implement sc-register") | |
480 | |
481 (defun sc-register (file revision) | |
482 "Register FILE under source control with initial revision REVISION." | |
483 (funcall sc-generic-register file revision)) | |
484 | |
485 | |
486 (defvar sc-generic-check-out () | |
487 "Function to implement sc-check-out") | |
488 | |
489 (defun sc-check-out (file lockp) | |
490 "Checks out the latest version of FILE. | |
491 If LOCKP is not NIL, FILE is also locked." | |
492 (funcall sc-generic-check-out file lockp)) | |
493 | |
494 | |
495 (defvar sc-generic-get-version () | |
496 "Function to implement sc-get-version") | |
497 | |
498 (defun sc-get-version (file buffer revision) | |
499 "Insert a previous revison of FILE in BUFFER. | |
500 REVISION is the revision number requested." | |
501 (funcall sc-generic-get-version file buffer revision)) | |
502 | |
503 | |
504 (defvar sc-generic-check-in () | |
505 "Function to implement sc-check-in") | |
506 | |
507 (defun sc-check-in (file revision message) | |
508 "Check in FILE with revision REVISION. | |
509 MESSAGE is a string describing the changes." | |
510 (funcall sc-generic-check-in file revision message)) | |
511 | |
512 | |
513 (defvar sc-generic-history () | |
514 "Function to implement sc-history") | |
515 | |
516 (defun sc-history (file) | |
517 "Insert the edit history of FILE in the current buffer." | |
518 (funcall sc-generic-history file)) | |
519 | |
520 | |
521 (defvar sc-generic-tree-list () | |
522 "Function to implement sc-tree-list") | |
523 | |
524 (defun sc-tree-list () | |
525 "List in the current buffer the files registered in the source control system" | |
526 (funcall sc-generic-tree-list)) | |
527 | |
528 | |
529 (defvar sc-generic-new-revision-p () | |
530 "Function to implement sc-new-revision-p") | |
531 | |
532 (defun sc-new-revision-p (file) | |
533 "True if a new revision of FILE was checked in since we last got a copy of it" | |
534 (funcall sc-generic-new-revision-p file)) | |
535 | |
536 | |
537 (defvar sc-generic-revert () | |
538 "Function to implement sc-revert") | |
539 | |
540 (defun sc-revert (file) | |
541 "Cancel a check out of FILE and get back the latest checked in version" | |
542 (funcall sc-generic-revert file)) | |
543 | |
544 | |
545 (defvar sc-generic-rename () | |
546 "Function to implement sc-rename") | |
547 | |
548 (defun sc-rename (old new) | |
549 "Rename the source control archives for OLD to NEW" | |
550 (funcall sc-generic-rename old new)) | |
551 | |
552 | |
553 (defvar sc-menu () | |
554 "Menu to use") | |
555 | |
556 | |
557 ;;; Utilities functions | |
558 (defun sc-do-command (buffer message command file sc-file &rest flags) | |
559 "Execute a command, notifying the user and checking for errors." | |
560 (setq file (expand-file-name file)) | |
561 (message "Running %s on %s..." message file) | |
562 (let ((status | |
563 (save-excursion | |
564 (set-buffer (get-buffer-create buffer)) | |
565 (erase-buffer) | |
566 (setq flags (append flags (and file (list sc-file)))) | |
567 (setq flags (delq () flags)) | |
568 (let ((default-directory (file-name-directory (or file "./")))) | |
569 (eq (apply 'call-process command nil t nil flags) 0))))) | |
570 (if status | |
571 (message "Running %s...OK" message) | |
572 (save-excursion | |
573 (set-buffer buffer) | |
574 (goto-char (point-min)) | |
575 (insert command) | |
576 (mapcar '(lambda (i) (insert " " i)) flags) | |
577 (insert "\n\n") | |
578 (goto-char (point-min))) | |
579 (display-buffer buffer) | |
580 (error "Running %s...FAILED" message)))) | |
581 | |
582 (defun sc-enter-comment () | |
583 "Enter a comment. Return it as a string." | |
584 (let ((buffer (sc-temp-buffer))) | |
585 (setq sc-generic-log-buf | |
586 (get-buffer-create (format "*%s-Log*" sc-generic-name))) | |
587 (save-window-excursion | |
588 ;; this excursion returns t if the new version was saved OK | |
589 (pop-to-buffer buffer) | |
590 (erase-buffer) | |
591 (set-buffer-modified-p nil) | |
592 (sc-log-entry-mode) | |
593 (message | |
594 "Enter log message. Type C-c C-c when done, C-c ? for help.") | |
595 (prog1 | |
596 (and (not (error-occurred (recursive-edit))) | |
597 (let ((bs (buffer-string))) | |
598 (if (> (length bs) 0) bs))) | |
599 (setq buffer-file-name nil) | |
600 (bury-buffer buffer))))) | |
601 | |
602 (defun sc-locking-user (file) | |
603 "Return the login name of the locker of FILE. Return nil if FILE is not locked" | |
604 (car (sc-lock-info file))) | |
605 | |
606 (defun sc-locked-revision (file) | |
607 "Return the revision number currently locked for FILE, nil if FILE is not locked." | |
608 (car (cdr (sc-lock-info file)))) | |
609 | |
610 (defun sc-mode-line () | |
611 "Set the mode line for the current buffer. | |
612 FILE is the file being visited." | |
613 (let* ((file buffer-file-name) | |
614 (lock-info (sc-lock-info file))) | |
615 ;; ensure that the global mode string is not NIL | |
616 (or global-mode-string (setq global-mode-string '(""))) | |
617 ;; ensure that our variable is in the global-mode-string | |
618 (or (memq 'sc-mode-line-string global-mode-string) | |
619 (setq global-mode-string | |
620 (append global-mode-string '(sc-mode-line-string)))) | |
621 (make-local-variable 'sc-mode-line-string) | |
622 (setq sc-mode-line-string | |
623 (cond ((or | |
624 (eq lock-info 'na) | |
625 (null lock-info)) ()) | |
626 ((null (car lock-info)) | |
627 (format " <%s:>" sc-generic-name)) | |
628 ((equal (car lock-info) (user-login-name)) | |
629 (format " <%s: %s>" sc-generic-name (car (cdr lock-info)))) | |
630 (t | |
631 (format " <%s: %s>" sc-generic-name (car lock-info))))))) | |
632 | |
633 (defun sc-temp-buffer () | |
634 "Return a temporary buffer to use for output" | |
635 (get-buffer-create (format "*%s*" sc-generic-name))) | |
636 | |
637 (defun sc-tree-walk (func &rest args) | |
638 "Apply FUNC to the files registered in the source control system. | |
639 FUNC is passed the file path and ARGS." | |
640 (let* ((buffer-name (format "*%s directory*" sc-generic-name)) | |
641 (buffer (get-buffer-create buffer-name)) | |
642 (dir default-directory) | |
643 files) | |
644 ;; recreate the directory buffer in the right directory | |
645 (save-excursion | |
646 (set-buffer buffer) | |
647 (erase-buffer) | |
648 (setq default-directory dir) | |
649 ;; get a list of all the registered files | |
650 (sc-tree-list) | |
651 ;; remove the "not found" messages | |
652 (goto-char (point-min)) | |
653 (while (search-forward "not found" () t) | |
654 (beginning-of-line 1) | |
655 (kill-line 1)) | |
656 ;; check if any file is listed | |
657 (if (= (point-min) (point-max)) | |
658 (error "No registered files under %s" default-directory)) | |
659 ;; build the list of files | |
660 (goto-char (point-min)) | |
661 (setq files ()) | |
662 (while (not (eobp)) | |
663 (let ((file | |
664 (buffer-substring (point) (progn (end-of-line) (point))))) | |
665 (setq files (cons file files))) | |
666 (forward-line 1)) | |
667 (setq files (nreverse files)) | |
668 ;; let the function output information in the buffer | |
669 (erase-buffer)) | |
670 (display-buffer buffer) | |
671 ;; apply the function | |
672 (save-excursion | |
673 (set-buffer buffer) | |
674 (while files | |
675 (apply func (car files) args) | |
676 (setq files (cdr files))) | |
677 buffer))) | |
678 | |
679 (defun sc-get-version-in-temp-file (file revision) | |
680 "For the given FILE, retrieve a copy of the version with given REVISION. | |
681 The text is retrieved into a tempfile. Return the tempfile name." | |
682 (let* ((oldversion | |
683 (make-temp-name | |
684 (concat (or (ccase-protect-expanded-name revision) "current") | |
685 "-" | |
686 (file-name-nondirectory file) | |
687 "-"))) | |
688 (vbuf (get-buffer-create oldversion))) | |
689 (sc-get-version file vbuf revision) | |
690 (save-excursion | |
691 (set-buffer vbuf) | |
692 (write-region (point-min) (point-max) oldversion t 0)) | |
693 (kill-buffer vbuf) | |
694 (sc-chmod "-w" oldversion) | |
695 oldversion)) | |
696 | |
697 ;; Functions used to get directory level information | |
698 | |
699 (defun sc-insert-file-lock-info (file lock-info) | |
700 (insert (car lock-info) ":" (car (cdr lock-info))) | |
701 (indent-to-column 16 1) | |
702 (insert (file-name-nondirectory file) "\n")) | |
703 | |
704 (defun sc-list-file-if-locked (file &optional arg) | |
705 "List all files underneath the current directory matching a prefix type." | |
706 (let ((lock-info (sc-lock-info file))) | |
707 (if (and lock-info | |
708 (car lock-info) | |
709 (or (null arg) (equal arg (car lock-info)))) | |
710 (progn | |
711 (sc-insert-file-lock-info file lock-info) | |
712 (sit-for 0))))) | |
713 | |
714 (defun sc-list-file (file) | |
715 (let ((lock-info (sc-lock-info file))) | |
716 (cond ((eq lock-info 'na) | |
717 (indent-to-column 16 1) | |
718 (insert (file-name-nondirectory file) "\n")) | |
719 ((car lock-info) | |
720 (sc-insert-file-lock-info file lock-info)) | |
721 ((sc-new-revision-p file) | |
722 (insert "needs update") | |
723 (indent-to-column 16 1) | |
724 (insert (file-name-nondirectory file) "\n")) | |
725 (t | |
726 (indent-to-column 16 1) | |
727 (insert (file-name-nondirectory file) "\n"))) | |
728 (sit-for 0))) | |
729 | |
730 ;;; Function to update one file from the archive | |
731 (defun sc-update-file (file) | |
732 "get the latest version of the file if a new one was checked-in" | |
733 (if (sc-new-revision-p file) | |
734 (let ((file-name (file-name-nondirectory file))) | |
735 ;; get the latest copy | |
736 (rename-file (sc-get-version-in-temp-file file nil) file t) | |
737 (let ((b (get-file-buffer file))) | |
738 (if b | |
739 (save-excursion | |
740 (set-buffer b) | |
741 (revert-buffer nil t) | |
742 (sc-mode-line)))) | |
743 ;; show the file was updated | |
744 (insert "updated") | |
745 (indent-to-column 16 1) | |
746 (insert file-name "\n") | |
747 (sit-for 0)))) | |
748 | |
749 ;; Set up key bindings for use while editing log messages | |
750 | |
751 (if sc-log-entry-keymap | |
752 nil | |
753 (setq sc-log-entry-keymap (make-sparse-keymap)) | |
754 (define-key sc-log-entry-keymap "\C-ci" 'sc-insert-last-log) | |
755 (define-key sc-log-entry-keymap "\C-c\C-i" 'sc-insert-last-log) | |
756 (define-key sc-log-entry-keymap "\C-ca" 'sc-abort-check-in) | |
757 (define-key sc-log-entry-keymap "\C-c\C-a" 'sc-abort-check-in) | |
758 (define-key sc-log-entry-keymap "\C-c\C-c" 'sc-log-exit) | |
759 (define-key sc-log-entry-keymap "\C-x\C-s" 'sc-log-exit)) | |
760 | |
761 (defvar sc-mode-hook nil | |
762 "*Function or functions to run on entry to sc-mode.") | |
763 | |
764 (defvar sc-mode () | |
765 "The currently active source control mode. Use M-x sc-mode to set it") | |
766 | |
767 ;;;###autoload | |
768 (defun sc-mode (system) | |
769 "Toggle sc-mode. | |
770 SYSTEM can be sccs, rcs or cvs. | |
771 Cvs requires the pcl-cvs package. | |
772 | |
773 The following commands are available | |
774 \\[sc-next-operation] perform next logical source control operation on current file | |
775 \\[sc-show-changes] compare the version being edited with an older one | |
776 \\[sc-version-diff-file] compare two older versions of a file | |
777 \\[sc-show-history] display change history of current file | |
778 \\[sc-visit-previous-revision] display an older revision of current file | |
779 \\[sc-revert-file] revert buffer to last checked-in version | |
780 \\[sc-list-all-locked-files] show all files locked in current directory | |
781 \\[sc-list-locked-files] show all files locked by you in current directory | |
782 \\[sc-list-registered-files] show all files under source control in current directory | |
783 \\[sc-update-directory] get fresh copies of files checked-in by others in current directory | |
784 \\[sc-rename-file] rename the current file and its source control file | |
785 | |
786 | |
787 While you are entering a change log message for a check in, sc-log-entry-mode | |
788 will be in effect. | |
789 | |
790 Global user options: | |
791 sc-diff-command A list consisting of the command and flags | |
792 to be used for generating context diffs. | |
793 sc-mode-expert suppresses some conformation prompts, | |
794 notably for delta aborts and file saves. | |
795 sc-max-log-size specifies the maximum allowable size | |
796 of a log message plus one. | |
797 | |
798 | |
799 When using SCCS you have additional commands and options | |
800 | |
801 \\[sccs-insert-headers] insert source control headers in current file | |
802 | |
803 When you generate headers into a buffer using \\[sccs-insert-headers], | |
804 the value of sc-insert-headers-hook is called before insertion. If the | |
805 file is recognized a C or Lisp source, sc-insert-c-header-hook or | |
806 sc-insert-lisp-header-hook is called after insertion respectively. | |
807 | |
808 sccs-headers-wanted which %-keywords to insert when adding | |
809 headers with C-c h | |
810 sccs-insert-static if non-nil, keywords inserted in C files | |
811 get stuffed in a static string area so that | |
812 what(1) can see them in the compiled object code. | |
813 | |
814 When using CVS you have additional commands | |
815 | |
816 \\[sc-cvs-update-directory] update the current directory using pcl-cvs | |
817 \\[sc-cvs-file-status] show the CVS status of current file | |
818 " | |
819 (interactive | |
820 (if sc-mode | |
821 '(()) | |
822 (list | |
823 (intern | |
824 (read-string "Turn on source control mode on for: " "SCCS"))))) | |
825 (cond ((eq system ()) | |
826 (remove-hook 'find-file-hooks 'sc-mode-line) | |
827 (delete-menu-item (list sc-generic-name)) | |
828 (remove-hook 'activate-menubar-hook 'sc-sensitize-menu) | |
829 (setq sc-mode ())) | |
830 (sc-mode | |
831 (sc-mode ()) | |
832 (sc-mode system)) | |
833 (t | |
834 (setq system (intern (upcase (symbol-name system)))) | |
835 (let ((f (intern (format "sc-set-%s-mode" system)))) | |
836 (if (not (fboundp f)) | |
837 (error | |
838 "No source control interface for \"%s\". \ | |
839 Please use SCCS, RCS, CVS, or Atria." | |
840 system) | |
841 (funcall f) | |
842 (add-hook 'find-file-hooks 'sc-mode-line) | |
843 (add-submenu '() (cons sc-generic-name sc-menu)) | |
844 (add-hook 'activate-menubar-hook 'sc-sensitize-menu) | |
845 (run-hooks 'sc-mode-hook) | |
846 (setq sc-mode system)))))) | |
847 | |
848 (defun sc-log-entry-mode () | |
849 "Major mode for editing log message. | |
850 | |
851 These bindings are available when entering the log message | |
852 \\[sc-log-exit] proceed with check in, ending log message entry | |
853 \\[sc-insert-last-log] insert log message from last check-in | |
854 \\[sc-abort-check-in] abort this check-in | |
855 | |
856 Entry to the change-log submode calls the value of text-mode-hook, then | |
857 the value sc-log-entry-mode-hook. | |
858 " | |
859 (interactive) | |
860 (set-syntax-table text-mode-syntax-table) | |
861 (use-local-map sc-log-entry-keymap) | |
862 (setq local-abbrev-table text-mode-abbrev-table) | |
863 (setq major-mode 'sc-log-entry-mode) | |
864 (setq mode-name "Source Control Change Log Entry") | |
865 (run-hooks 'text-mode-hook 'sc-log-entry-mode-hook)) | |
866 | |
867 | |
868 | |
869 ;;; SCCS specific part | |
870 | |
871 ;; Find a reasonable default for the SCCS bin directory | |
872 (defvar sccs-bin-directory | |
873 (cond ((file-executable-p "/usr/sccs/unget") "/usr/sccs") | |
874 ((file-executable-p "/usr/bin/unget") "/usr/bin") | |
875 ((file-directory-p "/usr/sccs") "/usr/sccs") | |
876 ((file-directory-p "/usr/bin/sccs") "/usr/bin/sccs") | |
877 (t "/usr/bin")) | |
878 "*Directory where to find the sccs executables") | |
879 | |
880 (defvar sccs-headers-wanted '("\%\W\%") | |
881 "*SCCS header keywords to be inserted when sccs-insert-header is executed.") | |
882 | |
883 (defvar sccs-insert-static t | |
884 "*Insert a static character string when inserting source control headers in C mode. | |
885 Only relevant for the SCCS mode.") | |
886 | |
887 ;; Vars the user doesn't need to know about. | |
888 | |
889 (defvar sccs-log-entry-mode nil) | |
890 (defvar sccs-current-major-version nil) | |
891 | |
892 ;; Some helper functions | |
893 | |
894 (defun sccs-name (file &optional letter) | |
895 "Return the sccs-file name corresponding to a given file." | |
896 (if (null file) | |
897 () | |
898 (let ((expanded-file (expand-file-name file))) | |
899 (format "%sSCCS/%s.%s" | |
900 (concat (file-name-directory expanded-file)) | |
901 (or letter "s") | |
902 (concat (file-name-nondirectory expanded-file)))))) | |
903 | |
904 (defun sccs-lock-info (file) | |
905 "Lock-info method for SCCS. See sc-generic-lock-info" | |
906 (let ((sccs-file (sccs-name file "s")) | |
907 (lock-file (sccs-name file "p"))) | |
908 (cond ((or (null file) (not (file-exists-p sccs-file))) | |
909 ()) | |
910 ((not (file-exists-p lock-file)) | |
911 (list () ())) | |
912 (t | |
913 (save-excursion | |
914 (set-buffer (get-buffer-create "*SCCS tmp*")) | |
915 (insert-file lock-file) | |
916 (while (search-forward " " () t) | |
917 (replace-match "\n" () t)) | |
918 (goto-char (point-min)) | |
919 (forward-line 1) | |
920 (let ((revision | |
921 (buffer-substring (point) (progn (end-of-line) (point)))) | |
922 (name | |
923 (progn (forward-line 1) | |
924 (buffer-substring (point) | |
925 (progn (end-of-line) (point)))))) | |
926 (kill-buffer (current-buffer)) | |
927 (list name revision))))))) | |
928 | |
929 | |
930 (defun sccs-do-command (buffer command file &rest flags) | |
931 "Execute an SCCS command, notifying the user and checking for errors." | |
932 (let ((exec-path (cons sccs-bin-directory exec-path))) | |
933 (apply 'sc-do-command buffer command command file (sccs-name file) flags))) | |
934 | |
935 (defun sccs-admin (file sid) | |
936 "Checks a file into sccs. | |
937 FILE is the unmodified name of the file. SID should be the base-level sid to | |
938 check it in under." | |
939 ;; give a change to save the file if it's modified | |
940 (if (and (buffer-modified-p) | |
941 (y-or-n-p (format "%s has been modified. Write it out? " | |
942 (buffer-name)))) | |
943 (save-buffer)) | |
944 (sccs-do-command "*SCCS*" "admin" file | |
945 (concat "-i" file) (concat "-r" sid)) | |
946 (sc-chmod "-w" file) | |
947 ;; expand SCCS headers | |
948 (sccs-check-out file nil)) | |
949 | |
950 (defun sccs-register (file revision) | |
951 (sccs-load-vars) | |
952 (if (and (not (file-exists-p "SCCS")) | |
953 (y-or-n-p "Directory SCCS does not exist, create it?")) | |
954 (make-directory "SCCS")) | |
955 (sccs-admin file | |
956 (cond | |
957 (revision revision) | |
958 ((error-occurred (load-file "SCCS/emacs-vars.el")) "1") | |
959 (t sccs-current-major-version)))) | |
960 | |
961 (defun sccs-check-out (file lockp) | |
962 "Retrieve a copy of the latest version of the given file." | |
963 (sccs-do-command "*SCCS*" "get" file (if lockp "-e"))) | |
964 | |
965 (defun sccs-get-version (file buffer revision) | |
966 (sccs-do-command buffer "get" file | |
967 (and revision (concat "-r" revision)) | |
968 "-p" "-s")) | |
969 | |
970 (defun sccs-check-in (file revision comment) | |
971 "Check-in a given version of the given file with the given comment." | |
972 (sccs-do-command "*SCCS*" "delta" file "-n" | |
973 (format "-r%s" revision) | |
974 (format "-y%s" comment)) | |
975 (sc-chmod "-w" file) | |
976 ;; sccs-delta already turned off write-privileges on the | |
977 ;; file, let's not re-fetch it unless there's something | |
978 ;; in it that get would expand | |
979 (save-excursion | |
980 (let ((buffer (get-file-buffer file))) | |
981 (if buffer | |
982 (progn | |
983 (set-buffer buffer) | |
984 (sccs-check-out file nil)))))) | |
985 | |
986 (defun sccs-history (file) | |
987 (sccs-do-command (current-buffer) "prs" file)) | |
988 | |
989 ;; There has *got* to be a better way to do this... | |
990 | |
991 (defun sccs-save-vars (sid) | |
992 (save-excursion | |
993 (find-file "SCCS/emacs-vars.el") | |
994 (erase-buffer) | |
995 (insert "(setq sccs-current-major-version \"" sid "\")") | |
996 (basic-save-buffer))) | |
997 | |
998 (defun sccs-load-vars () | |
999 (if (error-occurred (load-file "SCCS/emacs-vars.el")) | |
1000 (setq sccs-current-major-version "1"))) | |
1001 | |
1002 ;; SCCS header insertion code | |
1003 | |
1004 (defun sccs-insert-headers () | |
1005 "*Insert headers for use with the Source Code Control System. | |
1006 Headers desired are inserted at the start of the buffer, and are pulled from | |
1007 the variable sccs-headers-wanted" | |
1008 (interactive) | |
1009 (save-excursion | |
1010 (save-restriction | |
1011 (widen) | |
1012 (if (or (not (sccs-check-headers)) | |
1013 (y-or-n-p "SCCS headers already exist. Insert another set?")) | |
1014 (progn | |
1015 (goto-char (point-min)) | |
1016 (run-hooks 'sccs-insert-headers-hook) | |
1017 (cond ((eq major-mode 'c-mode) (sccs-insert-c-header)) | |
1018 ((eq major-mode 'lisp-mode) (sccs-insert-lisp-header)) | |
1019 ((eq major-mode 'emacs-lisp-mode) (sccs-insert-lisp-header)) | |
1020 ((eq major-mode 'scheme-mode) (sccs-insert-lisp-header)) | |
1021 ((eq major-mode 'nroff-mode) (sccs-insert-nroff-header)) | |
1022 ((eq major-mode 'plain-tex-mode) (sccs-insert-tex-header)) | |
1023 ((eq major-mode 'texinfo-mode) (sccs-insert-texinfo-header)) | |
1024 (t (sccs-insert-generic-header)))))))) | |
1025 | |
1026 | |
1027 | |
1028 (defun sccs-insert-c-header () | |
1029 (insert "/*\n") | |
1030 (mapcar '(lambda (s) | |
1031 (insert " *\t" s "\n")) | |
1032 sccs-headers-wanted) | |
1033 (insert " */\n\n") | |
1034 (if (and sccs-insert-static | |
1035 (not (string-match "\\.h$" buffer-file-name))) | |
1036 (progn | |
1037 (insert "#ifndef lint\n" | |
1038 "static char *sccsid") | |
1039 ;; (setq st (point)) | |
1040 ;; (insert (file-name-nondirectory buffer-file-name)) | |
1041 ;; (setq en (point)) | |
1042 ;; (subst-char-in-region st en ?. ?_) | |
1043 (insert " = \"\%\W\%\";\n" | |
1044 "#endif /* lint */\n\n"))) | |
1045 (run-hooks 'sccs-insert-c-header-hook)) | |
1046 | |
1047 (defun sccs-insert-lisp-header () | |
1048 (mapcar '(lambda (s) | |
1049 (insert ";;;\t" s "\n")) | |
1050 sccs-headers-wanted) | |
1051 (insert "\n") | |
1052 (run-hooks 'sccs-insert-lisp-header-hook)) | |
1053 | |
1054 (defun sccs-insert-nroff-header () | |
1055 (mapcar '(lambda (s) | |
1056 (insert ".\\\"\t" s "\n")) | |
1057 sccs-headers-wanted) | |
1058 (insert "\n") | |
1059 (run-hooks 'sccs-insert-nroff-header-hook)) | |
1060 | |
1061 (defun sccs-insert-tex-header () | |
1062 (mapcar '(lambda (s) | |
1063 (insert "%%\t" s "\n")) | |
1064 sccs-headers-wanted) | |
1065 (insert "\n") | |
1066 (run-hooks 'sccs-insert-tex-header-hook)) | |
1067 | |
1068 (defun sccs-insert-texinfo-header () | |
1069 (mapcar '(lambda (s) | |
1070 (insert "@comment\t" s "\n")) | |
1071 sccs-headers-wanted) | |
1072 (insert "\n") | |
1073 (run-hooks 'sccs-insert-texinfo-header-hook)) | |
1074 | |
1075 (defun sccs-insert-generic-header () | |
1076 (let* ((comment-start-sccs (or comment-start "#")) | |
1077 (comment-end-sccs (or comment-end "")) | |
1078 (dont-insert-nl-p (string-match "\n" comment-end-sccs))) | |
1079 (mapcar '(lambda (s) | |
1080 (insert comment-start-sccs "\t" s "" | |
1081 comment-end-sccs (if dont-insert-nl-p "" "\n"))) | |
1082 sccs-headers-wanted) | |
1083 (insert comment-start-sccs comment-end-sccs (if dont-insert-nl-p "" "\n")))) | |
1084 | |
1085 (defun sccs-check-headers () | |
1086 "Check if the current file has any SCCS headers in it." | |
1087 (save-excursion | |
1088 (goto-char (point-min)) | |
1089 (let ((case-fold-search ())) | |
1090 (re-search-forward "%[MIRLBSDHTEGUYFPQCZWA]%" (point-max) t)))) | |
1091 | |
1092 (defun sccs-tree-list () | |
1093 "List all the registered files in the current directory" | |
1094 (call-process "/bin/sh" () t () "-c" | |
1095 (concat "/bin/ls -1 " default-directory "SCCS/s.*")) | |
1096 (goto-char (point-min)) | |
1097 (while (search-forward "SCCS/s." () t) | |
1098 (replace-match "" () t))) | |
1099 | |
1100 (defun sccs-new-revision-p (file) | |
1101 "True if the SCCS archive is more recent than the file itself" | |
1102 (file-newer-than-file-p (sccs-name file) file)) | |
1103 | |
1104 (defun sccs-revert (file) | |
1105 "Cancel a check-out and get a fresh copy of the file" | |
1106 (delete-file (sccs-name file "p")) | |
1107 (delete-file file) | |
1108 (sccs-do-command "*SCCS*" "get" file "-s")) | |
1109 | |
1110 (defun sccs-rename (old new) | |
1111 "Rename the SCCS archives for OLD to NEW" | |
1112 (if (file-exists-p (sccs-name old "p")) | |
1113 (rename-file (sccs-name old "p") (sccs-name new "p") t)) | |
1114 (if (file-exists-p (sccs-name old "s")) | |
1115 (rename-file (sccs-name old "s") (sccs-name new "s") t))) | |
1116 | |
1117 | |
1118 ;;; RCS specific part | |
1119 | |
1120 ;; Some helper functions | |
1121 | |
1122 (defun rcs-name (file) | |
1123 "Return the rcs-file corresponding to a given file." | |
1124 (if (null file) | |
1125 () | |
1126 (let* ((name (expand-file-name file)) | |
1127 (rcs-file (concat name ",v"))) | |
1128 (if (and (not (file-exists-p rcs-file)) | |
1129 (file-exists-p (concat (file-name-directory name) "RCS"))) | |
1130 (setq rcs-file | |
1131 (format "%sRCS/%s,v" (file-name-directory name) | |
1132 (file-name-nondirectory name)))) | |
1133 rcs-file))) | |
1134 | |
1135 (defun rcs-lock-info (file) | |
1136 "Lock-info method for RCS. See sc-generic-lock-info" | |
1137 (let ((rcs-file (rcs-name file)) | |
1138 locks-regexp) | |
1139 (if (or (null rcs-file) (not (file-exists-p rcs-file))) | |
1140 () | |
1141 (save-excursion | |
1142 (set-buffer (get-buffer-create "*RCS tmp*")) | |
1143 (erase-buffer) | |
1144 (call-process "rlog" () t () "-L" "-h" rcs-file) | |
1145 (goto-char (point-min)) | |
1146 (if (looking-at "\n.*Working file") | |
1147 ;; RCS 4.x | |
1148 (setq locks-regexp "^locks:") | |
1149 ;; RCS 5.x | |
1150 (setq locks-regexp "^locks:.*$\n")) | |
1151 (if (not (re-search-forward locks-regexp () t)) | |
1152 (list () ()) | |
1153 (if (not (looking-at (concat "[\t ]*\\([^:]*\\): \\([0-9\\.]*\\)"))) | |
1154 (list () ()) | |
1155 (list (buffer-substring (match-beginning 1) (match-end 1)) | |
1156 (buffer-substring (match-beginning 2) (match-end 2))))))))) | |
1157 | |
1158 | |
1159 (defun rcs-register (file revision) | |
1160 (if (and (not (file-exists-p "RCS")) | |
1161 (y-or-n-p "Directory RCS does not exist, create it?")) | |
1162 (make-directory "RCS")) | |
1163 (sc-do-command "*RCS*" "ci" "ci" file (rcs-name file) "-u")) | |
1164 | |
1165 (defun rcs-check-out (file lockp) | |
1166 (sc-do-command "*RCS*" "co" "co" file (rcs-name file) (if lockp "-l"))) | |
1167 | |
1168 (defun rcs-get-version (file buffer revision) | |
1169 (sc-do-command buffer "co" "co" file (rcs-name file) | |
1170 (if revision (concat "-p" revision) "-p") | |
1171 "-q")) | |
1172 | |
1173 (defun rcs-check-in (file revision comment) | |
1174 "Check-in a given version of the given file with the given comment." | |
1175 (sc-do-command "*RCS*" "ci" "ci" file (rcs-name file) "-f" | |
1176 (format "-m%s" comment) | |
1177 (if (equal revision (sc-locked-revision file)) | |
1178 "-u" | |
1179 (format "-u%s" revision)))) | |
1180 | |
1181 (defun rcs-history (file) | |
1182 (sc-do-command (current-buffer) "rlog" "rlog" file (rcs-name file))) | |
1183 | |
1184 (defun rcs-tree-list () | |
1185 "List all the registered files in the current directory" | |
1186 (call-process "/bin/sh" () t () "-c" | |
1187 (concat "/bin/ls -1 " default-directory "RCS/*,v")) | |
1188 (call-process "/bin/sh" () t () "-c" | |
1189 (concat "/bin/ls -1 " default-directory "*,v")) | |
1190 (goto-char (point-min)) | |
1191 (while (search-forward "RCS/" () t) | |
1192 (replace-match "" () t)) | |
1193 (goto-char (point-min)) | |
1194 (while (search-forward ",v" () t) | |
1195 (replace-match "" () t))) | |
1196 | |
1197 (defun rcs-new-revision-p (file) | |
1198 "True if the archive is more recent than the file itself" | |
1199 (file-newer-than-file-p (rcs-name file) file)) | |
1200 | |
1201 (defun rcs-revert (file) | |
1202 "Cancel a check-out and get a fresh copy of the file" | |
1203 (sc-do-command "*RCS*" "rcs" "rcs" file (rcs-name file) "-u") | |
1204 (delete-file file) | |
1205 (sc-do-command "*RCS*" "co" "co" file (rcs-name file))) | |
1206 | |
1207 (defun rcs-rename (old new) | |
1208 "Rename the archives for OLD to NEW" | |
1209 (if (file-exists-p (rcs-name old)) | |
1210 (rename-file (rcs-name old) (rcs-name new) t))) | |
1211 | |
1212 | |
1213 ;;; CVS specific part | |
1214 | |
1215 ;;; As we rely on pcl-cvs for the directory level functions the menu is | |
1216 ;;; much shorter in CVS mode | |
1217 | |
1218 | |
1219 (defun cvs-lock-info (file) | |
1220 "Lock-info method for CVS, different from RCS and SCCS modes. | |
1221 File are never locked in CVS." | |
1222 (list () ())) | |
1223 | |
1224 (defun cvs-register (file revision) | |
1225 (sc-do-command "*CVS*" "cvs add" cvs-program file | |
1226 (file-name-nondirectory file) | |
1227 "add" "-mInitial revision")) | |
1228 | |
1229 (defun cvs-check-out (file lockp) | |
1230 ) | |
1231 | |
1232 (defun cvs-get-version (file buffer revision) | |
1233 (sc-do-command buffer "cvs update" cvs-program file file "update" | |
1234 (if revision (concat "-r" revision)) | |
1235 "-p" "-q")) | |
1236 | |
1237 (defun cvs-check-in (file revision comment) | |
1238 "Check-in a given version of the given file with the given comment." | |
1239 (sc-do-command "*CVS*" "cvs commit" cvs-program file file "commit" | |
1240 (and revision (format "-r%s" revision)) | |
1241 (format "-m%s" comment))) | |
1242 | |
1243 (defun cvs-history (file) | |
1244 (sc-do-command (current-buffer) "cvs log" cvs-program file file "log")) | |
1245 | |
1246 (defun cvs-revert (file) | |
1247 "Cancel a check-out and get a fresh copy of the file" | |
1248 (delete-file file) | |
1249 (sc-do-command "*CVS*" "cvs update" cvs-program file file "update")) | |
1250 | |
1251 (defun sc-cvs-update-directory () | |
1252 "Update the current directory by calling cvs-update from pcl-cvs" | |
1253 (interactive) | |
1254 (cvs-update default-directory)) | |
1255 | |
1256 (defun sc-cvs-file-status () | |
1257 "Show the CVS status of the current file" | |
1258 (interactive) | |
1259 (if (not buffer-file-name) | |
1260 (error "There is no file associated with buffer %s" (buffer-name))) | |
1261 (let ((file buffer-file-name)) | |
1262 (sc-do-command "*CVS*" "cvs status" cvs-program file file "status" "-v")) | |
1263 (save-excursion | |
1264 (set-buffer "*CVS*") | |
1265 (goto-char (point-min))) | |
1266 (display-buffer "*CVS*")) | |
1267 | |
1268 | |
1269 ;;; ClearCase specific part | |
1270 | |
1271 (defun ccase-is-registered-3 (fod) | |
1272 (if (or (not fod) | |
1273 (not (file-readable-p fod))) | |
1274 'na | |
1275 (let ((dirs sc-ccase-mfs-prefixes) | |
1276 (f nil) | |
1277 (file (expand-file-name fod))) | |
1278 (while (and (null f) dirs) | |
1279 (if (string-match (car dirs) file) | |
1280 (setq f t) | |
1281 (setq dirs (cdr dirs)))) | |
1282 (if (null f) | |
1283 'na | |
1284 (sc-do-command "*CCase*" "describe" "cleartool" fod fod "describe") | |
1285 (save-excursion | |
1286 (set-buffer "*CCase*") | |
1287 (let ((s (buffer-string))) | |
1288 (cond | |
1289 ((string-match "@@" s) t) | |
1290 ((string-match "^Unix" s) 'na) | |
1291 (t nil) | |
1292 ))))))) | |
1293 | |
1294 (defun ccase-is-registered (fod) | |
1295 (eq (ccase-is-registered-3 fod) t)) | |
1296 | |
1297 (defun ccase-lock-info (file) | |
1298 (let ((cc (ccase-is-registered-3 file)) | |
1299 s) | |
1300 (if (eq cc 't) | |
1301 (progn | |
1302 (save-excursion | |
1303 (set-buffer "*CCase*") | |
1304 (setq s (buffer-string))) | |
1305 (if (string-match "@@[^\n]*CHECKEDOUT\" from \\([^ ]*\\)[^\n]*\n[^\n]* by \\([^(\n]*\\) (" s) | |
1306 (list | |
1307 (substring s (match-beginning 1) (match-end 1)) | |
1308 (substring s (match-beginning 2) (match-end 2))) | |
1309 (list nil nil))) | |
1310 cc))) | |
1311 | |
1312 (defun ccase-maybe-comment (tag) | |
1313 (if (memq tag sc-ccase-comment-on) | |
1314 (sc-enter-comment))) | |
1315 | |
1316 (defun ccase-register (file revision) | |
1317 "Registers the file. We don't support the revision argument. | |
1318 Also, we have to checkout the directory first." | |
1319 ;; probably need proper error handling to catch the | |
1320 ;; cases where we co the directory, but don't get to | |
1321 ;; ci it back (want to uco in this case) | |
1322 (let ((dpath (file-name-directory file))) | |
1323 (if (not (ccase-is-registered dpath)) | |
1324 (error "Cannot register file outside of VOB") | |
1325 (sc-do-command "*CCase*" "co - dir" "cleartool" dpath dpath "co") | |
1326 (sc-do-command "*CCase*" "register" "cleartool" file file "mkelem") | |
1327 (sc-do-command "*CCase*" "ci - dir" "cleartool" dpath dpath "ci")))) | |
1328 | |
1329 (defun ccase-check-out (file lockp) | |
1330 "Checks out the latest version of FILE. | |
1331 If LOCKP is not NIL, FILE is also locked." | |
1332 (let ((comment (ccase-maybe-comment 'checkout))) | |
1333 (sc-do-command "*CCase*" "co" "cleartool" file file "co" | |
1334 (if comment "-c" "-nc") | |
1335 (if comment comment) | |
1336 ;; this locking does not correspond to what we actually want. It's a | |
1337 ;; hack from the days when this was SCCS-only | |
1338 (if (ccase-reserve-p) "-res" "-unr")) | |
1339 )) | |
1340 | |
1341 (defun ccase-reserve-p () | |
1342 "Determine whether the user wants a reserved or unreserved checkout" | |
1343 (cond | |
1344 ((eq sc-ccase-reserve t) t) | |
1345 ((eq sc-ccase-reserve nil) nil) | |
1346 (t (y-or-n-p "Reserve Checkout? ")))) | |
1347 | |
1348 (defun ccase-get-version (file buffer revision) | |
1349 "Insert a previous revison of FILE in BUFFER. | |
1350 REVISION is the revision number requested." | |
1351 (save-excursion | |
1352 (set-buffer buffer) | |
1353 (delete-region (point-min) (point-max)) | |
1354 (insert-file-contents (concat file "@@/" revision))) | |
1355 ) | |
1356 | |
1357 (defun ccase-check-in (file revision message) | |
1358 "Check in FILE with revision REVISION. | |
1359 MESSAGE is a string describing the changes." | |
1360 ;; we ignore revision since we can't use it | |
1361 (sc-do-command "*CCase*" "ci" "cleartool" file file "ci" "-c" message (if sc-mode-expert "-ide")) | |
1362 ) | |
1363 | |
1364 (defun ccase-history (file) | |
1365 "Insert the edit history of FILE in the current buffer." | |
1366 (sc-do-command (buffer-name) "history" "cleartool" file file "lsh") | |
1367 ) | |
1368 | |
1369 (defun ccase-tree-list () | |
1370 "List in the current buffer the files registered in the source control system" | |
1371 ;;; This isn't going to fly as a practicality. We abstract everything out. | |
1372 ;; (sc-do-command (buffer-name) "listing" "cleartool" (default-directory) (default-directory) "ls" "-r" "-short" "-vis" "-nxname") | |
1373 ) | |
1374 | |
1375 (defun ccase-new-revision-p (file) | |
1376 "True if a new revision of FILE was checked in since we last got a copy of it" | |
1377 (save-excursion | |
1378 (let (newfile res br1 br2) | |
1379 (sc-do-command "*CCase*" "Describe" "cleartool" file file "des") | |
1380 (set-buffer "*CCase*") | |
1381 (goto-char (point-min)) | |
1382 (if (setq pos (search-forward-regexp "@@\\([^ \"]*\\)CHECKEDOUT\" from \\([^ ]*\\) (\\([a-z]*\\))" nil t)) | |
1383 ;; (if (setq pos (search-forward-regexp "@@\\([^ \"]*\\)CHECKEDOUT\"" nil t)) | |
1384 (progn | |
1385 (setq res (buffer-substring (match-beginning 3) (match-end 3))) | |
1386 (if (equal res "unreserved") | |
1387 (progn | |
1388 (setq newfile (concat file "@@" | |
1389 (buffer-substring (match-beginning 1) | |
1390 (match-end 1)) | |
1391 "LATEST")) | |
1392 (setq br1 (buffer-substring (match-beginning 2) (match-end 2))) | |
1393 (sc-do-command "*CCase*" "Describe" "cleartool" file newfile | |
1394 "des") | |
1395 (search-forward-regexp "@@\\([^ \"]*\\)" nil t) | |
1396 (setq br2 (buffer-substring (match-beginning 1) (match-end 1))) | |
1397 (not (equal br1 br2))) | |
1398 nil)) | |
1399 (error "%s not currently checked out" file))))) | |
1400 | |
1401 (defun ccase-revert (file) | |
1402 "Cancel a check out of FILE and get back the latest checked in version" | |
1403 (sc-do-command "*CCase*" "uco" "cleartool" file file "unco") | |
1404 ) | |
1405 | |
1406 (defun ccase-rename (old new) | |
1407 "Rename the source control archives for OLD to NEW" | |
1408 (let ((dpath (file-name-directory old)) | |
1409 (comment (ccase-maybe-comment 'rename))) | |
1410 (if (not (ccase-is-registered dpath)) | |
1411 (error "Cannot rename file outside of VOB") | |
1412 (sc-do-command "*CCase*" "co - dir" "cleartool" dpath dpath "co" | |
1413 (if comment "-c" "-nc") | |
1414 (if comment comment)) | |
1415 (sc-do-command "*CCase*" "mv" "cleartool" new new "mv" | |
1416 (if comment "-c" "-nc") | |
1417 (if comment comment) | |
1418 old) | |
1419 (sc-do-command "*CCase*" "ci - dir" "cleartool" dpath dpath "ci" | |
1420 (if comment "-c" "-nc") | |
1421 (if comment comment))))) | |
1422 | |
1423 (defun sc-ccase-checkout-dir () | |
1424 "Checkout the directory this file is in" | |
1425 (interactive) | |
1426 (let ((dpath default-directory) | |
1427 (comment (ccase-maybe-comment 'checkout-dir))) | |
1428 (if (not (ccase-is-registered dpath)) | |
1429 (error "Cannot checkout directory outside of VOB") | |
1430 (sc-do-command "*CCase*" "co - dir" "cleartool" dpath dpath "co" | |
1431 (if comment "-c" "-nc") | |
1432 (if comment comment))))) | |
1433 | |
1434 (defun sc-ccase-checkin-dir () | |
1435 "Checkin the directory this file is in" | |
1436 (interactive) | |
1437 (let ((dpath default-directory) | |
1438 (comment (ccase-maybe-comment 'checkin-dir))) | |
1439 (if (not (ccase-is-registered dpath)) | |
1440 (error "Cannot checkout directory outside of VOB") | |
1441 (sc-do-command "*CCase*" "ci - dir" "cleartool" dpath dpath "ci" | |
1442 (if comment "-c" "-nc") | |
1443 (if comment comment))))) | |
1444 | |
1445 (defun sc-ccase-editcs () | |
1446 "Edit Config Spec for this view" | |
1447 (interactive) | |
1448 (sc-do-command "*CCase-cs*" "catcs" "cleartool" "" nil "catcs") | |
1449 (switch-to-buffer-other-window "*CCase-cs*") | |
1450 (local-set-key "\C-c\C-c" 'exit-recursive-edit) | |
1451 (recursive-edit) | |
1452 (set-buffer "*CCase-cs*") | |
1453 (let ((name (make-temp-name "/tmp/configspec"))) | |
1454 (write-region (point-min) (point-max) name) | |
1455 (kill-buffer "*CCase-cs*") | |
1456 (sc-do-command "*CCase*" "setcs" "cleartool" name name "setcs")) | |
1457 ) | |
1458 | |
1459 (defun sc-ccase-new-brtype (brt) | |
1460 "Create a new branch type" | |
1461 (interactive "sBranch Name: ") | |
1462 (let ((comment (ccase-maybe-comment 'new-brtype))) | |
1463 (sc-do-command "*CCase*" "mkbrt" "cleartool" brt brt "mkbrtype" | |
1464 (if comment "-c" "-nc") | |
1465 (if comment comment)))) | |
1466 | |
1467 (defun sc-ccase-new-branch (brch) | |
1468 "Create a new branch for element" | |
1469 (interactive "sBranch: ") | |
1470 (let ((file (buffer-file-name)) | |
1471 (comment (ccase-maybe-comment 'new-branch))) | |
1472 (sc-do-command "*CCase*" "mkbrch" "cleartool" file file "mkbranch" | |
1473 (if comment "-c" "-nc") | |
1474 (if comment comment) | |
1475 brch))) | |
1476 | |
1477 (defun sc-ccase-checkin-merge () | |
1478 "Merge in changes to enable checkin" | |
1479 (interactive) | |
1480 (save-excursion | |
1481 (let ((file (buffer-file-name)) | |
1482 (buf (current-buffer)) | |
1483 (comment (ccase-maybe-comment 'checkin-merge))) | |
1484 (sc-do-command "*CCase*" "Describe" "cleartool" file file "des") | |
1485 (set-buffer "*CCase*") | |
1486 (goto-char (point-min)) | |
1487 (if (search-forward-regexp "@@\\([^ \"]*\\)CHECKEDOUT\" from \\([^ ]*\\) (\\([a-z]*\\))" nil t) | |
1488 (progn | |
1489 (sc-do-command "*CCase*" "Merging" "cleartool" file | |
1490 (concat (buffer-substring (match-beginning 1) | |
1491 (match-end 1)) "LATEST") | |
1492 "merge" | |
1493 (if comment "-c" "-nc") | |
1494 (if comment comment) | |
1495 "-abort" "-to" file "-ver") | |
1496 (set-buffer buf) | |
1497 (revert-buffer t t) | |
1498 (display-buffer "*CCase*")) | |
1499 (error "File %s not checked out" file))))) | |
1500 | |
1501 (defun sc-ccase-version-tree () | |
1502 "List version tree for file" | |
1503 (interactive) | |
1504 (let ((p (buffer-file-name))) | |
1505 (sc-do-command "*CCase*" "lsvtree" "cleartool" p p "lsvtree") | |
1506 (display-buffer "*CCase*"))) | |
1507 | |
1508 (defun ccase-protect-expanded-name (revision) | |
1509 "Protect ccase extended names from being used as temp names. Munge /s into :s" | |
1510 (if (equal sc-generic-name "CCase") | |
1511 (progn | |
1512 (if (string-match "/" revision) | |
1513 (let ((str (substring revision 0)) ;; copy string | |
1514 i) | |
1515 (while (setq i (string-match "/" str)) | |
1516 (aset str i 58)) ; 58 is for : | |
1517 str))))) | |
1518 | |
1519 (defun sc-ccase-list-locked-files () | |
1520 (interactive) | |
1521 (sc-do-command "*CCase directory*" "listing" "cleartool" (default-directory) nil "lsco" "-cview")) | |
1522 | |
1523 (defun sc-ccase-list-all-locked-files () | |
1524 (interactive) | |
1525 (sc-do-command "*CCase directory*" "listing" "cleartool" (default-directory) nil "lsco")) | |
1526 | |
1527 (defun sc-ccase-list-registered-files () | |
1528 "List files registered in clearcase" | |
1529 (interactive) | |
1530 (sc-do-command "*CCase directory*" "listing" "cleartool" (default-directory) nil "ls" "-r" "-vis" "-nxname")) | |
1531 | |
1532 ;;; Instantiation and installation of the menus | |
1533 | |
1534 ;;; Set the menubar for Lucid Emacs | |
1535 (defvar sc-default-menu | |
1536 '(["NEXT-OPERATION" sc-next-operation t nil] | |
1537 ["Update Current Directory" sc-update-directory t] | |
1538 "----" | |
1539 ["Revert File" sc-revert-file t nil] | |
1540 ["Rename File" sc-rename-this-file t nil] | |
1541 "----" | |
1542 ["Show Changes" sc-show-changes t] | |
1543 ["Show Changes Since Revision..." sc-show-revision-changes t] | |
1544 ["Visit Previous Revision..." sc-visit-previous-revision t] | |
1545 ["Show Edit History" sc-show-history t] | |
1546 "----" | |
1547 ["List Locked Files" sc-list-locked-files t] | |
1548 ["List Locked Files Any User" sc-list-all-locked-files t] | |
1549 ["List Registered Files" sc-list-registered-files t]) | |
1550 "Menubar entry for using the revision control system.") | |
1551 | |
1552 (defvar sc-cvs-menu | |
1553 '(["Update Current Directory" sc-cvs-update-directory t] | |
1554 ["Revert File" sc-revert-file t nil] | |
1555 "----" | |
1556 ["Show Changes" sc-show-changes t] | |
1557 ["Show Changes Since Revision..." sc-show-revision-changes t] | |
1558 ["Visit Previous Revision..." sc-visit-previous-revision t] | |
1559 ["Show File Status" sc-cvs-file-status t] | |
1560 ["Show Edit History" sc-show-history t]) | |
1561 "Menubar entry for using the revision control system with CVS.") | |
1562 | |
1563 (defvar sc-ccase-menu | |
1564 '(["NEXT-OPERATION" sc-next-operation t nil] | |
1565 ["Revert File" sc-revert-file t nil] | |
1566 ["Checkin Merge" sc-ccase-checkin-merge t] | |
1567 "----" | |
1568 ["Show Changes" sc-show-changes t] | |
1569 ["Show Changes Since Revision..." sc-show-revision-changes t] | |
1570 ["Visit Previous Revision..." sc-visit-previous-revision t] | |
1571 ["Show Edit History" sc-show-history t] | |
1572 "----" | |
1573 ("Directories" | |
1574 ["Checkout Directory" sc-ccase-checkout-dir t] | |
1575 ["Checkin Directory" sc-ccase-checkin-dir t] | |
1576 ["Rename File..." sc-rename-this-file t nil]) | |
1577 ("Configs" | |
1578 ["Edit Config Spec..." sc-ccase-editcs t] | |
1579 ["Create New Branch..." sc-ccase-new-brtype t] | |
1580 ["Make New Branch..." sc-ccase-new-branch t]) | |
1581 ("Listings" | |
1582 ["List Version Tree" sc-ccase-version-tree t] | |
1583 ["List Locked Files" sc-ccase-list-locked-files t] | |
1584 ["List Locked Files Any User" sc-ccase-list-all-locked-files t] | |
1585 ["List Registered Files" sc-ccase-list-registered-files t] | |
1586 )) | |
1587 "Menubar entry for using the revision control system.") | |
1588 | |
1589 (defun sc-sensitize-menu () | |
1590 (let* ((rest (cdr (car | |
1591 (find-menu-item current-menubar (list sc-generic-name))))) | |
1592 (case-fold-search t) | |
1593 (file (if buffer-file-name | |
1594 (file-name-nondirectory buffer-file-name) | |
1595 (buffer-name))) | |
1596 (lock-info (sc-lock-info buffer-file-name)) | |
1597 command | |
1598 nested-rest | |
1599 item) | |
1600 (while rest | |
1601 (setq item (car rest)) | |
1602 (if (listp item) | |
1603 (progn | |
1604 (setq nested-rest (cons (cdr rest) nested-rest)) | |
1605 (setq rest (cdr item))) | |
1606 (if (vectorp item) | |
1607 (progn | |
1608 (setq command (aref item 1)) | |
1609 (cond ((eq 'sc-next-operation command) | |
1610 (aset item 0 | |
1611 (cond ((eq lock-info 'na) "Not Available") | |
1612 ((not lock-info) "Register File") | |
1613 ((not (car lock-info)) "Check out File") | |
1614 (t "Check in File"))) | |
1615 ;; if locked by somebody else disable the next-operation | |
1616 (if (or (not buffer-file-name) | |
1617 (eq lock-info 'na) | |
1618 (and (car lock-info) | |
1619 (not (equal sc-generic-name "CCase")) | |
1620 (not (equal (car lock-info) (user-login-name))))) | |
1621 (aset item 2 ()) | |
1622 (aset item 2 t))) | |
1623 ((eq lock-info 'na) (aset item 2 ())) | |
1624 ((> (length item) 3) | |
1625 (aset item 3 file)) | |
1626 (t nil)) | |
1627 (if (not (eq lock-info 'na)) | |
1628 (let ((enable-file-items | |
1629 (if (member sc-generic-name '("CVS" "CCase")) | |
1630 buffer-file-name | |
1631 (if lock-info t ())))) | |
1632 (if (memq command | |
1633 '(sc-force-check-in-file | |
1634 sc-register-file | |
1635 sc-revert-file | |
1636 sc-rename-this-file | |
1637 sc-show-history | |
1638 sc-show-changes | |
1639 sc-show-revision-changes | |
1640 sc-visit-previous-revision | |
1641 sc-cvs-file-status | |
1642 sc-ccase-checkout-dir | |
1643 sc-ccase-checkin-dir | |
1644 sc-ccase-editcs | |
1645 sc-ccase-new-brtype | |
1646 sc-ccase-new-branch | |
1647 sc-ccase-checkin-merge | |
1648 sc-ccase-needs-merge | |
1649 sc-ccase-merge-changes | |
1650 sc-ccase-create-label | |
1651 sc-ccase-label-sources | |
1652 sc-ccase-version-tree | |
1653 sc-list-locked-files | |
1654 sc-list-all-locked-files | |
1655 sc-ccase-list-registered-files | |
1656 )) | |
1657 (aset item 2 enable-file-items)))))) | |
1658 (if (not (setq rest (cdr rest))) | |
1659 (if nested-rest | |
1660 (progn | |
1661 (setq rest (car nested-rest)) | |
1662 (setq nested-rest (cdr nested-rest))))))) | |
1663 nil)) | |
1664 | |
1665 | |
1666 ;;; Function to decide which Source control to use | |
1667 (defun sc-set-SCCS-mode () | |
1668 (setq sc-generic-name "SCCS") | |
1669 (setq sc-can-hack-dir t) | |
1670 (setq sc-generic-lock-info 'sccs-lock-info) | |
1671 (setq sc-generic-register 'sccs-register) | |
1672 (setq sc-generic-check-out 'sccs-check-out) | |
1673 (setq sc-generic-get-version 'sccs-get-version) | |
1674 (setq sc-generic-check-in 'sccs-check-in) | |
1675 (setq sc-generic-history 'sccs-history) | |
1676 (setq sc-generic-tree-list 'sccs-tree-list) | |
1677 (setq sc-generic-new-revision-p 'sccs-new-revision-p) | |
1678 (setq sc-generic-revert 'sccs-revert) | |
1679 (setq sc-generic-rename 'sccs-rename) | |
1680 (setq sc-menu | |
1681 (cons (car sc-default-menu) | |
1682 (cons ["Insert Headers" sccs-insert-headers t] | |
1683 (cdr sc-default-menu)))) | |
1684 (define-key sc-prefix-map "h" 'sccs-insert-headers) | |
1685 (define-key sc-prefix-map "\C-d" 'sc-update-directory)) | |
1686 | |
1687 (defun sc-set-RCS-mode () | |
1688 (setq sc-generic-name "RCS") | |
1689 (setq sc-can-hack-dir t) | |
1690 (setq sc-generic-lock-info 'rcs-lock-info) | |
1691 (setq sc-generic-register 'rcs-register) | |
1692 (setq sc-generic-check-out 'rcs-check-out) | |
1693 (setq sc-generic-get-version 'rcs-get-version) | |
1694 (setq sc-generic-check-in 'rcs-check-in) | |
1695 (setq sc-generic-history 'rcs-history) | |
1696 (setq sc-generic-tree-list 'rcs-tree-list) | |
1697 (setq sc-generic-new-revision-p 'rcs-new-revision-p) | |
1698 (setq sc-generic-revert 'rcs-revert) | |
1699 (setq sc-generic-rename 'rcs-rename) | |
1700 (setq sc-menu sc-default-menu) | |
1701 (define-key sc-prefix-map "\C-d" 'sc-update-directory)) | |
1702 | |
1703 (defun sc-set-CVS-mode () | |
1704 (require 'pcl-cvs) | |
1705 (setq sc-generic-name "CVS") | |
1706 (setq sc-can-hack-dir t) | |
1707 (setq sc-generic-lock-info 'cvs-lock-info) | |
1708 (setq sc-generic-register 'cvs-register) | |
1709 (setq sc-generic-check-out 'cvs-check-out) | |
1710 (setq sc-generic-get-version 'cvs-get-version) | |
1711 (setq sc-generic-check-in 'cvs-check-in) | |
1712 (setq sc-generic-history 'cvs-history) | |
1713 (setq sc-generic-tree-list 'cvs-tree-list) | |
1714 (setq sc-generic-new-revision-p 'cvs-new-revision-p) | |
1715 (setq sc-generic-revert 'cvs-revert) | |
1716 (setq sc-generic-rename 'cvs-rename) | |
1717 (setq sc-menu sc-cvs-menu) | |
1718 (define-key sc-prefix-map "\C-d" 'sc-cvs-update-directory) | |
1719 (define-key sc-prefix-map "s" 'sc-cvs-file-status)) | |
1720 | |
1721 (defun sc-set-CLEARCASE-mode () | |
1722 (setq sc-generic-name "CCase") | |
1723 (setq sc-can-hack-dir nil) | |
1724 (setq sc-generic-lock-info 'ccase-lock-info) | |
1725 (setq sc-generic-register 'ccase-register) | |
1726 (setq sc-generic-check-out 'ccase-check-out) | |
1727 (setq sc-generic-get-version 'ccase-get-version) | |
1728 (setq sc-generic-check-in 'ccase-check-in) | |
1729 (setq sc-generic-history 'ccase-history) | |
1730 (setq sc-generic-tree-list 'ccase-tree-list) | |
1731 (setq sc-generic-new-revision-p 'ccase-new-revision-p) | |
1732 (setq sc-generic-revert 'ccase-revert) | |
1733 (setq sc-generic-rename 'ccase-rename) | |
1734 (setq sc-menu sc-ccase-menu) | |
1735 | |
1736 ;; caching for file directory types | |
1737 (save-excursion | |
1738 (set-buffer (get-buffer-create "*CCase*")) | |
1739 (shell-command-on-region (point-min) (point-max) "df -t mfs | sed -n 's%.*[ ]\\(/[^ ]*\\)$%\\1%p'" t) | |
1740 (goto-char (point-min)) | |
1741 (let (x l) | |
1742 (while (condition-case nil (setq x (read (current-buffer))) | |
1743 (error nil)) | |
1744 (setq l (cons (prin1-to-string x) l))) | |
1745 (setq sc-ccase-mfs-prefixes (nreverse l)))) | |
1746 ) | |
1747 | |
1748 (defun sc-set-ATRIA-mode () | |
1749 (sc-set-CLEARCASE-mode)) | |
1750 | |
1751 (defun sc-set-CCASE-mode () | |
1752 (sc-set-CLEARCASE-mode)) | |
1753 | |
1754 | |
1755 ;; the module is sucessfully loaded! | |
1756 (provide 'generic-sc) | |
1757 | |
1758 ;;; generic-sc.el ends here |