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