Merge from emacs--rel--22
[bpt/emacs.git] / lisp / vc-bzr.el
1 ;;; vc-bzr.el --- VC backend for the bzr revision control system
2
3 ;; Copyright (C) 2006, 2007 Free Software Foundation, Inc.
4
5 ;; NOTE: THIS IS A MODIFIED VERSION OF Dave Love's vc-bzr.el,
6 ;; which you can find at: http://www.loveshack.ukfsn.org/emacs/vc-bzr.el
7 ;; I could not get in touch with Dave Love by email, so
8 ;; I am releasing my changes separately. -- Riccardo
9
10 ;; Author: Dave Love <fx@gnu.org>, Riccardo Murri <riccardo.murri@gmail.com>
11 ;; Keywords: tools
12 ;; Created: Sept 2006
13 ;; Version: 2007-05-24
14 ;; URL: http://launchpad.net/vc-bzr
15
16 ;; This file is free software; you can redistribute it and/or modify
17 ;; it under the terms of the GNU General Public License as published by
18 ;; the Free Software Foundation; either version 2, or (at your option)
19 ;; any later version.
20
21 ;; This file is distributed in the hope that it will be useful,
22 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 ;; GNU General Public License for more details.
25
26 ;; You should have received a copy of the GNU General Public License
27 ;; along with GNU Emacs; see the file COPYING. If not, write to the
28 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29 ;; Boston, MA 02110-1301, USA.
30
31
32 ;;; Commentary:
33
34 ;; NOTE: THIS IS A MODIFIED VERSION OF Dave Love's vc-bzr.el,
35 ;; which you can find at: http://www.loveshack.ukfsn.org/emacs/vc-bzr.el
36
37 ;; See <URL:http://bazaar-vcs.org/> concerning bzr.
38
39 ;; Load this library to register bzr support in VC. It covers basic VC
40 ;; functionality, but was only lightly exercised with a few Emacs/bzr
41 ;; version combinations, namely those current on the authors' PCs.
42 ;; See various Fixmes below.
43
44
45 ;; Known bugs
46 ;; ==========
47
48 ;; When edititing a symlink and *both* the symlink and its target
49 ;; are bzr-versioned, `vc-bzr` presently runs `bzr status` on the
50 ;; symlink, thereby not detecting whether the actual contents
51 ;; (that is, the target contents) are changed.
52 ;; See https://bugs.launchpad.net/vc-bzr/+bug/116607
53
54 ;; For an up-to-date list of bugs, please see:
55 ;; https://bugs.launchpad.net/vc-bzr/+bugs
56
57
58 ;;; Code:
59
60 (eval-when-compile
61 (require 'cl)
62 (require 'vc)) ; for vc-exec-after
63
64 ;; Clear up the cache to force vc-call to check again and discover
65 ;; new functions when we reload this file.
66 (put 'BZR 'vc-functions nil)
67
68 (defgroup vc-bzr nil
69 "VC bzr backend."
70 ;; :version "22"
71 :group 'vc)
72
73 (defcustom vc-bzr-program "bzr"
74 "Name of the bzr command (excluding any arguments)."
75 :group 'vc-bzr
76 :type 'string)
77
78 ;; Fixme: there's probably no call for this.
79 (defcustom vc-bzr-program-args nil
80 "List of global arguments to pass to `vc-bzr-program'."
81 :group 'vc-bzr
82 :type '(repeat string))
83
84 (defcustom vc-bzr-diff-switches nil
85 "String/list of strings specifying extra switches for bzr diff under VC."
86 :type '(choice (const :tag "None" nil)
87 (string :tag "Argument String")
88 (repeat :tag "Argument List" :value ("") string))
89 :group 'vc-bzr)
90
91 (defvar vc-bzr-version nil
92 "Internal use.")
93
94 ;; Could be used for compatibility checks if bzr changes.
95 (defun vc-bzr-version ()
96 "Return a three-numeric element list with components of the bzr version.
97 This is of the form (X Y Z) for revision X.Y.Z. The elements are zero
98 if running `vc-bzr-program' doesn't produce the expected output."
99 (or vc-bzr-version
100 (setq vc-bzr-version
101 (let ((s (shell-command-to-string
102 (concat (shell-quote-argument vc-bzr-program)
103 " --version"))))
104 (if (string-match "\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)$" s)
105 (list (string-to-number (match-string 1 s))
106 (string-to-number (match-string 2 s))
107 (string-to-number (match-string 3 s)))
108 '(0 0 0))))))
109
110 (defun vc-bzr-at-least-version (vers)
111 "Return t if the bzr command reports being a least version VERS.
112 First argument VERS is a list of the form (X Y Z), as returned by `vc-bzr-version'."
113 (version-list-<= vers (vc-bzr-version)))
114
115 ;; since v0.9, bzr supports removing the progress indicators
116 ;; by setting environment variable BZR_PROGRESS_BAR to "none".
117 (defun vc-bzr-command (bzr-command buffer okstatus file &rest args)
118 "Wrapper round `vc-do-command' using `vc-bzr-program' as COMMAND.
119 Invoke the bzr command adding `BZR_PROGRESS_BAR=none' to the environment."
120 (let ((process-environment
121 (list* "BZR_PROGRESS_BAR=none" ; Suppress progress output (bzr >=0.9)
122 "LC_ALL=C" ; Force English output
123 process-environment))
124 ;; bzr may attempt some kind of user interaction if its stdin/stdout
125 ;; is connected to a PTY; therefore, ask Emacs to use a pipe to
126 ;; communicate with it.
127 ;; This is redundant because vc-do-command does it already. --Stef
128 (process-connection-type nil))
129 (apply 'vc-do-command buffer okstatus vc-bzr-program
130 file bzr-command (append vc-bzr-program-args args))))
131
132 (unless (vc-bzr-at-least-version '(0 9))
133 ;; For older versions, we fall back to washing the log buffer
134 ;; when all output has been gathered.
135 (defun vc-bzr-post-command-function (command file flags)
136 "`vc-post-command-functions' function to remove progress messages."
137 ;; Note that using this requires that the vc command is run
138 ;; synchronously. Otherwise, the ^Ms in the leading progress
139 ;; message on stdout cause the stream to be interpreted as having
140 ;; DOS line endings, losing the ^Ms, so the search fails. I don't
141 ;; know how this works under Windows.
142 (when (equal command vc-bzr-program)
143 (save-excursion
144 (goto-char (point-min))
145 (if (looking-at "^\\(\r.*\r\\)[^\r]+$")
146 (replace-match "" nil nil nil 1)))
147 (save-excursion
148 (goto-char (point-min))
149 ;; This is inserted by bzr 0.11 `log', at least
150 (while (looking-at "read knit.*\n")
151 (replace-match "")))))
152
153 (add-hook 'vc-post-command-functions 'vc-bzr-post-command-function))
154
155 ;;;###autoload
156 (defconst vc-bzr-admin-dirname ".bzr") ; FIXME: "_bzr" on w32?
157
158 ;;;###autoload (defun vc-bzr-registered (file)
159 ;;;###autoload (if (vc-find-root file vc-bzr-admin-dirname)
160 ;;;###autoload (progn
161 ;;;###autoload (load "vc-bzr")
162 ;;;###autoload (vc-bzr-registered file))))
163
164 (defun vc-bzr-root-dir (file)
165 "Return the root directory in the hierarchy above FILE.
166 Return nil if there isn't one."
167 (vc-find-root file vc-bzr-admin-dirname))
168
169 (defun vc-bzr-registered (file)
170 "Return non-nil if FILE is registered with bzr."
171 (if (vc-bzr-root-dir file) ; Short cut.
172 (vc-bzr-state file))) ; Expensive.
173
174 (defun vc-bzr-buffer-nonblank-p (&optional buffer)
175 "Return non-nil if BUFFER contains any non-blank characters."
176 (or (> (buffer-size buffer) 0)
177 (save-excursion
178 (set-buffer (or buffer (current-buffer)))
179 (goto-char (point-min))
180 (re-search-forward "[^ \t\n]" (point-max) t))))
181
182 (defconst vc-bzr-state-words
183 "added\\|ignored\\|modified\\|removed\\|renamed\\|unknown"
184 "Regexp matching file status words as reported in `bzr' output.")
185
186 ;; FIXME: Also get this in a non-registered sub-directory.
187 (defun vc-bzr-state (file)
188 (with-temp-buffer
189 (cd (file-name-directory file))
190 (let ((ret (vc-bzr-command "status" t 255 file))
191 (state 'up-to-date))
192 ;; the only secure status indication in `bzr status' output
193 ;; is a couple of lines following the pattern::
194 ;; | <status>:
195 ;; | <file name>
196 ;; if the file is up-to-date, we get no status report from `bzr',
197 ;; so if the regexp search for the above pattern fails, we consider
198 ;; the file to be up-to-date.
199 (goto-char (point-min))
200 (when
201 (re-search-forward
202 (concat "^\\(" vc-bzr-state-words "\\):[ \t\n]+"
203 (file-name-nondirectory file) "[ \t\n]*$")
204 (point-max) t)
205 (let ((start (match-beginning 0))
206 (end (match-end 0)))
207 (goto-char start)
208 (setq state
209 (cond
210 ((not (equal ret 0)) nil)
211 ((looking-at "added\\|renamed\\|modified\\|removed") 'edited)
212 ((looking-at "unknown\\|ignored") nil)))
213 ;; erase the status text that matched
214 (delete-region start end)))
215 (when (vc-bzr-buffer-nonblank-p)
216 ;; "bzr" will output some warnings and informational messages
217 ;; to the user to stderr; due to Emacs' `vc-do-command' (and,
218 ;; it seems, `start-process' itself), we cannot catch stderr
219 ;; and stdout into different buffers. So, if there's anything
220 ;; left in the buffer after removing the above status
221 ;; keywords, let us just presume that any other message from
222 ;; "bzr" is a user warning, and display it.
223 (message "Warnings in `bzr' output: %s"
224 (buffer-substring (point-min) (point-max))))
225 (when state
226 (vc-file-setprop file 'vc-workfile-version
227 (vc-bzr-workfile-version file))
228 (vc-file-setprop file 'vc-state state))
229 state)))
230
231 (defun vc-bzr-workfile-unchanged-p (file)
232 (eq 'up-to-date (vc-bzr-state file)))
233
234 (defun vc-bzr-workfile-version (file)
235 ;; Looks like this could be obtained via counting lines in
236 ;; .bzr/branch/revision-history.
237 (with-temp-buffer
238 (vc-bzr-command "revno" t 0 file)
239 (goto-char (point-min))
240 (buffer-substring (point) (line-end-position))))
241
242 (defun vc-bzr-checkout-model (file)
243 'implicit)
244
245 (defun vc-bzr-register (file &optional rev comment)
246 "Register FILE under bzr.
247 Signal an error unless REV is nil.
248 COMMENT is ignored."
249 (if rev (error "Can't register explicit version with bzr"))
250 (vc-bzr-command "add" nil 0 file))
251
252 ;; Could run `bzr status' in the directory and see if it succeeds, but
253 ;; that's relatively expensive.
254 (defalias 'vc-bzr-responsible-p 'vc-bzr-root-dir
255 "Return non-nil if FILE is (potentially) controlled by bzr.
256 The criterion is that there is a `.bzr' directory in the same
257 or a superior directory.")
258
259 (defun vc-bzr-could-register (file)
260 "Return non-nil if FILE could be registered under bzr."
261 (and (vc-bzr-responsible-p file) ; shortcut
262 (condition-case ()
263 (with-temp-buffer
264 (vc-bzr-command "add" t 0 file "--dry-run")
265 ;; The command succeeds with no output if file is
266 ;; registered (in bzr 0.8).
267 (goto-char (point-min))
268 (looking-at "added "))
269 (error))))
270
271 (defun vc-bzr-unregister (file)
272 "Unregister FILE from bzr."
273 (vc-bzr-command "remove" nil 0 file))
274
275 (defun vc-bzr-checkin (file rev comment)
276 "Check FILE in to bzr with log message COMMENT.
277 REV non-nil gets an error."
278 (if rev (error "Can't check in a specific version with bzr"))
279 (vc-bzr-command "commit" nil 0 file "-m" comment))
280
281 (defun vc-bzr-checkout (file &optional editable rev destfile)
282 "Checkout revision REV of FILE from bzr to DESTFILE.
283 EDITABLE is ignored."
284 (unless destfile
285 (setq destfile (vc-version-backup-file-name file rev)))
286 (let ((coding-system-for-read 'binary)
287 (coding-system-for-write 'binary))
288 (with-temp-file destfile
289 (if rev
290 (vc-bzr-command "cat" t 0 file "-r" rev)
291 (vc-bzr-command "cat" t 0 file)))))
292
293 (defun vc-bzr-revert (file &optional contents-done)
294 (unless contents-done
295 (with-temp-buffer (vc-bzr-command "revert" t 'async file))))
296
297 (defvar log-view-message-re)
298 (defvar log-view-file-re)
299 (defvar log-view-font-lock-keywords)
300 (defvar log-view-current-tag-function)
301
302 (define-derived-mode vc-bzr-log-view-mode log-view-mode "Bzr-Log-View"
303 (remove-hook 'log-view-mode-hook 'vc-bzr-log-view-mode) ;Deactivate the hack.
304 (require 'add-log)
305 ;; Don't have file markers, so use impossible regexp.
306 (set (make-local-variable 'log-view-file-re) "\\'\\`")
307 (set (make-local-variable 'log-view-message-re)
308 "^ *-+\n *\\(?:revno: \\([0-9]+\\)\\|merged: .+\\)")
309 (set (make-local-variable 'log-view-font-lock-keywords)
310 ;; log-view-font-lock-keywords is careful to use the buffer-local
311 ;; value of log-view-message-re only since Emacs-23.
312 (append `((,log-view-message-re . 'log-view-message-face))
313 ;; log-view-font-lock-keywords
314 '(("^ *committer: \
315 \\([^<(]+?\\)[ ]*[(<]\\([[:alnum:]_.+-]+@[[:alnum:]_.-]+\\)[>)]"
316 (1 'change-log-name)
317 (2 'change-log-email))
318 ("^ *timestamp: \\(.*\\)" (1 'change-log-date-face))))))
319
320 (defun vc-bzr-print-log (file &optional buffer) ; get buffer arg in Emacs 22
321 "Get bzr change log for FILE into specified BUFFER."
322 ;; Fixme: This might need the locale fixing up if things like `revno'
323 ;; got localized, but certainly it shouldn't use LC_ALL=C.
324 ;; NB. Can't be async -- see `vc-bzr-post-command-function'.
325 (vc-bzr-command "log" buffer 0 file)
326 ;; FIXME: Until Emacs-23, VC was missing a hook to sort out the mode for
327 ;; the buffer, or at least set the regexps right.
328 (unless (fboundp 'vc-default-log-view-mode)
329 (add-hook 'log-view-mode-hook 'vc-bzr-log-view-mode)))
330
331 (defun vc-bzr-show-log-entry (version)
332 "Find entry for patch name VERSION in bzr change log buffer."
333 (goto-char (point-min))
334 (let (case-fold-search)
335 (if (re-search-forward (concat "^-+\nrevno: " version "$") nil t)
336 (beginning-of-line 0)
337 (goto-char (point-min)))))
338
339 ;; Fixem: vc-bzr-wash-log
340
341 (autoload 'vc-diff-switches-list "vc" nil nil t)
342
343 (defun vc-bzr-diff (file &optional rev1 rev2 buffer)
344 "VC bzr backend for diff."
345 (let ((working (vc-workfile-version file)))
346 (if (and (equal rev1 working) (not rev2))
347 (setq rev1 nil))
348 (if (and (not rev1) rev2)
349 (setq rev1 working))
350 ;; NB. Can't be async -- see `vc-bzr-post-command-function'.
351 ;; bzr diff produces condition code 1 for some reason.
352 (apply #'vc-bzr-command "diff" (or buffer "*vc-diff*") 1 file
353 "--diff-options" (mapconcat 'identity (vc-diff-switches-list bzr)
354 " ")
355 (when rev1
356 (if rev2
357 (list "-r" (format "%s..%s" rev1 rev2))
358 (list "-r" rev1))))))
359
360 (defalias 'vc-bzr-diff-tree 'vc-bzr-diff)
361
362 ;; Fixme: implement vc-bzr-dir-state, vc-bzr-dired-state-info
363
364 ;; Fixme: vc-{next,previous}-version need fixing in vc.el to deal with
365 ;; straight integer versions.
366
367 (defun vc-bzr-delete-file (file)
368 "Delete FILE and delete it in the bzr repository."
369 (condition-case ()
370 (delete-file file)
371 (file-error nil))
372 (vc-bzr-command "remove" nil 0 file))
373
374 (defun vc-bzr-rename-file (old new)
375 "Rename file from OLD to NEW using `bzr mv'."
376 (vc-bzr-command "mv" nil 0 new old))
377
378 (defvar vc-bzr-annotation-table nil
379 "Internal use.")
380 (make-variable-buffer-local 'vc-bzr-annotation-table)
381
382 (defun vc-bzr-annotate-command (file buffer &optional version)
383 "Prepare BUFFER for `vc-annotate' on FILE.
384 Each line is tagged with the revision number, which has a `help-echo'
385 property containing author and date information."
386 (apply #'vc-bzr-command "annotate" buffer 0 file "-l" "--all"
387 (if version (list "-r" version)))
388 (with-current-buffer buffer
389 ;; Store the tags for the annotated source lines in a hash table
390 ;; to allow saving space by sharing the text properties.
391 (setq vc-bzr-annotation-table (make-hash-table :test 'equal))
392 (goto-char (point-min))
393 (while (re-search-forward "^\\( *[0-9]+\\) \\(.+\\) +\\([0-9]\\{8\\}\\) |"
394 nil t)
395 (let* ((rev (match-string 1))
396 (author (match-string 2))
397 (date (match-string 3))
398 (key (match-string 0))
399 (tag (gethash key vc-bzr-annotation-table)))
400 (unless tag
401 (save-match-data
402 (string-match " +\\'" author)
403 (setq author (substring author 0 (match-beginning 0))))
404 (setq tag (propertize rev 'help-echo (concat "Author: " author
405 ", date: " date)
406 'mouse-face 'highlight))
407 (puthash key tag vc-bzr-annotation-table))
408 (replace-match "")
409 (insert tag " |")))))
410
411 ;; Definition from Emacs 22
412 (unless (fboundp 'vc-annotate-convert-time)
413 (defun vc-annotate-convert-time (time)
414 "Convert a time value to a floating-point number of days.
415 The argument TIME is a list as returned by `current-time' or
416 `encode-time', only the first two elements of that list are considered."
417 (/ (+ (* (float (car time)) (lsh 1 16)) (cadr time)) 24 3600)))
418
419 (defun vc-bzr-annotate-time ()
420 (when (re-search-forward "^ *[0-9]+ |" nil t)
421 (let ((prop (get-text-property (line-beginning-position) 'help-echo)))
422 (string-match "[0-9]+\\'" prop)
423 (vc-annotate-convert-time
424 (encode-time 0 0 0
425 (string-to-number (substring (match-string 0 prop) 6 8))
426 (string-to-number (substring (match-string 0 prop) 4 6))
427 (string-to-number (substring (match-string 0 prop) 0 4))
428 )))))
429
430 (defun vc-bzr-annotate-extract-revision-at-line ()
431 "Return revision for current line of annoation buffer, or nil.
432 Return nil if current line isn't annotated."
433 (save-excursion
434 (beginning-of-line)
435 (if (looking-at " *\\([0-9]+\\) | ")
436 (match-string-no-properties 1))))
437
438 ;; Not needed for Emacs 22
439 (defun vc-bzr-annotate-difference (point)
440 (let ((next-time (vc-bzr-annotate-time)))
441 (if next-time
442 (- (vc-annotate-convert-time (current-time)) next-time))))
443
444 ;; FIXME: `bzr root' will return the real path to the repository root,
445 ;; that is, it can differ from the buffer's current directory name
446 ;; if there are any symbolic links.
447 (defun vc-bzr-root (dir)
448 "Return the root directory of the bzr repository containing DIR."
449 ;; Cache technique copied from vc-arch.el.
450 (or (vc-file-getprop dir 'bzr-root)
451 (vc-file-setprop
452 dir 'bzr-root
453 (substring
454 (shell-command-to-string (concat vc-bzr-program " root " dir)) 0 -1))))
455
456 ;; TODO: it would be nice to mark the conflicted files in VC Dired,
457 ;; and implement a command to run ediff and `bzr resolve' once the
458 ;; changes have been merged.
459 (defun vc-bzr-dir-state (dir &optional localp)
460 "Find the VC state of all files in DIR.
461 Optional argument LOCALP is always ignored."
462 (let ((bzr-root-directory (vc-bzr-root dir))
463 (at-start t)
464 current-bzr-state current-vc-state)
465 ;; Check that DIR is a bzr repository.
466 (unless (file-name-absolute-p bzr-root-directory)
467 (error "Cannot find bzr repository for directory `%s'" dir))
468 ;; `bzr ls --versioned' lists all versioned files;
469 ;; assume they are up-to-date, unless we are given
470 ;; evidence of the contrary.
471 (setq at-start t)
472 (with-temp-buffer
473 (vc-bzr-command "ls" t 0 nil "--versioned" "--non-recursive")
474 (goto-char (point-min))
475 (while (or at-start
476 (eq 0 (forward-line)))
477 (setq at-start nil)
478 (let ((file (expand-file-name
479 (buffer-substring-no-properties
480 (line-beginning-position) (line-end-position))
481 bzr-root-directory)))
482 (vc-file-setprop file 'vc-state 'up-to-date)
483 ;; XXX: is this correct? what happens if one
484 ;; mixes different SCMs in the same dir?
485 (vc-file-setprop file 'vc-backend 'BZR))))
486 ;; `bzr status' reports on added/modified/renamed and unknown/ignored files
487 (setq at-start t)
488 (with-temp-buffer
489 (vc-bzr-command "status" t 0 nil)
490 (goto-char (point-min))
491 (while (or at-start
492 (eq 0 (forward-line)))
493 (setq at-start nil)
494 (cond
495 ((looking-at "^added")
496 (setq current-vc-state 'edited)
497 (setq current-bzr-state 'added))
498 ((looking-at "^modified")
499 (setq current-vc-state 'edited)
500 (setq current-bzr-state 'modified))
501 ((looking-at "^renamed")
502 (setq current-vc-state 'edited)
503 (setq current-bzr-state 'renamed))
504 ((looking-at "^\\(unknown\\|ignored\\)")
505 (setq current-vc-state nil)
506 (setq current-bzr-state 'not-versioned))
507 ((looking-at " ")
508 ;; file names are indented by two spaces
509 (when current-vc-state
510 (let ((file (expand-file-name
511 (buffer-substring-no-properties
512 (match-end 0) (line-end-position))
513 bzr-root-directory)))
514 (vc-file-setprop file 'vc-state current-vc-state)
515 (vc-file-setprop file 'vc-bzr-state current-bzr-state)
516 (when (eq 'added current-bzr-state)
517 (vc-file-setprop file 'vc-workfile-version "0"))))
518 (when (eq 'not-versioned current-bzr-state)
519 (let ((file (expand-file-name
520 (buffer-substring-no-properties
521 (match-end 0) (line-end-position))
522 bzr-root-directory)))
523 (vc-file-setprop file 'vc-backend 'none)
524 (vc-file-setprop file 'vc-state nil))))
525 (t
526 ;; skip this part of `bzr status' output
527 (setq current-vc-state nil)
528 (setq current-bzr-state nil)))))))
529
530 (defun vc-bzr-dired-state-info (file)
531 "Bzr-specific version of `vc-dired-state-info'."
532 (if (eq 'edited (vc-state file))
533 (let ((bzr-state (vc-file-getprop file 'vc-bzr-state)))
534 (if bzr-state
535 (concat "(" (symbol-name bzr-state) ")")
536 ;; else fall back to default vc representation
537 (vc-default-dired-state-info 'BZR file)))))
538
539 ;; In case of just `(load "vc-bzr")', but that's probably the wrong
540 ;; way to do it.
541 (add-to-list 'vc-handled-backends 'BZR)
542
543 (eval-after-load "vc"
544 '(add-to-list 'vc-directory-exclusion-list ".bzr" t))
545
546 (defconst vc-bzr-unload-hook
547 (lambda ()
548 (setq vc-handled-backends (delq 'BZR vc-handled-backends))
549 (remove-hook 'vc-post-command-functions 'vc-bzr-post-command-function)))
550
551 (provide 'vc-bzr)
552 ;; arch-tag: 8101bad8-4e92-4e7d-85ae-d8e08b4e7c06
553 ;;; vc-bzr.el ends here