update subrepo elisp-vcs

This commit is contained in:
Kai Tetzlaff 2011-04-24 09:16:02 +02:00
parent 7473bfb2cb
commit b10fbbad5b
17 changed files with 1021 additions and 711 deletions

View File

@ -53,6 +53,7 @@ install: all
echo Installing $$elc ; \
$(INSTALL_DATA) $$elc "$(lispdir)" ; \
done
$(INSTALL_DATA) xmtn-hooks.lua $(lispdir)
clean:
rm -f *.elc dvc-site.el \

View File

@ -1,6 +1,6 @@
;;; dvc-buffers.el --- Buffer management for DVC
;; Copyright (C) 2005-2010 by all contributors
;; Copyright (C) 2005-2011 by all contributors
;; Author: Matthieu Moy <Matthieu.Moy@imag.fr>
;; Contributions from:
@ -178,8 +178,9 @@ See also `dvc-get-buffer'"
(eq mode 'string-multiple))
(generate-new-buffer (format name path))
(let ((default-directory
(or (file-name-directory path)
default-directory)))
(if (file-name-directory path)
(expand-file-name (file-name-directory path))
default-directory)))
(dvc-create-buffer name)))))
(with-current-buffer buffer
(if (featurep 'xemacs)

View File

@ -1,7 +1,7 @@
;;; dvc-fileinfo.el --- An ewoc structure for displaying file information
;;; for DVC
;; Copyright (C) 2007 - 2010 by all contributors
;; Copyright (C) 2007 - 2011 by all contributors
;; Author: Stephen Leake, <stephen_leake@stephe-leake.org>
@ -553,42 +553,8 @@ in that directory. Then move to previous ewoc entry."
(otherwise
(error "not on a file or directory")))))
(defun dvc-fileinfo-next (&optional no-ding)
"Move to the next ewoc entry. If optional NO-DING, don't ding
if there is no next."
(interactive)
(let* ((current (ewoc-locate dvc-fileinfo-ewoc))
(cur-location (ewoc-location current))
(next (ewoc-next dvc-fileinfo-ewoc current)))
(cond
((> cur-location (point))
;; not exactly at an element; move there
(goto-char cur-location))
(next
(goto-char (ewoc-location next)))
(t
;; at last element
(unless no-ding (ding))))))
(defun dvc-fileinfo-prev (&optional no-ding)
"Move to the previous ewoc entry. If optional NO-DING, don't ding
if there is no prev."
(interactive)
(let* ((current (ewoc-locate dvc-fileinfo-ewoc))
(cur-location (ewoc-location current))
(prev (ewoc-prev dvc-fileinfo-ewoc current)))
(cond
((> (point) cur-location)
(goto-char cur-location))
(prev
(goto-char (ewoc-location prev)))
(t
;; at first element
(unless no-ding (ding))))))
(dvc-make-ewoc-next dvc-fileinfo-next dvc-fileinfo-ewoc)
(dvc-make-ewoc-prev dvc-fileinfo-prev dvc-fileinfo-ewoc)
(defun dvc-fileinfo-find-file (file)
"Return ewoc element for FILE (full path)."

View File

@ -1,6 +1,6 @@
;;; dvc-log.el --- Manipulation of the log before committing
;; Copyright (C) 2005-2008 by all contributors
;; Copyright (C) 2005-2008, 2010 by all contributors
;; Author: Matthieu Moy <Matthieu.Moy@imag.fr>
;; Contributions from:
@ -121,7 +121,7 @@ is reused."
(current-window-configuration))
(let ((start-buffer (current-buffer)))
(dvc-switch-to-buffer
(dvc-get-buffer-create (dvc-current-active-dvc) 'log-edit)
(dvc-get-buffer-create (dvc-current-active-dvc) 'log-edit root)
other-frame)
;; `no-init' is somewhat misleading here. It is set to t in
;; dvc-add-log-entry, and nil in dvc-log-edit. That prevents

View File

@ -1,6 +1,6 @@
;;; dvc-status.el --- A generic status mode for DVC
;; Copyright (C) 2007 - 2009 by all contributors
;; Copyright (C) 2007 - 2009, 2011 by all contributors
;; Author: Stephen Leake, <stephen_leake@stephe-leake.org>
@ -32,12 +32,12 @@
(require 'uniquify)
(defcustom dvc-status-display-known nil
"If non-nil, display files with 'known' status in xmtn-status buffer."
"If non-nil, display files with 'known' status in dvc-status buffer."
:type 'boolean
:group 'dvc)
(defcustom dvc-status-display-ignored nil
"If non-nil, display files with 'ignored' status in xmtn-status buffer."
"If non-nil, display files with 'ignored' status in dvc-status buffer."
:type 'boolean
:group 'dvc)
@ -126,8 +126,7 @@
;; "<back-end>-status-mode", if defined, will be used instead of this
;; one. If so, it should be derived from dvc-status-mode (via
;; `define-derived-mode'), and rely on it for as many features as
;; possible (one can, for example, extend the menu and keymap). See
;; `xmtn-status-mode' in xmtn-dvc.el for a good example.
;; possible (one can, for example, extend the menu and keymap).
;; Remember to add the new mode to uniquify-list-buffers-directory-modes
(define-derived-mode dvc-status-mode fundamental-mode "dvc-status"
"Major mode to display workspace status."

View File

@ -287,15 +287,23 @@ If DONT-SWITCH is non-nil, just show the diff buffer, don't select it."
buffer file name; nil means entire tree; negative prefix arg
means prompt for tree depending on value of
dvc-read-project-tree-mode), LAST-N entries (default
`dvc-log-last-n'; all if nil, positive prefix value means that
many entries). Use `dvc-changelog' for the full log."
`dvc-log-last-n'; all if nil, prefix value means that
many entries (absolute value)). Use `dvc-changelog' for the full log."
(interactive "i\nP")
<<<<<<< TREE
(let* ((allentries (or (eq last-n nil)
(< (prefix-numeric-value last-n) 0)))
(last-n (prefix-numeric-value last-n))
(path (if (< last-n 0)
nil (buffer-file-name)))
(last-n (if allentries nil last-n))
=======
(let* ((path (if (and last-n (< (prefix-numeric-value last-n) 0))
nil (buffer-file-name)))
(last-n (if last-n
(abs (prefix-numeric-value last-n))
dvc-log-last-n))
>>>>>>> MERGE-SOURCE
(default-directory
(dvc-read-project-tree-maybe "DVC tree root (directory): "
(when path (expand-file-name path))

View File

@ -1,6 +1,6 @@
;;; xmtn-automate.el --- Interface to monotone's "automate" functionality
;; Copyright (C) 2008 - 2010 Stephen Leake
;; Copyright (C) 2008 - 2011 Stephen Leake
;; Copyright (C) 2006, 2007 Christian M. Ohler
;; Author: Christian M. Ohler
@ -131,7 +131,7 @@ workspace root."
(buffer-substring-no-properties (point-min) (point-max))
(xmtn-automate--cleanup-command handle))))
(defun xmtn-automate-simple-command-output-string (root command)
(defun xmtn-automate-command-output-string (root command)
"Send COMMAND to session for ROOT. Return result as a string."
(let* ((session (xmtn-automate-cache-session root))
(command-handle (xmtn-automate--new-command session command)))
@ -149,34 +149,37 @@ workspace root."
(xmtn-automate-command-buffer command-handle)))
(xmtn-automate--cleanup-command command-handle)))
(defun xmtn-automate-command-output-lines (handle)
"Return list of lines of output in HANDLE; first line output is
first in list."
(xmtn-automate-command-wait-until-finished handle)
(with-current-buffer (xmtn-automate-command-buffer handle)
(goto-char (point-min))
(let (result)
(while (< (point) (point-max))
(setq result (cons (buffer-substring-no-properties
(point)
(progn (end-of-line) (point)))
result))
(forward-line 1))
(xmtn-automate--cleanup-command handle)
(nreverse result))))
(defun xmtn-automate-command-output-file (root file command)
"Send COMMAND to session for ROOT, store result in FILE."
(let* ((session (xmtn-automate-cache-session root))
(command-handle (xmtn-automate--new-command session command nil nil)))
(xmtn-automate-command-wait-until-finished command-handle)
(with-current-buffer (xmtn-automate-command-buffer command-handle)
(write-region nil nil file))
(xmtn-automate--cleanup-command command-handle)))
(defun xmtn-automate-simple-command-output-lines (root command)
(defun xmtn-automate-command-output-lines (root command)
"Return list of strings containing output of COMMAND, one line per
string."
(let* ((session (xmtn-automate-cache-session root))
(command-handle (xmtn-automate--new-command session command)))
(xmtn-automate-command-output-lines command-handle)))
(handle (xmtn-automate--new-command session command)))
(xmtn-automate-command-wait-until-finished handle)
(with-current-buffer (xmtn-automate-command-buffer handle)
(goto-char (point-max))
(let (result)
(while (= 0 (forward-line -1))
(setq result (cons (buffer-substring-no-properties
(point)
(progn (end-of-line) (point)))
result)))
(xmtn-automate--cleanup-command handle)
result))))
(defun xmtn-automate-simple-command-output-line (root command)
(defun xmtn-automate-command-output-line (root command)
"Return the one line output from mtn automate as a string.
Signals an error if output contains zero lines or more than one line."
(let ((lines (xmtn-automate-simple-command-output-lines root command)))
(let ((lines (xmtn-automate-command-output-lines root command)))
(unless (eql (length lines) 1)
(error "Expected precisely one line of output from mtn automate, got %s: %s %S"
(length lines)
@ -287,12 +290,14 @@ Signals an error if output contains zero lines or more than one line."
(defun xmtn-automate-kill-session (root)
"Kill session for ROOT."
(interactive)
(let ((temp (assoc (dvc-uniquify-file-name root) xmtn-automate--*sessions*)))
(let ((session (assoc (dvc-uniquify-file-name root) xmtn-automate--*sessions*)))
;; session may have already been killed
(when temp
(xmtn-automate--close-session (cdr temp))
(when session
(when (xmtn-automate--session-error-file (cdr session))
(delete-file (xmtn-automate--session-error-file session)))
(xmtn-automate--close-session (cdr session))
(setq xmtn-automate--*sessions*
(delete temp xmtn-automate--*sessions* )))))
(delete session xmtn-automate--*sessions*)))))
(defun xmtn-kill-all-sessions ()
"Kill all xmtn-automate sessions."
@ -671,7 +676,7 @@ Each element of the list is a list; key, signature, name, value, trust."
accu))
(defun xmtn--heads (root branch)
(xmtn-automate-simple-command-output-lines
(xmtn-automate-command-output-lines
root
(cons
(list "ignore-suspend-certs" "")
@ -679,8 +684,33 @@ Each element of the list is a list; key, signature, name, value, trust."
(or branch
(xmtn--tree-default-branch root))))))
(defun xmtn--rev-author (root rev)
"Return first author of REV"
(let (cert-name
result)
(with-temp-buffer
(xmtn-automate-command-output-buffer root (current-buffer) (list "certs" rev))
(goto-char (point-min))
;; key [46ec58576f9e4f34a9eede521422aa5fd299dc50]
;; signature "ok"
;; name "author"
;; value "beth"
;; trust "trusted"
;;
;; ...
(while (not result)
(xmtn-basic-io-skip-line "key")
(xmtn-basic-io-skip-line "signature")
(xmtn-basic-io-check-line "name" (setq cert-name (cadar value)))
(xmtn-basic-io-check-line "value"
(if (string= cert-name "author")
(setq result (cadar value))))
(xmtn-basic-io-skip-line "trust")
(xmtn-basic-io-check-empty)))
result))
(defun xmtn--tree-default-branch (root)
(xmtn-automate-simple-command-output-line root `("get_option" "branch")))
(xmtn-automate-command-output-line root `("get_option" "branch")))
(defun xmtn--get-corresponding-path-raw (root normalized-file-name
source-revision-hash-id

View File

@ -1,6 +1,6 @@
;;; xmtn-conflicts.el --- conflict resolution for DVC backend for monotone
;; Copyright (C) 2008 - 2010 Stephen Leake
;; Copyright (C) 2008 - 2011 Stephen Leake
;; Author: Stephen Leake
;; Keywords: tools
@ -44,34 +44,38 @@
(defvar xmtn-conflicts-left-work ""
"Buffer-local variable holding left workspace root.")
(make-variable-buffer-local 'xmtn-conflicts-left-work)
(put 'xmtn-conflicts-left-work 'permanent-local t)
(defvar xmtn-conflicts-right-work ""
"Buffer-local variable holding right workspace root.")
(make-variable-buffer-local 'xmtn-conflicts-right-work)
(put 'xmtn-conflicts-right-work 'permanent-local t)
(defvar xmtn-conflicts-left-root ""
(defvar xmtn-conflicts-left-resolution-root ""
"Buffer-local variable holding left resolution root directory
name; relative to workspace root.")
(make-variable-buffer-local 'xmtn-conflicts-left-root)
(make-variable-buffer-local 'xmtn-conflicts-left-resolution-root)
(defvar xmtn-conflicts-right-root ""
(defvar xmtn-conflicts-right-resolution-root ""
"Buffer-local variable holding right resolution root directory
name; relative to workspace root.")
(make-variable-buffer-local 'xmtn-conflicts-right-root)
(make-variable-buffer-local 'xmtn-conflicts-right-resolution-root)
(defvar xmtn-conflicts-left-branch ""
"Buffer-local variable holding left resolution branch.")
"Buffer-local variable holding left branch.")
(make-variable-buffer-local 'xmtn-conflicts-left-branch)
(put 'xmtn-conflicts-left-branch 'permanent-local t)
(defvar xmtn-conflicts-right-branch ""
"Buffer-local variable holding right resolution branch.")
"Buffer-local variable holding right branch.")
(make-variable-buffer-local 'xmtn-conflicts-right-branch)
(put 'xmtn-conflicts-right-branch 'permanent-local t)
(defvar xmtn-conflicts-ancestor-revision ""
(defvar xmtn-conflicts-left-author ""
"Buffer-local variable holding left author.")
(make-variable-buffer-local 'xmtn-conflicts-left-author)
(defvar xmtn-conflicts-right-author ""
"Buffer-local variable holding right branch.")
(make-variable-buffer-local 'xmtn-conflicts-right-author)
(defvar xmtn-conflicts-ancestor-revision nil
"Buffer-local variable holding ancestor revision id.")
(make-variable-buffer-local 'xmtn-conflicts-ancestor-revision)
@ -87,10 +91,6 @@
"Count of resolved-internal conflicts.")
(make-variable-buffer-local 'xmtn-conflicts-resolved-internal-count)
(defvar xmtn-conflicts-output-buffer nil
"Buffer to write basic-io to, when saving a conflicts buffer.")
(make-variable-buffer-local 'xmtn-conflicts-output-buffer)
(defvar xmtn-conflicts-current-conflict-buffer nil
"Global variable for use in ediff quit hook.")
;; xmtn-conflicts-current-conflict-buffer cannot be buffer local,
@ -185,8 +185,8 @@ The elements must all be of type xmtn-conflicts-conflict.")
(make-variable-buffer-local 'xmtn-conflicts-ewoc)
(defun xmtn-conflicts-parse-header ()
"Fill `xmtn-conflicts-left-revision', `xmtn-conflicts-left-root',
`xmtn-conflicts-right-revision', `xmtn-conflicts-right-root'
"Fill `xmtn-conflicts-left-revision', `xmtn-conflicts-left-resolution-root',
`xmtn-conflicts-right-revision', `xmtn-conflicts-right-resolution-root'
`xmtn-conflicts-ancestor-revision' with data from conflict
header."
;; left [9a019f3a364416050a8ff5c05f1e44d67a79e393]
@ -201,15 +201,16 @@ header."
(setq xmtn-conflicts-ancestor-revision (cadar value)))
(xmtn-basic-io-check-empty)
;; xmtn-conflicts-left-branch xmtn-conflicts-right-branch set by xmtn-conflicts-load-opts
;; xmtn-conflicts-left-branch, -right-branch, -left-author,
;; -right-author set by xmtn-conflicts-load-opts
(if (string= xmtn-conflicts-left-branch xmtn-conflicts-right-branch)
(progn
(setq xmtn-conflicts-left-root "_MTN/resolutions/left")
(setq xmtn-conflicts-right-root "_MTN/resolutions/right"))
(setq xmtn-conflicts-left-resolution-root "_MTN/resolutions/left")
(setq xmtn-conflicts-right-resolution-root "_MTN/resolutions/right"))
(progn
(setq xmtn-conflicts-left-root (concat "_MTN/resolutions/" xmtn-conflicts-left-branch))
(setq xmtn-conflicts-right-root (concat "_MTN/resolutions/" xmtn-conflicts-right-branch))))
(setq xmtn-conflicts-left-resolution-root (concat "_MTN/resolutions/" xmtn-conflicts-left-branch))
(setq xmtn-conflicts-right-resolution-root (concat "_MTN/resolutions/" xmtn-conflicts-right-branch))))
(setq xmtn-conflicts-total-count 0)
(setq xmtn-conflicts-resolved-count 0)
(setq xmtn-conflicts-resolved-internal-count 0)
@ -476,7 +477,9 @@ header."
xmtn-conflicts-ewoc
(concat
(format " Left branch : %s\n" xmtn-conflicts-left-branch)
(format " Left author : %s\n" xmtn-conflicts-left-author)
(format " Right branch : %s\n" xmtn-conflicts-right-branch)
(format " Right author : %s\n" xmtn-conflicts-right-author)
(format " Total conflicts : %d\n" xmtn-conflicts-total-count)
(format "Resolved conflicts : %d\n" xmtn-conflicts-resolved-count)
)
@ -491,10 +494,13 @@ header."
(goto-char begin)
(xmtn-conflicts-parse-header)
(if xmtn-conflicts-ancestor-revision
;; if there is no ancestor revision, then left is ancestor of
;; right or vice versa, and there can be no conflicts.
(xmtn-conflicts-parse-conflicts (1- end)); off-by-one somewhere.
;; else no conflicts
)
(let ((inhibit-read-only t)) (delete-region begin (1- end)))
(xmtn-conflicts-load-opts)
(xmtn-conflicts-set-hf)
(set-buffer-modified-p nil)
(point-max))
@ -509,7 +515,7 @@ header."
;; point, and inserts empty header and footer lines.
(goto-char (point-max))
(let ((text-end (point)))
(xmtn-conflicts-mode)
(xmtn-conflicts-mode) ;; kills non-permanent buffer-local variables
(xmtn-conflicts-read (point-min) text-end))
(set-buffer-modified-p nil)
@ -517,10 +523,10 @@ header."
(xmtn-conflicts-next nil t))
(defun xmtn-conflicts-write-header (ewoc-buffer)
"Write EWOC-BUFFER header info in basic-io format to current buffer."
"Write revisions from EWOC-BUFFER header info in basic-io format to current buffer."
(xmtn-basic-io-write-id "left" (with-current-buffer ewoc-buffer xmtn-conflicts-left-revision))
(xmtn-basic-io-write-id "right" (with-current-buffer ewoc-buffer xmtn-conflicts-right-revision))
(if xmtn-conflicts-ancestor-revision
(if (with-current-buffer ewoc-buffer xmtn-conflicts-ancestor-revision)
(xmtn-basic-io-write-id "ancestor" (with-current-buffer ewoc-buffer xmtn-conflicts-ancestor-revision)))
)
@ -672,13 +678,13 @@ header."
(xmtn-basic-io-write-str "resolved_rename_left" (cadr (xmtn-conflicts-conflict-left_resolution conflict))))
))))
(defun xmtn-conflicts-write-conflicts (ewoc)
"Write EWOC elements in basic-io format to xmtn-conflicts-output-buffer."
(defun xmtn-conflicts-write-conflicts (ewoc buffer)
"Write EWOC elements in basic-io format to BUFFER."
(setq xmtn-conflicts-resolved-count 0)
(setq xmtn-conflicts-resolved-internal-count 0)
(ewoc-map
(lambda (conflict)
(with-current-buffer xmtn-conflicts-output-buffer
(with-current-buffer buffer
(ecase (xmtn-conflicts-conflict-conflict_type conflict)
(content
(xmtn-conflicts-write-content conflict))
@ -693,20 +699,16 @@ header."
"Replace region BEGIN END with EWOC-BUFFER ewoc in basic-io format."
(delete-region begin end)
(xmtn-conflicts-write-header ewoc-buffer)
;; ewoc-map sets current-buffer to ewoc-buffer, so we need a
;; reference to the current buffer.
(let ((xmtn-conflicts-output-buffer (current-buffer))
(ewoc (with-current-buffer ewoc-buffer xmtn-conflicts-ewoc)))
(xmtn-conflicts-write-conflicts ewoc)
(with-current-buffer ewoc-buffer (xmtn-conflicts-set-hf))
(let ((ewoc (with-current-buffer ewoc-buffer xmtn-conflicts-ewoc)))
(xmtn-conflicts-write-conflicts ewoc (current-buffer))
;; 'update' not needed for save, but it's nice for the user
(with-current-buffer ewoc-buffer (xmtn-conflicts-update-counts))
))
;; Arrange for xmtn-conflicts-save to be called by save-buffer. We do
;; not automatically convert in insert-file-contents, because we don't
;; want to convert _all_ conflict files (consider the monotone test
;; suite!). Instead, we call xmtn-conflicts-read explicitly from
;; xmtn-conflicts-review, and set after-insert-file-functions to a
;; buffer-local value in xmtn-conflicts-mode.
;; Arrange for xmtn-conflicts-save to be called by save-buffer. We
;; also set after-insert-file-functions to a buffer-local value in
;; xmtn-conflicts-mode.
(add-to-list 'format-alist
'(xmtn-conflicts-format
"Save conflicts in basic-io format."
@ -719,6 +721,7 @@ header."
(defun xmtn-conflicts-update-counts ()
"Update resolved counts."
(interactive)
(setq xmtn-conflicts-resolved-count 0)
(setq xmtn-conflicts-resolved-internal-count 0)
@ -742,7 +745,8 @@ header."
(setq xmtn-conflicts-resolved-count (+ 1 xmtn-conflicts-resolved-count))))
))
xmtn-conflicts-ewoc))
xmtn-conflicts-ewoc)
(xmtn-conflicts-set-hf))
(dvc-make-ewoc-next xmtn-conflicts-next xmtn-conflicts-ewoc)
(dvc-make-ewoc-prev xmtn-conflicts-prev xmtn-conflicts-ewoc)
@ -845,11 +849,11 @@ header."
(xmtn-conflicts-conflict-ancestor_name conflict))))
(file-left (xmtn-conflicts-get-file xmtn-conflicts-left-work
(xmtn-conflicts-conflict-left_file_id conflict)
xmtn-conflicts-left-root
xmtn-conflicts-left-resolution-root
(xmtn-conflicts-conflict-left_name conflict)))
(file-right (xmtn-conflicts-get-file xmtn-conflicts-right-work
(xmtn-conflicts-conflict-right_file_id conflict)
xmtn-conflicts-right-root
xmtn-conflicts-right-resolution-root
(xmtn-conflicts-conflict-right_name conflict)))
(result-file (concat "_MTN/resolutions/result/" (xmtn-conflicts-conflict-right_name conflict))) )
@ -1137,22 +1141,6 @@ non-nil, show log-edit buffer in other frame."
(insert ": ")
))
(defun xmtn-conflicts-do-propagate (&optional cached-branch)
"Perform propagate on revisions in current conflict buffer."
(interactive)
(save-some-buffers t); log buffer
;; save-some-buffers does not save the conflicts buffer, which is the current buffer
(save-buffer)
(xmtn-propagate-from xmtn-conflicts-left-branch cached-branch))
(defun xmtn-conflicts-do-merge ()
"Perform merge on revisions in current conflict buffer."
(interactive)
(save-some-buffers t); log buffer
;; save-some-buffers does not save the conflicts buffer, which is the current buffer
(save-buffer)
(xmtn-dvc-merge-1 default-directory nil))
(defun xmtn-conflicts-ediff-resolution-ws ()
"Ediff current resolution file against workspace."
(interactive)
@ -1177,22 +1165,18 @@ non-nil, show log-edit buffer in other frame."
(define-key map [?q] 'dvc-buffer-quit)
(define-key map [?r] xmtn-conflicts-resolve-map)
(define-key map [?t] 'xmtn-conflicts-add-log-entry)
(define-key map [?u] 'xmtn-conflicts-update-counts)
(define-key map "\M-d" xmtn-conflicts-resolve-map)
(define-key map "MM" 'xmtn-conflicts-do-merge)
(define-key map "MP" 'xmtn-conflicts-do-propagate)
(define-key map "MU" 'dvc-update)
map)
"Keymap used in `xmtn-conflicts-mode'.")
(easy-menu-define xmtn-conflicts-mode-menu xmtn-conflicts-mode-map
"`xmtn-conflicts' menu"
`("Mtn-conflicts"
["Clear resolution" xmtn-conflicts-clear-resolution t]
["Clear resolution" xmtn-conflicts-clear-resolution t]
["Ediff resolution to ws" xmtn-conflicts-ediff-resolution-ws t]
["Propagate" xmtn-conflicts-do-propagate t]
["Merge" xmtn-conflicts-do-merge t]
["Update" dvc-update t]
["Clean" xmtn-conflicts-clean t]
["Add log entry" xmtn-conflicts-add-log-entry t]
["Clean" xmtn-conflicts-clean t]
))
;; derive from nil causes no keymap to be used, but still have self-insert keys
@ -1217,20 +1201,23 @@ non-nil, show log-edit buffer in other frame."
(defconst xmtn-conflicts-opts-file "_MTN/dvc-conflicts-opts")
(defun xmtn-conflicts-save-opts (left-work right-work &optional left-branch right-branch)
"Store LEFT-WORK, RIGHT-WORK in `xmtn-conflicts-opts-file', for
(defun xmtn-conflicts-save-opts (left-work right-work left-branch right-branch left-rev right-rev)
"Store LEFT-*, RIGHT-* in `xmtn-conflicts-opts-file', for
retrieval by `xmtn-conflicts-load-opts'."
;; need correct buffer-local variable names for load-opts
(let ((xmtn-conflicts-left-work left-work)
(xmtn-conflicts-right-work right-work)
(xmtn-conflicts-left-branch (or left-branch
(xmtn--tree-default-branch left-work)))
(xmtn-conflicts-right-branch (or right-branch
(xmtn--tree-default-branch right-work))))
(xmtn-conflicts-left-branch left-branch)
(xmtn-conflicts-right-branch right-branch)
(xmtn-conflicts-left-author (xmtn--rev-author left-work left-rev))
(xmtn-conflicts-right-author (xmtn--rev-author right-work right-rev)))
(dvc-save-state (list 'xmtn-conflicts-left-work
'xmtn-conflicts-left-branch
'xmtn-conflicts-left-author
'xmtn-conflicts-right-work
'xmtn-conflicts-right-branch)
'xmtn-conflicts-right-branch
'xmtn-conflicts-right-author)
(concat (file-name-as-directory right-work) xmtn-conflicts-opts-file))
))
@ -1244,132 +1231,88 @@ root where options file is stored."
;; When reviewing conflicts after a merge is complete, the options file is not present
(message "%s options file not found" opts-file))))
(defun xmtn-conflicts-1 (left-work left-rev right-work right-rev)
(defun xmtn-conflicts-load-file ()
"Load _MTN/conflicts for default-directory."
(dvc-switch-to-buffer-maybe (dvc-get-buffer-create 'xmtn 'conflicts default-directory))
(setq buffer-read-only nil)
(set (make-local-variable 'after-insert-file-functions) '(xmtn-conflicts-after-insert-file))
(insert-file-contents "_MTN/conflicts" t nil nil t))
(defun xmtn-conflicts-1 (left-work left-rev right-work right-rev &optional left-branch right-branch)
"List conflicts between LEFT-REV and RIGHT-REV
revisions (monotone revision specs; if nil, defaults to heads of
respective workspace branches) in LEFT-WORK and RIGHT-WORK
workspaces (strings). Allow specifying resolutions, propagating
to right. Stores conflict file in RIGHT-WORK/_MTN."
(let ((default-directory right-work))
(xmtn-conflicts-save-opts left-work right-work)
(dvc-run-dvc-async
'xmtn
(list "conflicts" "store" left-rev right-rev)
:finished (lambda (output error status arguments)
(xmtn-conflicts-review default-directory))
(xmtn-conflicts-save-opts left-work right-work left-branch right-branch left-rev right-rev)
(xmtn-automate-command-output-file
default-directory
"_MTN/conflicts"
(list "show_conflicts" left-rev right-rev))
(xmtn-conflicts-load-file)))
:error (lambda (output error status arguments)
(pop-to-buffer error))
)))
(defun xmtn-conflicts-review (left-work left-rev right-work right-rev left-branch right-branch show)
"Review conflicts between LEFT-WORK (a directory), rev LEFT-REV,
and RIGHT-WORK, rev RIGHT-REV. If LEFT_WORK/_MTN/conflicts
exists and is current, display it. Otherwise generate a new
RIGHT_WORK/_MTN/conflicts file and display that. Return the
conflicts buffer."
(let ((default-directory right-work)
(dvc-switch-to-buffer-first show))
(if (file-exists-p "_MTN/conflicts")
(progn
(xmtn-conflicts-load-file)
(if (not (and (string-equal xmtn-conflicts-left-revision left-rev)
(string-equal xmtn-conflicts-left-work left-work)
(string-equal xmtn-conflicts-right-revision right-rev)
(string-equal xmtn-conflicts-right-work right-work)))
;; file not current; regenerate
(xmtn-conflicts-1 left-work left-rev right-work right-rev left-branch right-branch)))
(defun xmtn-check-workspace-for-propagate (work cached-branch)
"Check that workspace WORK is ready for propagate.
It must be merged, and should be at the head revision, and have no local changes."
(let* ((default-directory work)
(heads (xmtn--heads default-directory cached-branch))
(base (xmtn--get-base-revision-hash-id-or-null default-directory)))
;; else generate new file
(xmtn-conflicts-1 left-work left-rev right-work right-rev left-branch right-branch)))
(current-buffer))
(message "checking %s for multiple heads, base not head" work)
(defun xmtn-conflicts-status (buffer left-work left-rev right-work right-rev left-branch right-branch)
"Return '(status buffer), where status is one of 'need-resolve
| 'need-review-resolve-internal | 'resolved | 'none for
BUFFER. Regenerate conflicts if not current. Conflicts stored in
RIGHT-WORK."
(if (buffer-live-p buffer)
;; check if buffer still current
(with-current-buffer buffer
(let ((revs-current
(and (string= left-rev xmtn-conflicts-left-revision)
(string= right-rev xmtn-conflicts-right-revision))))
(if revs-current
(progn
(xmtn-conflicts-update-counts)
(save-buffer))
;; else reload or regenerate
(save-excursion
(setq buffer
(xmtn-conflicts-review
left-work left-rev right-work right-rev left-branch right-branch nil))))))
(if (> 1 (length heads))
(error "%s has multiple heads; can't propagate" work))
;; else reload or regenerate
(save-excursion
(setq buffer
(xmtn-conflicts-review
left-work left-rev right-work right-rev left-branch right-branch nil))))
(if (not (string= base (nth 0 heads)))
(error "Aborting due to %s not at head" work))
;; check for local changes
(message "checking %s for local changes" work)
(dvc-run-dvc-sync
'xmtn
(list "status")
:finished (lambda (output error status arguments)
;; we don't get an error status for not up-to-date,
;; so parse the output.
;; FIXME: add option to automate inventory to just return status; can return on first change
;; FIXME: 'patch' may be internationalized.
(set-buffer output)
(goto-char (point-min))
(if (search-forward "patch" (point-max) t)
(if (not (yes-or-no-p (format "%s has local changes; really show conflicts? " work)))
(error "aborting due to local changes"))))
:error (lambda (output error status arguments)
(pop-to-buffer error))))
)
(defun xmtn-check-propagate-needed (left-work right-work)
"Throw error unless branch in workspace LEFT-WORK needs to be propagated to RIGHT-WORK."
;; We assume xmtn-check-workspace-for-propagate has already been run
;; on left-work, right-work, so just check if they have the same
;; base revision, or the target (right) base revision is a
;; descendant of the source.
(message "checking if propagate needed")
(let ((left-base (xmtn--get-base-revision-hash-id-or-null left-work))
(right-base (xmtn--get-base-revision-hash-id-or-null right-work)))
(if (string= left-base right-base)
(error "don't need to propagate")
;; check for right descendant of left
(let ((descendents (xmtn-automate-simple-command-output-lines left-work (list "descendents" left-base))))
(while descendents
(if (string= right-base (car descendents))
(error "don't need to propagate"))
(setq descendents (cdr descendents)))))
))
;;;###autoload
(defun xmtn-conflicts-propagate (left-work right-work)
"List conflicts for a propagate from LEFT-WORK to RIGHT-WORK workspace branch head revisions.
Allow specifying resolutions. LEFT-WORK and RIGHT-WORK are strings giving
workspace directories; prompted if nil. Review is done in RIGHT-WORK
workspace."
(interactive "i\ni")
(setq left-work (dvc-read-project-tree-maybe "Propagate from (workspace directory): " left-work))
(setq right-work (dvc-read-project-tree-maybe "to (workspace directory): " right-work))
(let ((left-branch (xmtn--tree-default-branch left-work))
(right-branch (xmtn--tree-default-branch right-work)))
(xmtn-check-workspace-for-propagate left-work left-branch)
(xmtn-check-workspace-for-propagate right-work right-branch)
(xmtn-check-propagate-needed left-work right-work)
(message "computing conflicts")
(xmtn-conflicts-1 left-work
(car (xmtn--heads left-work left-branch))
right-work
(car (xmtn--heads right-work right-branch)))))
;;;###autoload
(defun xmtn-conflicts-merge ()
"List conflicts between current head revisions."
(interactive)
(let ((default-directory
(dvc-read-project-tree-maybe "Review conflicts in (workspace directory): ")))
(xmtn-conflicts-1 default-directory nil default-directory nil)))
;;;###autoload
(defun xmtn-conflicts-review (&optional workspace)
"Review conflicts for WORKSPACE (a directory; default prompt)."
(interactive)
(let ((default-directory
(dvc-read-project-tree-maybe "Review conflicts for (workspace directory): "
(when workspace (expand-file-name workspace))))
(file-name "_MTN/conflicts"))
(if (not (file-exists-p file-name))
(error "conflicts file not found"))
(let ((conflicts-buffer (dvc-get-buffer-create 'xmtn 'conflicts default-directory)))
(dvc-switch-to-buffer-maybe conflicts-buffer)
(setq buffer-read-only nil)
(xmtn-conflicts-load-opts)
(set (make-local-variable 'after-insert-file-functions) '(xmtn-conflicts-after-insert-file))
(insert-file-contents "_MTN/conflicts" t nil nil t))))
;; compute status
(with-current-buffer buffer
(case xmtn-conflicts-total-count
(0 (list buffer 'none))
(t
(cond
((= xmtn-conflicts-total-count xmtn-conflicts-resolved-count)
(if (> xmtn-conflicts-resolved-internal-count 0)
(list buffer 'need-review-resolve-internal)
(list buffer 'resolved)))
(t
(list buffer 'need-resolve)))))))
;;;###autoload
(defun xmtn-conflicts-clean (&optional workspace)

View File

@ -1,6 +1,6 @@
;;; xmtn-dvc.el --- DVC backend for monotone
;; Copyright (C) 2008 - 2010 Stephen Leake
;; Copyright (C) 2008 - 2011 Stephen Leake
;; Copyright (C) 2006, 2007, 2008 Christian M. Ohler
;; Author: Christian M. Ohler
@ -95,35 +95,17 @@
"_MTN/log"))
(defun xmtn--toposort (root revision-hash-ids)
(xmtn-automate-simple-command-output-lines root
(xmtn-automate-command-output-lines root
`("toposort"
,@revision-hash-ids)))
(add-to-list 'format-alist
'(xmtn--log-file
"This format automatically removes xmtn's log edit hints from
the file before saving."
nil
xmtn--log-file-format-from-fn
xmtn--log-file-format-to-fn
t
nil
nil))
(defun xmtn--log-file-format-from-fn (begin end)
(xmtn--assert-nil))
(defun xmtn--log-file-format-to-fn (begin end buffer)
(dvc-log-flush-commit-file-list))
;;;###autoload
(defun xmtn-dvc-log-edit (root other-frame no-init)
(if no-init
(dvc-dvc-log-edit root other-frame no-init)
(progn
(dvc-dvc-log-edit root other-frame nil)
(setq buffer-file-coding-system 'xmtn--monotone-normal-form) ;; FIXME: move this into dvc-get-buffer-create?
(add-to-list 'buffer-file-format 'xmtn--log-file) ;; FIXME: generalize to dvc--log-file
(setq buffer-file-coding-system 'xmtn--monotone-normal-form)
)))
(defun xmtn-dvc-log-message ()
@ -158,7 +140,6 @@ the file before saving."
(if session (xmtn-automate--close-session session)))
(read-from-minibuffer "branch: " (xmtn--tree-default-branch root)))
(xmtn--tree-default-branch root))))
;; Saving the buffer will automatically delete any log edit hints.
(save-buffer)
(dvc-save-some-buffers root)
@ -230,6 +211,48 @@ the file before saving."
(message "%s... " progress-message))
(set-window-configuration dvc-pre-commit-window-configuration)))
(defun xmtn-show-commit ()
"Show commit command for use on command line"
(interactive)
(let ((excluded-files
(with-current-buffer dvc-partner-buffer
(xmtn--normalize-file-names default-directory (dvc-fileinfo-excluded-files)))))
(save-buffer)
(dvc-save-some-buffers default-directory)
;; check that the first line says something; it should be a summary of the rest
(goto-char (point-min))
(forward-line)
(if (= (point) (1+ (point-min)))
(error "Please put a summary comment on the first line"))
(message
(concat
"mtn commit "
(xmtn-dvc-log-message)
" "
(if excluded-files
(mapconcat (lambda (file) (concat "--exclude=" file)) excluded-files " "))))
(pop-to-buffer "*Messages*")))
;; Add xmtn-show-commit to dvc-log-edit menu
(defvar xmtn-log-edit-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [(control ?c) (control ?s)] 'xmtn-show-commit)
map))
(easy-menu-define xmtn-log-edit-mode-menu xmtn-log-edit-mode-map
"Mtn specific log-edit menu."
`("DVC-Mtn"
["Show commit command" xmtn-show-commit t]
))
(define-derived-mode xmtn-log-edit-mode dvc-log-edit-mode "xmtn-log-edit"
"Add back-end-specific commands for dvc-log-edit.")
(dvc-add-uniquify-directory-mode 'xmtn-log-edit-mode)
;; The term "normalization" here has nothing to do with Unicode
;; normalization.
(defun xmtn--normalize-file-name (root file-name)
@ -356,20 +379,6 @@ the file before saving."
(message "Tree %s has no base revision" root))))
;;;###autoload
(defun xmtn-dvc-search-file-in-diff (file)
(re-search-forward
(let ((quoted-file (regexp-quote file)))
(concat "^\\(\\("
"\\+\\+\\+ " quoted-file
"\\)\\|\\("
;; FIXME: What `dvc-diff-diff-or-list' does doesn't work
;; for this case, since `diff-hunk-next' doesn't recognize
;; mtn's output for this case as a diff hunk.
"# " quoted-file " is binary"
"\\)\\)$"))))
;;;###autoload
(defun xmtn-dvc-diff (&optional rev path dont-switch)
;; If rev is an ancestor of base-rev of path, then rev is from, path
@ -383,7 +392,7 @@ the file before saving."
(if (string= rev-string base)
;; local changes in workspace are 'to'
(xmtn-dvc-delta rev workspace dont-switch)
(let ((descendents (xmtn-automate-simple-command-output-lines path (list "descendents" base)))
(let ((descendents (xmtn-automate-command-output-lines path (list "descendents" base)))
(done nil))
(while descendents
(if (string= rev-string (car descendents))
@ -396,45 +405,14 @@ the file before saving."
;; rev is ancestor of workspace; workspace is 'to'
(xmtn-dvc-delta rev workspace dont-switch))))))
(defvar xmtn-diff-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "CM" 'xmtn-conflicts-merge)
(define-key map "CP" 'xmtn-conflicts-propagate)
(define-key map "CR" 'xmtn-conflicts-review)
(define-key map "CC" 'xmtn-conflicts-clean)
(define-key map "MH" 'xmtn-view-heads-revlist)
(define-key map "MP" 'xmtn-propagate-from)
map))
;; items added here should probably also be added to xmtn-revlist-mode-menu, -map in xmtn-revlist.el
(easy-menu-define xmtn-diff-mode-menu xmtn-diff-mode-map
"Mtn specific diff menu."
`("DVC-Mtn"
["View Heads" xmtn-view-heads-revlist t]
["Show propagate conflicts" xmtn-conflicts-propagate t]
["Review conflicts" xmtn-conflicts-review t]
["Propagate branch" xmtn-propagate-from t]
["Clean conflicts resolutions" xmtn-conflicts-clean t]
))
(define-derived-mode xmtn-diff-mode dvc-diff-mode "xmtn-diff"
"Add back-end-specific commands for dvc-diff.")
(dvc-add-uniquify-directory-mode 'xmtn-diff-mode)
(defun xmtn--rev-to-option (resolved from)
"Return a string contaiing the mtn diff command-line option for RESOLVED-REV.
If FROM is non-nil, RESOLVED-REV is assumed older than workspace;
"Return a string contaiing the mtn diff command-line option for RESOLVED.
If FROM is non-nil, RESOLVED is assumed older than workspace;
otherwise newer."
(ecase (car resolved)
('local-tree
(if from
(progn
;; FIXME: --reverse is not in mtn 0.44; bump overall
;; required version on new mtn release
(let ((xmtn--minimum-required-command-version '(0 45)))
(xmtn--check-cached-command-version)
"--reverse"))
"--reverse"
""))
('revision (concat "--revision=" (cadr resolved)))))
@ -466,32 +444,6 @@ otherwise newer."
;; The call site in `dvc-revlist-diff' needs this return value.
diff-buffer)))
(defvar xmtn-status-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "CM" 'xmtn-conflicts-merge)
(define-key map "CP" 'xmtn-conflicts-propagate)
(define-key map "CR" 'xmtn-conflicts-review)
(define-key map "CC" 'xmtn-conflicts-clean)
(define-key map "MP" 'xmtn-propagate-from)
(define-key map "MH" 'xmtn-view-heads-revlist)
map))
(easy-menu-define xmtn-status-mode-menu xmtn-status-mode-map
"Mtn specific status menu."
`("DVC-Mtn"
["View Heads" xmtn-view-heads-revlist t]
["Show merge conflicts" xmtn-conflicts-merge t]
["Show propagate conflicts" xmtn-conflicts-propagate t]
["Review conflicts" xmtn-conflicts-review t]
["Propagate branch" xmtn-propagate-from t]
["Clean conflicts resolutions" xmtn-conflicts-clean t]
))
(define-derived-mode xmtn-status-mode dvc-status-mode "xmtn-status"
"Add back-end-specific commands for dvc-status.")
(add-to-list 'uniquify-list-buffers-directory-modes 'xmtn-status-mode)
(defun xmtn--remove-content-hashes-from-diff ()
;; Hack: Remove mtn's file content hashes from diff headings since
;; `dvc-diff-diff-or-list' and `dvc-diff-find-file-name' gets
@ -514,16 +466,6 @@ otherwise newer."
(defun xmtn-dvc-command-version ()
(fourth (xmtn--command-version xmtn-executable)))
(defvar xmtn-dvc-automate-version nil
"Cached value of mtn automate interface version.")
(defun xmtn-dvc-automate-version ()
"Return mtn automate version as a number."
(if xmtn-dvc-automate-version
xmtn-dvc-automate-version
(setq xmtn-dvc-automate-version
(string-to-number (xmtn--command-output-line nil '("automate" "interface_version"))))))
(defun xmtn--changes-image (change)
(ecase change
(content "content")
@ -702,7 +644,6 @@ otherwise newer."
(dvc-status-prepare-buffer
'xmtn
root
;; FIXME: just pass header
;; base-revision
(if base-revision (format "%s" base-revision) "none")
;; branch
@ -746,8 +687,7 @@ otherwise newer."
:text (concat " no changes in workspace")))
(ewoc-refresh dvc-fileinfo-ewoc)))))
:error (lambda (output error status arguments)
;; FIXME: need `dvc-status-error-in-process', or change name.
(dvc-diff-error-in-process
(dvc-diff-error-in-process ;; correct for status-mode as well
status-buffer
(format "Error running mtn with arguments %S" arguments)
output error))
@ -929,7 +869,6 @@ otherwise newer."
(1 (format "%s" (first normalized-file-names)))
(t (format "%s files/directories"
(length normalized-file-names))))))
;; FIXME: confirm should be in upper level DVC code.
(when (or (not dvc-confirm-ignore)
(y-or-n-p (format "Ignore %s in monotone tree %s? " msg root)))
(xmtn--add-patterns-to-mtnignore
@ -970,7 +909,7 @@ otherwise newer."
(xmtn--add-files (dvc-tree-root) files))
;; Appears redundant, given that there is `xmtn-dvc-add-files'. But
;; it's part of the DVC API. FIXME.
;; it's part of the DVC API.
;;;###autoload
(defun xmtn-dvc-add (file)
(xmtn--add-files (dvc-tree-root) (list file)))
@ -1156,7 +1095,9 @@ finished."
nil)
(defun xmtn-propagate-from (other &optional cached-branch)
"Propagate from OTHER branch to local tree branch."
"Propagate from OTHER branch to CACHED-BRANCH (default local tree branch).
Conflict resolution taken from `default-directory', which must be
a workspace for CACHED-BRANCH."
(interactive "MPropagate from branch: ")
(let*
((root (dvc-tree-root))
@ -1232,7 +1173,7 @@ finished."
;; mtn progress messages are put to stderr, and there is typically
;; nothing written to stdout from this command, so put both in the
;; same buffer.
;; FIXME: this output is not useful; need to use automation
;; This output is not useful; xmtn-sync, xmtn-sync-review is much better
(xmtn--run-command-async root `("pull" ,other)
:output-buffer name
:error-buffer name
@ -1475,7 +1416,7 @@ finished."
(defun xmtn--file-contents-as-string (root content-hash-id)
(check-type content-hash-id xmtn--hash-id)
(xmtn-automate-simple-command-output-string
(xmtn-automate-command-output-string
root `("get_file" ,content-hash-id)))
<<<<<<< TREE

View File

@ -1,6 +1,6 @@
;;; xmtn-ids.el --- Resolver routines for xmtn revision ids
;; Copyright (C) 2008 - 2010 Stephen Leake
;; Copyright (C) 2008 - 2011 Stephen Leake
;; Copyright (C) 2006, 2007 Christian M. Ohler
;; Author: Christian M. Ohler
@ -145,7 +145,7 @@ See file commentary for details."
(defun xmtn--get-parent-revision-hash-id (root hash-id local-branch)
(check-type hash-id xmtn--hash-id)
(let ((parents (xmtn-automate-simple-command-output-lines root `("parents"
(let ((parents (xmtn-automate-command-output-lines root `("parents"
,hash-id))))
(case (length parents)
(0 (error "Revision has no parents: %s" hash-id))
@ -192,7 +192,7 @@ See file commentary for details."
nil)
(defun xmtn--expand-selector (root selector)
(xmtn-automate-simple-command-output-lines root `("select" ,selector)))
(xmtn-automate-command-output-lines root `("select" ,selector)))
(defun xmtn--branch-of (root hash-id)
(let ((certs (xmtn--list-parsed-certs root hash-id))
@ -227,7 +227,7 @@ must be a workspace."
result))
(defun xmtn--get-base-revision-hash-id-or-null (root)
(let ((hash-id (xmtn-automate-simple-command-output-line
(let ((hash-id (xmtn-automate-command-output-line
root `("get_base_revision_id"))))
(when (equal hash-id "") (setq hash-id nil))
(assert (typep hash-id '(or xmtn--hash-id null)))

View File

@ -1,6 +1,6 @@
;;; xmtn-status.el --- manage actions for multiple projects
;; Copyright (C) 2009 - 2010 Stephen Leake
;; Copyright (C) 2009 - 2011 Stephen Leake
;; Author: Stephen Leake
;; Keywords: tools
@ -44,9 +44,9 @@ The elements must all be of class xmtn-status-data.")
(defstruct (xmtn-status-data (:copier nil))
work ; workspace directory name relative to xmtn-status-root
branch ; branch name (all workspaces have same branch; assumed never changes)
branch ; GDS branch name (all workspaces have same branch; assumed never changes)
need-refresh ; nil | t : if an async process was started that invalidates state data
head-rev ; nil | mtn rev string : current head revision, nil if multiple heads
head-revs ; either current head revision or (left, right) if multiple heads
conflicts-buffer ; *xmtn-conflicts* buffer for merge
status-buffer ; *xmtn-status* buffer for commit
heads ; 'need-scan | 'at-head | 'need-update | 'need-merge
@ -80,7 +80,7 @@ The elements must all be of class xmtn-status-data.")
(insert (dvc-face-add " need refresh\n" 'dvc-conflict))
(ecase (xmtn-status-data-local-changes data)
(need-scan (insert " local changes unknown\n"))
(need-scan (insert " local changes not checked\n"))
(need-commit (insert (dvc-face-add " need commit\n" 'dvc-header)))
(ok nil))
@ -122,12 +122,14 @@ The elements must all be of class xmtn-status-data.")
(if (buffer-live-p (xmtn-status-data-conflicts-buffer data))
(with-current-buffer (xmtn-status-data-conflicts-buffer data) (save-buffer))))
(defun xmtn-status-clean-1 (data)
"Clean DATA workspace."
(defun xmtn-status-clean-1 (data save-conflicts)
"Clean DATA workspace, kill associated automate session.
If SAVE-CONFLICTS non-nil, don't delete conflicts files."
(xmtn-automate-kill-session (xmtn-status-work data))
(xmtn-status-kill-conflicts-buffer data)
(xmtn-status-kill-status-buffer data)
(xmtn-conflicts-clean (xmtn-status-work data)))
(unless save-conflicts
(xmtn-conflicts-clean (xmtn-status-work data))))
(defun xmtn-status-clean ()
"Clean current workspace, delete from ewoc"
@ -135,14 +137,13 @@ The elements must all be of class xmtn-status-data.")
(let* ((elem (ewoc-locate xmtn-status-ewoc))
(data (ewoc-data elem))
(inhibit-read-only t))
(xmtn-status-clean-1 data)
(xmtn-status-clean-1 data nil)
(ewoc-delete xmtn-status-ewoc elem)))
(defun xmtn-status-quit ()
"Clean all remaining workspaces, kill automate sessions, kill buffer."
(defun xmtn-status-clean-all (&optional save-conflicts)
"Clean all remaining workspaces."
(interactive)
(ewoc-map 'xmtn-status-clean-1 xmtn-status-ewoc)
(kill-buffer))
(ewoc-map 'xmtn-status-clean-1 xmtn-status-ewoc save-conflicts))
(defun xmtn-status-cleanp ()
"Non-nil if clean & quit is appropriate for current workspace."
@ -186,13 +187,21 @@ The elements must all be of class xmtn-status-data.")
(and (not (xmtn-status-data-need-refresh data))
(eq 'need-update (xmtn-status-data-heads data)))))
(defun xmtn-status-update-preview ()
"Preview update for current workspace."
(interactive)
(let* ((elem (ewoc-locate xmtn-status-ewoc))
(data (ewoc-data elem))
(default-directory (xmtn-status-work data)))
(xmtn-dvc-missing)))
(defun xmtn-status-resolve-conflicts ()
"Resolve conflicts for current workspace."
(interactive)
(let* ((elem (ewoc-locate xmtn-status-ewoc))
(data (ewoc-data elem)))
(xmtn-status-need-refresh elem data nil)
(setf (xmtn-status-data-conflicts data) 'resolved)
(setf (xmtn-status-data-conflicts data) 'need-scan)
(pop-to-buffer (xmtn-status-data-conflicts-buffer data))))
(defun xmtn-status-resolve-conflictsp ()
@ -229,18 +238,18 @@ The elements must all be of class xmtn-status-data.")
(member (xmtn-status-data-local-changes data)
'(need-scan need-commit)))))
(defun xmtn-status-review-update ()
(defun xmtn-status-update-review ()
"Review last update for current workspace."
(interactive)
(let* ((elem (ewoc-locate xmtn-status-ewoc))
(data (ewoc-data elem)))
;; assume they are adding FIXMEs
;; assume they are adding fixmes
(xmtn-status-need-refresh elem data 'need-scan)
(setf (xmtn-status-data-update-review data) 'done)
(xmtn-review-update (xmtn-status-work data))))
(xmtn-update-review (xmtn-status-work data))))
(defun xmtn-status-review-updatep ()
"Non-nil if xmtn-status-review-update is appropriate for current workspace."
(defun xmtn-status-update-reviewp ()
"Non-nil if xmtn-status-update-review is appropriate for current workspace."
(let* ((data (ewoc-data (ewoc-locate xmtn-status-ewoc))))
(and (not (xmtn-status-data-need-refresh data))
(eq 'need-review (xmtn-status-data-update-review data)))))
@ -252,7 +261,16 @@ The elements must all be of class xmtn-status-data.")
(data (ewoc-data elem))
(default-directory (xmtn-status-work data)))
(xmtn-status-save-conflicts-buffer data)
(xmtn-dvc-merge-1 default-directory nil)
(xmtn--run-command-sync
default-directory
(list
"explicit_merge"
(nth 0 (xmtn-status-data-head-revs data))
(nth 1 (xmtn-status-data-head-revs data))
(xmtn--tree-default-branch default-directory)
(if (file-exists-p "_MTN/conflicts")
"--resolve-conflicts-file=_MTN/conflicts")
(xmtn-dvc-log-message)))
(xmtn-status-refresh-one data nil)
(ewoc-invalidate xmtn-status-ewoc elem)))
@ -271,6 +289,13 @@ The elements must all be of class xmtn-status-data.")
(and (not (xmtn-status-data-need-refresh data))
(eq 'need-merge (xmtn-status-data-heads data)))))
(defun xmtn-status-quit-save ()
"Quit, but save conflicts files for later resume."
(interactive)
(remove-hook 'kill-buffer-hook 'xmtn-status-clean-all t)
(xmtn-status-clean-all t)
(kill-buffer))
(defvar xmtn-status-actions-map
(let ((map (make-sparse-keymap "actions")))
(define-key map [?c] '(menu-item "c) clean/delete"
@ -282,9 +307,12 @@ The elements must all be of class xmtn-status-data.")
(define-key map [?i] '(menu-item "i) ignore local changes"
xmtn-status-status-ok
:visible (xmtn-status-statusp)))
(define-key map [?5] '(menu-item "5) review update"
xmtn-status-review-update
:visible (xmtn-status-review-updatep)))
(define-key map [?6] '(menu-item "6) preview update"
xmtn-status-update-preview
:visible (xmtn-status-updatep)))
(define-key map [?5] '(menu-item "5) update review"
xmtn-status-update-review
:visible (xmtn-status-update-reviewp)))
(define-key map [?4] '(menu-item "4) update"
xmtn-status-update
:visible (xmtn-status-updatep)))
@ -310,12 +338,25 @@ The elements must all be of class xmtn-status-data.")
(let ((map (make-sparse-keymap)))
(define-key map "\M-d" xmtn-status-actions-map)
(define-key map [?g] 'xmtn-status-refresh)
(define-key map [?m] 'xmtn-status-update-preview)
(define-key map [?n] 'xmtn-status-next)
(define-key map [?p] 'xmtn-status-prev)
(define-key map [?q] 'xmtn-status-quit)
(define-key map [?r] 'xmtn-status-update-review)
(define-key map [?s] 'xmtn-status-quit-save)
(define-key map [?q] 'dvc-buffer-quit)
map)
"Keymap used in `xmtn-multiple-status-mode'.")
(easy-menu-define xmtn-multiple-status-mode-menu xmtn-multiple-status-mode-map
"Mtn specific status menu."
`("DVC-Mtn"
["Do the right thing" xmtn-status-actions-map t]
["Quit, clean conflicts" dvc-buffer-quit t]
["Quit, save conflicts" xmtn-status-quit-save t]
["Preview update" xmtn-status-update-preview t]
["Review update" xmtn-status-update-review t]
))
(define-derived-mode xmtn-multiple-status-mode nil "xmtn-multiple-status"
"Major mode to show status of multiple workspaces."
(setq dvc-buffer-current-active-dvc 'xmtn)
@ -326,6 +367,7 @@ The elements must all be of class xmtn-status-data.")
(set (make-local-variable 'write-file-functions) nil)
(dvc-install-buffer-menu)
(add-hook 'kill-buffer-hook 'xmtn-status-clean-all nil t)
(setq buffer-read-only t)
(buffer-disable-undo)
@ -333,35 +375,18 @@ The elements must all be of class xmtn-status-data.")
(defun xmtn-status-conflicts (data)
"Return value for xmtn-status-data-conflicts for DATA."
(let* ((work (xmtn-status-work data))
(default-directory work))
(if (buffer-live-p (xmtn-status-data-conflicts-buffer data))
(kill-buffer (xmtn-status-data-conflicts-buffer data)))
;; create conflicts file
(xmtn-conflicts-clean work)
(xmtn-conflicts-save-opts work work (xmtn-status-data-branch data) (xmtn-status-data-branch data))
(dvc-run-dvc-sync
'xmtn
(list "conflicts" "store")
:error (lambda (output error status arguments)
(pop-to-buffer error)))
;; create conflicts buffer
(setf (xmtn-status-data-conflicts-buffer data)
(save-excursion
(let ((dvc-switch-to-buffer-first nil))
(xmtn-conflicts-review work)
(current-buffer))))
(with-current-buffer (xmtn-status-data-conflicts-buffer data)
(case xmtn-conflicts-total-count
(0 'none)
(t
(if (= xmtn-conflicts-total-count xmtn-conflicts-resolved-internal-count)
'need-review-resolve-internal
'need-resolve))))))
;; only called if need merge; two items in head-revs
(let ((result (xmtn-conflicts-status
(xmtn-status-data-conflicts-buffer data) ; buffer
(xmtn-status-work data) ; left-work
(car (xmtn-status-data-head-revs data)) ; left-rev
(xmtn-status-work data) ; right-work
(cadr (xmtn-status-data-head-revs data)) ; right-rev
(xmtn-status-data-branch data) ; left-branch
(xmtn-status-data-branch data) ; right-branch
)))
(setf (xmtn-status-data-conflicts-buffer data) (car result))
(cadr result)))
(defun xmtn-status-refresh-one (data refresh-local-changes)
"Refresh DATA."
@ -373,29 +398,21 @@ The elements must all be of class xmtn-status-data.")
(base-rev (xmtn--get-base-revision-hash-id-or-null work)))
(case (length heads)
(1
(setf (xmtn-status-data-head-rev data) (nth 0 heads))
(setf (xmtn-status-data-head-revs data) (nth 0 heads))
(setf (xmtn-status-data-conflicts data) 'none)
(if (string= (xmtn-status-data-head-rev data) base-rev)
(if (string= (xmtn-status-data-head-revs data) base-rev)
(setf (xmtn-status-data-heads data) 'at-head)
(setf (xmtn-status-data-heads data) 'need-update)))
(t
(setf (xmtn-status-data-head-rev data) nil)
(setf (xmtn-status-data-heads data) 'need-merge)
(case (xmtn-status-data-conflicts data)
(resolved
;; Assume the resolution was just completed, so don't erase it!
nil)
(t
(setf (xmtn-status-data-conflicts data) 'need-scan))))))
(setf (xmtn-status-data-head-revs data) (list (nth 0 heads) (nth 1 heads)))
(setf (xmtn-status-data-heads data) 'need-merge))))
(message "")
(if refresh-local-changes
(progn
(setf (xmtn-status-data-local-changes data) 'need-scan)
(case (xmtn-status-data-update-review data)
('done (setf (xmtn-status-data-update-review data) 'need-review))
(t nil))))
(setf (xmtn-status-data-update-review data) 'need-review)))
(case (xmtn-status-data-local-changes data)
(need-scan
@ -411,11 +428,14 @@ The elements must all be of class xmtn-status-data.")
(xmtn-status-data-local-changes data) (cadr result))) ))
(t nil))
(case (xmtn-status-data-conflicts data)
(need-scan
(case (xmtn-status-data-heads data)
(need-merge
(setf (xmtn-status-data-conflicts data)
(xmtn-status-conflicts data)))
(t nil))
(t
(xmtn-status-kill-conflicts-buffer data)
(xmtn-conflicts-clean (xmtn-status-work data))
(setf (xmtn-status-data-conflicts data) 'none)))
(setf (xmtn-status-data-need-refresh data) nil))
@ -487,7 +507,7 @@ The elements must all be of class xmtn-status-data.")
(xmtn-status-next))
;;;###autoload
(defun xmtn-status-one-1 (root name head-rev status-buffer heads local-changes)
(defun xmtn-status-one-1 (root name head-revs status-buffer heads local-changes)
"Create an xmtn-multi-status buffer from xmtn-propagate."
(pop-to-buffer (get-buffer-create "*xmtn-multi-status*"))
(setq default-directory (concat root "/" name))
@ -500,7 +520,7 @@ The elements must all be of class xmtn-status-data.")
:work (file-name-nondirectory (directory-file-name default-directory))
:branch (xmtn--tree-default-branch default-directory)
:need-refresh nil
:head-rev head-rev
:head-revs head-revs
:conflicts-buffer nil
:status-buffer status-buffer
:heads heads

View File

@ -1,6 +1,6 @@
;;; xmtn-propagate.el --- manage multiple propagations for DVC backend for monotone
;; Copyright (C) 2009 - 2010 Stephen Leake
;; Copyright (C) 2009 - 2011 Stephen Leake
;; Author: Stephen Leake
;; Keywords: tools
@ -56,8 +56,8 @@ The elements must all be of class xmtn-propagate-data.")
from-branch ; branch name (assumed never changes)
to-branch ;
need-refresh ; nil | t; if an async process was started that invalidates state data
from-head-rev ; nil | mtn rev string; current head revision; nil if multiple heads
to-head-rev ;
from-head-revs ; mtn rev string; current head revision or (left right) if multiple heads
to-head-revs ;
conflicts-buffer ; *xmtn-conflicts* buffer for this propagation
from-status-buffer ; *xmtn-status* buffer for commit in from
to-status-buffer ; *xmtn-status* buffer for commit in to
@ -69,7 +69,7 @@ The elements must all be of class xmtn-propagate-data.")
(to-local-changes
'need-scan) ;
(conflicts
'need-scan) ; 'need-scan | 'need-resolve | 'need-review-resolve-internal | 'ok
'need-scan) ; 'need-scan | 'need-resolve | 'need-review-resolve-internal | 'resolved | 'none
; for propagate
)
@ -105,14 +105,14 @@ The elements must all be of class xmtn-propagate-data.")
(insert (dvc-face-add " need refresh\n" 'dvc-conflict))
(ecase (xmtn-propagate-data-from-local-changes data)
(need-scan (insert " local changes unknown " (xmtn-propagate-data-from-name data) "\n"))
(need-scan (insert " local changes not checked " (xmtn-propagate-data-from-name data) "\n"))
(need-commit
(insert (dvc-face-add (concat " need commit " (xmtn-propagate-data-from-name data) "\n")
'dvc-header)))
(ok nil))
(ecase (xmtn-propagate-data-to-local-changes data)
(need-scan (insert " local changes unknown " (xmtn-propagate-data-to-name data) "\n"))
(need-scan (insert " local changes not checked " (xmtn-propagate-data-to-name data) "\n"))
(need-commit
(insert (dvc-face-add (concat " need commit " (xmtn-propagate-data-to-name data) "\n")
'dvc-header)))
@ -124,7 +124,7 @@ The elements must all be of class xmtn-propagate-data.")
(insert (dvc-face-add (concat " need update " (xmtn-propagate-data-from-name data) "\n")
'dvc-conflict)))
(need-merge
(insert (dvc-face-add (concat " need merge " (xmtn-propagate-data-from-name data) "\n")
(insert (dvc-face-add (concat " need status for merge " (xmtn-propagate-data-from-name data) "\n")
'dvc-conflict))))
(ecase (xmtn-propagate-data-to-heads data)
@ -133,7 +133,7 @@ The elements must all be of class xmtn-propagate-data.")
(insert (dvc-face-add (concat " need update " (xmtn-propagate-data-to-name data) "\n")
'dvc-conflict)))
(need-merge
(insert (dvc-face-add (concat " need merge " (xmtn-propagate-data-to-name data) "\n")
(insert (dvc-face-add (concat " need status for merge " (xmtn-propagate-data-to-name data) "\n")
'dvc-conflict))))
(if (xmtn-propagate-data-propagate-needed data)
@ -148,7 +148,7 @@ The elements must all be of class xmtn-propagate-data.")
(need-review-resolve-internal
(insert (dvc-face-add " need review resolve internal\n" 'dvc-header))
(insert (dvc-face-add " need propagate\n" 'dvc-conflict)))
(ok
((resolved none)
(insert (dvc-face-add " need propagate\n" 'dvc-conflict)))))
(if (eq 'at-head (xmtn-propagate-data-to-heads data))
@ -169,29 +169,15 @@ The elements must all be of class xmtn-propagate-data.")
(defun xmtn-propagate-create-to-status-buffer (data)
"Create to-status buffer for DATA"
(if (buffer-live-p (xmtn-propagate-data-to-status-buffer data))
(with-current-buffer (xmtn-propagate-data-to-status-buffer data)
(xmtn-dvc-status)
(setf (xmtn-propagate-data-to-local-changes data)
(if (not (ewoc-locate dvc-fileinfo-ewoc))
'ok
'need-commit)))
(let ((result (xmtn--status-inventory-sync (xmtn-propagate-to-work data))))
(setf (xmtn-propagate-data-to-status-buffer data) (car result)
(xmtn-propagate-data-to-local-changes data) (cadr result))) ))
(let ((result (xmtn--status-inventory-sync (xmtn-propagate-to-work data))))
(setf (xmtn-propagate-data-to-status-buffer data) (car result)
(xmtn-propagate-data-to-local-changes data) (cadr result))))
(defun xmtn-propagate-create-from-status-buffer (data)
"Create from-status buffer for DATA"
(if (buffer-live-p (xmtn-propagate-data-from-status-buffer data))
(with-current-buffer (xmtn-propagate-data-from-status-buffer data)
(xmtn-dvc-status)
(setf (xmtn-propagate-data-from-local-changes data)
(if (not (ewoc-locate dvc-fileinfo-ewoc))
'ok
'need-commit)))
(let ((result (xmtn--status-inventory-sync (xmtn-propagate-from-work data))))
(setf (xmtn-propagate-data-from-status-buffer data) (car result)
(xmtn-propagate-data-from-local-changes data) (cadr result))) ))
(let ((result (xmtn--status-inventory-sync (xmtn-propagate-from-work data))))
(setf (xmtn-propagate-data-from-status-buffer data) (car result)
(xmtn-propagate-data-from-local-changes data) (cadr result))))
(defun xmtn-propagate-kill-status-buffers (data)
(if (buffer-live-p (xmtn-propagate-data-from-status-buffer data))
@ -199,29 +185,30 @@ The elements must all be of class xmtn-propagate-data.")
(if (buffer-live-p (xmtn-propagate-data-to-status-buffer data))
(kill-buffer (xmtn-propagate-data-to-status-buffer data))))
(defun xmtn-propagate-clean-1 (data)
"Clean DATA workspace"
(defun xmtn-propagate-clean-1 (data save-conflicts)
"Clean DATA workspace, kill associated automate session.
If SAVE-CONFLICTS non-nil, don't delete conflicts files."
(xmtn-automate-kill-session (xmtn-propagate-from-work data))
(xmtn-automate-kill-session (xmtn-propagate-to-work data))
(xmtn-propagate-kill-conflicts-buffer data)
(xmtn-propagate-kill-status-buffers data)
(xmtn-conflicts-clean (xmtn-propagate-to-work data)))
(unless save-conflicts
(xmtn-conflicts-clean (xmtn-propagate-to-work data))))
(defun xmtn-propagate-clean ()
"Clean current workspace, delete from ewoc"
"Clean current workspace, delete from ewoc."
(interactive)
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
(data (ewoc-data elem)))
(xmtn-propagate-clean-1 data)
(xmtn-propagate-clean-1 data nil)
(let ((inhibit-read-only t))
(ewoc-delete xmtn-propagate-ewoc elem))))
(defun xmtn-propagate-quit ()
"Clean all remaining workspaces, kill automate sessions, kill buffer."
(defun xmtn-propagate-clean-all (&optional save-conflicts)
"Clean all remaining workspaces."
(interactive)
(ewoc-map 'xmtn-propagate-clean-1 xmtn-propagate-ewoc)
(kill-buffer))
(ewoc-map 'xmtn-propagate-clean-1 xmtn-propagate-ewoc save-conflicts))
(defun xmtn-propagate-cleanp ()
"Non-nil if clean is appropriate for current workspace."
@ -256,7 +243,12 @@ The elements must all be of class xmtn-propagate-data.")
(data (ewoc-data elem)))
(xmtn-propagate-need-refresh elem data)
<<<<<<< TREE
<<<<<<< TREE
=======
=======
;; assume the commit is successful
(setf (xmtn-propagate-data-to-local-changes data) 'ok)
>>>>>>> MERGE-SOURCE
(if (not (buffer-live-p (xmtn-propagate-data-to-status-buffer data)))
(xmtn-propagate-create-to-status-buffer data))
>>>>>>> MERGE-SOURCE
@ -275,7 +267,12 @@ The elements must all be of class xmtn-propagate-data.")
(data (ewoc-data elem)))
(xmtn-propagate-need-refresh elem data)
<<<<<<< TREE
<<<<<<< TREE
=======
=======
;; assume the commit is successful
(setf (xmtn-propagate-data-from-local-changes data) 'ok)
>>>>>>> MERGE-SOURCE
(if (not (buffer-live-p (xmtn-propagate-data-from-status-buffer data)))
(xmtn-propagate-create-from-status-buffer data))
>>>>>>> MERGE-SOURCE
@ -294,7 +291,7 @@ The elements must all be of class xmtn-propagate-data.")
(data (ewoc-data elem)))
(xmtn-propagate-need-refresh elem data)
(xmtn--update (xmtn-propagate-to-work data)
(xmtn-propagate-data-to-head-rev data)
(xmtn-propagate-data-to-head-revs data)
nil t)
(xmtn-propagate-refresh-one data nil)
(ewoc-invalidate xmtn-propagate-ewoc elem)))
@ -306,6 +303,25 @@ The elements must all be of class xmtn-propagate-data.")
(eq (xmtn-propagate-data-to-heads data)
'need-update))))
(defun xmtn-propagate-update-from ()
"Update current `from' workspace."
(interactive)
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
(data (ewoc-data elem)))
(xmtn-propagate-need-refresh elem data)
(xmtn--update (xmtn-propagate-from-work data)
(xmtn-propagate-data-from-head-revs data)
nil t)
(xmtn-propagate-refresh-one data nil)
(ewoc-invalidate xmtn-propagate-ewoc elem)))
(defun xmtn-propagate-update-fromp ()
"Non-nil if update is appropriate for current `from' workspace."
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
(and (not (xmtn-propagate-data-need-refresh data))
(eq (xmtn-propagate-data-from-heads data)
'need-update))))
(defun xmtn-propagate-propagate ()
"Propagate current workspace."
(interactive)
@ -315,12 +331,17 @@ The elements must all be of class xmtn-propagate-data.")
(if (not (buffer-live-p (xmtn-propagate-data-conflicts-buffer data)))
;; user deleted conflicts buffer after resolving conflicts; get it back
(setf (xmtn-propagate-data-conflicts-buffer data)
(xmtn-propagate-conflicts-buffer data)))
(xmtn-propagate-conflicts data))
(with-current-buffer (xmtn-propagate-data-conflicts-buffer data)
(let ((xmtn-confirm-operation nil))
(xmtn-conflicts-do-propagate (xmtn-propagate-data-to-branch data))))
(save-some-buffers t); log buffer
;; save-some-buffers does not save the conflicts buffer, which is the current buffer
(save-buffer)
(xmtn-propagate-from
(xmtn-propagate-data-from-branch data) ; = left
(xmtn-propagate-data-to-branch data) ; = right
)))
(xmtn-propagate-refresh-one data nil)
(ewoc-invalidate xmtn-propagate-ewoc elem)))
@ -332,7 +353,7 @@ The elements must all be of class xmtn-propagate-data.")
(eq 'at-head (xmtn-propagate-data-from-heads data))
(eq 'at-head (xmtn-propagate-data-to-heads data))
(member (xmtn-propagate-data-conflicts data)
'(ok need-review-resolve-internal)))))
'(need-review-resolve-internal resolved none)))))
(defun xmtn-propagate-resolve-conflicts ()
"Resolve conflicts for current workspace."
@ -392,7 +413,7 @@ The elements must all be of class xmtn-propagate-data.")
(xmtn-status-one-1
xmtn-propagate-to-root
(xmtn-propagate-data-to-work data)
(xmtn-propagate-data-to-head-rev data)
(xmtn-propagate-data-to-head-revs data)
(xmtn-propagate-data-to-status-buffer data)
(xmtn-propagate-data-to-heads data)
(xmtn-propagate-data-to-local-changes data))
@ -419,7 +440,7 @@ The elements must all be of class xmtn-propagate-data.")
(xmtn-status-one-1
xmtn-propagate-from-root
(xmtn-propagate-data-from-work data)
(xmtn-propagate-data-from-head-rev data)
(xmtn-propagate-data-from-head-revs data)
(xmtn-propagate-data-from-status-buffer data)
(xmtn-propagate-data-from-heads data)
(xmtn-propagate-data-from-local-changes data))
@ -434,6 +455,13 @@ The elements must all be of class xmtn-propagate-data.")
'(need-update need-merge))
(eq (xmtn-propagate-data-from-local-changes data) 'need-commit)))))
(defun xmtn-propagate-quit-save ()
"Quit, but save conflicts files for later resume."
(interactive)
(remove-hook 'kill-buffer-hook 'xmtn-propagate-clean-all t)
(xmtn-propagate-clean-all t)
(kill-buffer))
(defvar xmtn-propagate-actions-map
(let ((map (make-sparse-keymap "actions")))
(define-key map [?c] '(menu-item "c) clean/delete"
@ -442,15 +470,18 @@ The elements must all be of class xmtn-propagate-data.")
(define-key map [?g] '(menu-item "g) refresh"
xmtn-propagate-do-refresh-one
:visible (xmtn-propagate-refreshp)))
(define-key map [?8] '(menu-item (concat "8) update " (xmtn-propagate-to-name))
(define-key map [?9] '(menu-item (concat "9) status " (xmtn-propagate-to-name))
xmtn-propagate-status-to
:visible (xmtn-propagate-status-top)))
(define-key map [?8] '(menu-item (concat "8) status " (xmtn-propagate-from-name))
xmtn-propagate-status-from
:visible (xmtn-propagate-status-fromp)))
(define-key map [?7] '(menu-item (concat "7) update " (xmtn-propagate-to-name))
xmtn-propagate-update-to
:visible (xmtn-propagate-update-top)))
(define-key map [?7] '(menu-item (concat "7) commit " (xmtn-propagate-to-name))
xmtn-propagate-commit-to
:visible (xmtn-propagate-commit-top)))
(define-key map [?6] '(menu-item (concat "6) commit " (xmtn-propagate-from-name))
xmtn-propagate-commit-from
:visible (xmtn-propagate-commit-fromp)))
(define-key map [?6] '(menu-item (concat "6) update " (xmtn-propagate-from-name))
xmtn-propagate-update-from
:visible (xmtn-propagate-update-fromp)))
(define-key map [?5] '(menu-item "5) propagate"
xmtn-propagate-propagate
:visible (xmtn-propagate-propagatep)))
@ -463,12 +494,12 @@ The elements must all be of class xmtn-propagate-data.")
(define-key map [?2] '(menu-item (concat "2) ignore local changes " (xmtn-propagate-from-name))
xmtn-propagate-local-changes-from-ok
:visible (xmtn-propagate-local-changes-fromp)))
(define-key map [?1] '(menu-item (concat "1) status " (xmtn-propagate-to-name))
xmtn-propagate-status-to
:visible (xmtn-propagate-status-top)))
(define-key map [?0] '(menu-item (concat "0) status " (xmtn-propagate-from-name))
xmtn-propagate-status-from
:visible (xmtn-propagate-status-fromp)))
(define-key map [?1] '(menu-item (concat "1) commit " (xmtn-propagate-to-name))
xmtn-propagate-commit-to
:visible (xmtn-propagate-commit-top)))
(define-key map [?0] '(menu-item (concat "0) commit " (xmtn-propagate-from-name))
xmtn-propagate-commit-from
:visible (xmtn-propagate-commit-fromp)))
map)
"Keyboard menu keymap used to manage propagates.")
@ -481,10 +512,19 @@ The elements must all be of class xmtn-propagate-data.")
(define-key map [?g] 'xmtn-propagate-refresh)
(define-key map [?n] 'xmtn-propagate-next)
(define-key map [?p] 'xmtn-propagate-prev)
(define-key map [?q] 'xmtn-propagate-quit)
(define-key map [?s] 'xmtn-propagate-quit-save)
(define-key map [?q] 'dvc-buffer-quit)
map)
"Keymap used in `xmtn-propagate-mode'.")
(easy-menu-define xmtn-propagate-mode-menu xmtn-propagate-mode-map
"Mtn specific status menu."
`("DVC-Mtn"
["Do the right thing" xmtn-status-actions-map t]
["Quit, clean conflicts" dvc-buffer-quit t]
["Quit, save conflicts" xmtn-propagate-quit-save t]
))
(define-derived-mode xmtn-propagate-mode nil "xmtn-propagate"
"Major mode to propagate multiple workspaces."
(setq dvc-buffer-current-active-dvc 'xmtn)
@ -495,6 +535,7 @@ The elements must all be of class xmtn-propagate-data.")
(set (make-local-variable 'write-file-functions) nil)
(dvc-install-buffer-menu)
(add-hook 'kill-buffer-hook 'xmtn-propagate-clean-all nil t)
(setq buffer-read-only t)
(buffer-disable-undo)
(set-buffer-modified-p nil)
@ -505,21 +546,22 @@ The elements must all be of class xmtn-propagate-data.")
"t if DATA needs propagate."
(let ((result t)
(from-work (xmtn-propagate-from-work data))
(from-head-rev (xmtn-propagate-data-from-head-rev data))
(to-head-rev (xmtn-propagate-data-to-head-rev data)))
(from-head-rev (xmtn-propagate-data-from-head-revs data))
(to-head-rev (xmtn-propagate-data-to-head-revs data)))
(if (or (not from-head-rev)
(not to-head-rev))
(if (or (listp from-head-rev)
(listp to-head-rev))
;; multiple heads; can't propagate
(setq result nil)
;; cases:
;; 1) to branched off earlier, and propagate is needed
;; 2) propagate was just done but required no changes; no propagate needed
;;
(if (string= from-head-rev to-head-rev)
;; case 2
(setq result nil)
(let ((descendents (xmtn-automate-simple-command-output-lines from-work (list "descendents" from-head-rev)))
(let ((descendents (xmtn-automate-command-output-lines from-work (list "descendents" from-head-rev)))
done)
(if (not descendents)
;; case 1
@ -533,6 +575,7 @@ The elements must all be of class xmtn-propagate-data.")
result
))
<<<<<<< TREE
(defun xmtn-propagate-conflicts-buffer (data)
"Return a conflicts buffer for FROM-WORK, TO-WORK (absolute paths)."
(let ((from-work (xmtn-propagate-from-work data))
@ -562,39 +605,23 @@ The elements must all be of class xmtn-propagate-data.")
(xmtn-conflicts-review to-work)
(current-buffer)))))))
=======
>>>>>>> MERGE-SOURCE
(defun xmtn-propagate-conflicts (data)
"Return value for xmtn-propagate-data-conflicts for DATA."
(if (not (buffer-live-p (xmtn-propagate-data-conflicts-buffer data)))
;; user may have deleted conflicts buffer after resolving
;; conflicts; don't throw that away.
(setf (xmtn-propagate-data-conflicts-buffer data)
(xmtn-propagate-conflicts-buffer data)))
(let ((revs-current
(with-current-buffer (xmtn-propagate-data-conflicts-buffer data)
(and (string= (xmtn-propagate-data-from-head-rev data) xmtn-conflicts-left-revision)
(string= (xmtn-propagate-data-to-head-rev data) xmtn-conflicts-right-revision)))))
(if revs-current
(with-current-buffer (xmtn-propagate-data-conflicts-buffer data)
(xmtn-conflicts-update-counts)
(save-buffer))
;; else recreate conflicts
(xmtn-propagate-kill-conflicts-buffer data)
(xmtn-conflicts-clean (xmtn-propagate-to-work data))
(setf (xmtn-propagate-data-conflicts-buffer data)
(xmtn-propagate-conflicts-buffer data))
)
(with-current-buffer (xmtn-propagate-data-conflicts-buffer data)
(if (= xmtn-conflicts-total-count xmtn-conflicts-resolved-count)
(if (< 0 xmtn-conflicts-resolved-internal-count)
'need-review-resolve-internal
'ok)
'need-resolve))))
;; Only called if neither side needs merge. See
;; xmtn-propagate-propagate for assignment of 'left' = 'from'.
(let ((result (xmtn-conflicts-status
(xmtn-propagate-data-conflicts-buffer data) ; buffer
(xmtn-propagate-from-work data) ; left-work
(xmtn-propagate-data-from-head-revs data) ; left-rev
(xmtn-propagate-to-work data) ; right-work
(xmtn-propagate-data-to-head-revs data) ; right-rev
(xmtn-propagate-data-from-branch data) ; left-branch
(xmtn-propagate-data-to-branch data) ; right-branch
)))
(setf (xmtn-propagate-data-conflicts-buffer data) (car result))
(cadr result)))
(defun xmtn-propagate-refresh-one (data refresh-local-changes)
"Refresh DATA."
@ -607,24 +634,24 @@ The elements must all be of class xmtn-propagate-data.")
(from-base-rev (xmtn--get-base-revision-hash-id-or-null from-work)))
(case (length heads)
(1
(setf (xmtn-propagate-data-from-head-rev data) (nth 0 heads))
(if (string= (xmtn-propagate-data-from-head-rev data) from-base-rev)
(setf (xmtn-propagate-data-from-head-revs data) (nth 0 heads))
(if (string= (xmtn-propagate-data-from-head-revs data) from-base-rev)
(setf (xmtn-propagate-data-from-heads data) 'at-head)
(setf (xmtn-propagate-data-from-heads data) 'need-update)))
(t
(setf (xmtn-propagate-data-from-head-rev data) nil)
(setf (xmtn-propagate-data-from-head-revs data) (list (nth 0 heads) (nth 1 heads)))
(setf (xmtn-propagate-data-from-heads data) 'need-merge))))
(let ((heads (xmtn--heads to-work (xmtn-propagate-data-to-branch data)))
(to-base-rev (xmtn--get-base-revision-hash-id-or-null to-work)))
(case (length heads)
(1
(setf (xmtn-propagate-data-to-head-rev data) (nth 0 heads))
(if (string= (xmtn-propagate-data-to-head-rev data) to-base-rev)
(setf (xmtn-propagate-data-to-head-revs data) (nth 0 heads))
(if (string= (xmtn-propagate-data-to-head-revs data) to-base-rev)
(setf (xmtn-propagate-data-to-heads data) 'at-head)
(setf (xmtn-propagate-data-to-heads data) 'need-update)))
(t
(setf (xmtn-propagate-data-to-head-rev data) nil)
(setf (xmtn-propagate-data-to-head-revs data) (list (nth 0 heads) (nth 1 heads)))
(setf (xmtn-propagate-data-to-heads data) 'need-merge))))
(setf (xmtn-propagate-data-propagate-needed data)
@ -635,19 +662,15 @@ The elements must all be of class xmtn-propagate-data.")
(setf (xmtn-propagate-data-from-local-changes data) 'need-scan)
(setf (xmtn-propagate-data-to-local-changes data) 'need-scan)))
(if (or refresh-local-changes
(xmtn-propagate-data-propagate-needed data))
;; these checks are slow, so don't do them if they probably are not needed.
(progn
(ecase (xmtn-propagate-data-from-local-changes data)
(need-scan
(xmtn-propagate-create-from-status-buffer data))
(t nil))
(ecase (xmtn-propagate-data-from-local-changes data)
(need-scan
(xmtn-propagate-create-from-status-buffer data))
(t nil))
(ecase (xmtn-propagate-data-to-local-changes data)
(need-scan
(xmtn-propagate-create-to-status-buffer data))
(t nil))))
(ecase (xmtn-propagate-data-to-local-changes data)
(need-scan
(xmtn-propagate-create-to-status-buffer data))
(t nil))
(if (xmtn-propagate-data-propagate-needed data)
(progn

View File

@ -1,6 +1,6 @@
;;; xmtn-revlist.el --- Interactive display of revision histories for monotone
;; Copyright (C) 2008 - 2010 Stephen Leake
;; Copyright (C) 2008 - 2011 Stephen Leake
;; Copyright (C) 2006, 2007 Christian M. Ohler
;; Author: Christian M. Ohler
@ -74,9 +74,7 @@ arg; root. Result is of the form:
authors
dates
changelogs
tags
parent-hash-ids
child-hash-ids)
tags)
;;;###autoload
(defun xmtn-revision-refresh-maybe ()
@ -91,17 +89,9 @@ arg; root. Result is of the form:
(defun xmtn-revision-list-entry-patch-printer (patch)
(let ((entry (dvc-revlist-entry-patch-struct patch)))
(assert (typep entry 'xmtn--revlist-entry))
(insert (format " %s %s%s\n"
(insert (format " %s %s\n"
(if (dvc-revlist-entry-patch-marked patch) "*" " ")
(xmtn--revlist-entry-revision-hash-id entry)
(let ((head-p
(endp (xmtn--revlist-entry-child-hash-ids entry)))
(root-p
(endp (xmtn--revlist-entry-parent-hash-ids entry))))
(cond ((and head-p root-p) " (head, root)")
(head-p " (head)")
(root-p " (root)")
(t "")))))
(xmtn--revlist-entry-revision-hash-id entry)))
(dolist (tag (xmtn--revlist-entry-tags entry))
(insert (format " Tag: %s\n" tag)))
(let ((authors (xmtn--revlist-entry-authors entry))
@ -117,7 +107,7 @@ arg; root. Result is of the form:
(eql (length dates) len)
(eql (length changelogs) len)))
(loop
;; FIXME: Matching the k-th author cert with the k-th date cert
;; Matching the k-th author cert with the k-th date cert
;; and the k-th changelog cert, like we do here, is unlikely to
;; be correct in general. That the relationship between date,
;; message and author of a commit is lost appears to be a
@ -145,9 +135,12 @@ arg; root. Result is of the form:
(insert (format " %s\n" line))))))))))
(defun xmtn--revlist-setup-ewoc (root ewoc header footer revision-hash-ids last-n)
(assert (every (lambda (x) (typep x 'xmtn--hash-id)) revision-hash-ids))
(ewoc-set-hf ewoc header footer)
(ewoc-filter ewoc (lambda (x) nil)) ; Clear it.
;; FIXME: setup should not modify order; this should be a waste of
;; time or wrong. This was here historically; see
;; xmtn--log-generator for comment on why I have not removed it. I
;; have not investigated order problems with other revlists.
(setq revision-hash-ids (xmtn--toposort root revision-hash-ids))
(if last-n
(let ((len (length revision-hash-ids)))
@ -159,8 +152,6 @@ arg; root. Result is of the form:
(1 "Setting up revlist buffer (1 revision)...")
(t (format "Setting up revlist buffer (%s revisions)..."
(length revision-hash-ids))))
;; Maybe also show parents and children? (Could add toggle
;; commands to show/hide these.)
(lexical-let ((rev (aref revision-hash-ids i))
(branches (list))
(authors (list))
@ -189,36 +180,21 @@ arg; root. Result is of the form:
changelogs (nreverse changelogs)
branches (nreverse branches)
tags (nreverse tags))
(let ((parent-hash-ids
(xmtn-automate-simple-command-output-lines root `("parents"
,rev)))
(child-hash-ids
(xmtn-automate-simple-command-output-lines root `("children"
,rev))))
(xmtn--assert-optional (every #'stringp authors))
(xmtn--assert-optional (every #'stringp dates))
(xmtn--assert-optional (every #'stringp changelogs))
(xmtn--assert-optional (every #'stringp branches))
(xmtn--assert-optional (every #'stringp tags))
(xmtn--assert-optional (every #'xmtn--hash-id-p parent-hash-ids))
(xmtn--assert-optional (every #'xmtn--hash-id-p child-hash-ids))
(ewoc-enter-last ewoc
;; Creating a list `(entry-patch
;; ,instance-of-dvc-revlist-entry-patch) seems
;; to be part of DVC's API.
`(entry-patch
,(make-dvc-revlist-entry-patch
:dvc 'xmtn
:rev-id `(xmtn (revision ,rev))
:struct (xmtn--make-revlist-entry
:revision-hash-id rev
:branches branches
:authors authors
:dates dates
:changelogs changelogs
:tags tags
:parent-hash-ids parent-hash-ids
:child-hash-ids child-hash-ids)))))))
(ewoc-enter-last ewoc
;; Creating a list `(entry-patch
;; ,instance-of-dvc-revlist-entry-patch) seems
;; to be part of DVC's API.
`(entry-patch
,(make-dvc-revlist-entry-patch
:dvc 'xmtn
:rev-id `(xmtn (revision ,rev))
:struct (xmtn--make-revlist-entry
:revision-hash-id rev
:branches branches
:authors authors
:dates dates
:changelogs changelogs
:tags tags))))))
nil)
(defun xmtn-revision-st-message (entry)
@ -226,11 +202,21 @@ arg; root. Result is of the form:
(defun xmtn--revlist-refresh ()
(let ((root default-directory))
<<<<<<< TREE
(destructuring-bind (merge-destination-branch
header-lines footer-lines revision-hash-ids)
=======
(destructuring-bind (header-lines footer-lines revs)
>>>>>>> MERGE-SOURCE
(funcall xmtn--revlist-*info-generator-fn* root)
<<<<<<< TREE
(setq xmtn--revlist-*merge-destination-branch* merge-destination-branch)
(let ((ewoc dvc-revlist-cookie))
=======
(let ((ewoc dvc-revlist-cookie)
(count (length revs))
(last-n dvc-revlist-last-n))
>>>>>>> MERGE-SOURCE
(xmtn--revlist-setup-ewoc root ewoc
(with-temp-buffer
(dolist (line header-lines)
@ -238,7 +224,16 @@ arg; root. Result is of the form:
(insert ?\n)
(insert line ?\n)))
(when header-lines (insert ?\n))
(buffer-string))
(insert
(cond
((= 0 count) "No revisions")
((= 1 count) "1 revision:")
((or (null last-n)
(> last-n count))
(format "%d of %d revisions:" count count))
(t (format "%d of %d revisions:" last-n count))))
(insert ?\n)
(buffer-string))
(with-temp-buffer
(when footer-lines (insert ?\n))
(dolist (line footer-lines)
@ -246,7 +241,7 @@ arg; root. Result is of the form:
(insert ?\n)
(insert line ?\n)))
(buffer-string))
revision-hash-ids
revs
dvc-revlist-last-n)
(if (null (ewoc-nth ewoc 0))
(goto-char (point-max))
@ -284,6 +279,7 @@ arg; root. Result is of the form:
;;;###autoload
(defun xmtn-dvc-changelog (&optional path)
<<<<<<< TREE
(xmtn--log-helper (dvc-tree-root) path nil nil))
(defun xmtn--log-helper (root path first-line-only-p last-n)
@ -367,6 +363,41 @@ arg; root. Result is of the form:
(length difference)))))
'()
difference)))
=======
(xmtn--setup-revlist
(dvc-tree-root)
'xmtn--log-generator
path
nil ;; first-line-only-p
nil ;; last-n
))
(defun xmtn--log-generator (root)
(let ((branch (xmtn--tree-default-branch root)))
(let
((header
(list (format "Log for branch %s" branch)))
(options
;; FIXME: this gives most the recent date first, we want
;; that last. See mtn issue 118 for why we can't fix that
;; with more options. The 'toposort' in
;; xmtn--revlist-setup-ewoc puts it in the desired date
;; order. In general, it would be better if revlist-setup
;; did not alter the order.
(if dvc-revlist-last-n
(list "last" (format "%d" dvc-revlist-last-n))))
(command
(if xmtn--revlist-*path*
(list "log" xmtn--revlist-*path*)
(list "log")))
)
;; See xmtn--revlist-*info-generator-fn* for result format
(list header
'() ;; footer
(xmtn-automate-command-output-lines ;; revisions
root
(cons options command))))))
>>>>>>> MERGE-SOURCE
(defun xmtn-revlist-show-conflicts ()
"If point is on a revision that has two parents, show conflicts
@ -396,59 +427,40 @@ from the merge."
(setq right-rev (substring changelog start end)))
((string= (substring changelog 0 5) "merge")
((or
(string= (substring changelog 0 5) "merge")
(string= (substring changelog 0 14) "explicit merge"))
(setq start (+ 4 (string-match "of" changelog)))
(setq end (string-match "'" changelog start))
(setq left-rev (substring changelog start (1- end)))
(setq left-rev (substring changelog start end))
(setq start (+ 5 (string-match "and" changelog start)))
(setq end (string-match "'" changelog start))
(setq right-rev (substring changelog start (1- end))))
(setq right-rev (substring changelog start end)))
(t
(error "not on a two parent revision")))
(xmtn-conflicts-save-opts
(read-file-name "left work: ")
(read-file-name "right work: ")
(xmtn-conflicts-review
default-directory ; left-work
left-rev
default-directory ; right-work
right-rev
left-branch
right-branch)
(dvc-run-dvc-async
'xmtn
(list "conflicts" "store" left-rev right-rev)
:finished (lambda (output error status arguments)
(let ((conflicts-buffer (dvc-get-buffer-create 'xmtn 'conflicts default-directory)))
(pop-to-buffer conflicts-buffer)
(xmtn-conflicts-load-opts)
(set (make-local-variable 'after-insert-file-functions) '(xmtn-conflicts-after-insert-file))
(insert-file-contents "_MTN/conflicts" t)))
:error (lambda (output error status arguments)
(pop-to-buffer error)))))
right-branch
t)))
;;;###autoload
(defvar xmtn-revlist-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "CM" 'xmtn-conflicts-merge)
(define-key map "CP" 'xmtn-conflicts-propagate)
(define-key map "CR" 'xmtn-conflicts-review)
(define-key map "CC" 'xmtn-conflicts-clean)
(define-key map "MH" 'xmtn-view-heads-revlist)
(define-key map "MP" 'xmtn-propagate-from)
(define-key map "MC" 'xmtn-revlist-show-conflicts)
(define-key map "CC" 'xmtn-conflicts-clean)
map))
;; items added here should probably also be added to xmtn-diff-mode-menu, -map in xmtn-dvc.el
(easy-menu-define xmtn-revlist-mode-menu xmtn-revlist-mode-map
"Mtn specific revlist menu."
`("DVC-Mtn"
["View Heads" xmtn-view-heads-revlist t]
["Show merge conflicts before merge" xmtn-conflicts-merge t]
["Show merge conflicts after merge" xmtn-revlist-show-conflicts t]
["Show propagate conflicts" xmtn-conflicts-propagate t]
["Review conflicts" xmtn-conflicts-review t]
["Propagate branch" xmtn-propagate-from t]
["Clean conflicts resolutions" xmtn-conflicts-clean t]
))
@ -463,9 +475,26 @@ from the merge."
(let ((root (dvc-tree-root)))
(xmtn--setup-revlist
root
<<<<<<< TREE
'xmtn--revlist--missing-get-info
;; Passing nil as first-line-only-p is arbitrary here.
;;
=======
(lambda (root)
(let ((revs
(xmtn-automate-command-output-lines
root
(cons (list "from" "h:" "to" "w:") (list "log")))))
(list
(list ;; header
(format "workspace %s" root)
nil ;; blank line
"Revisions that are not in base revision")
'() ;; footer
revs)))
nil ;; path
nil ;; first-line-only-p
>>>>>>> MERGE-SOURCE
;; When the missing revs are due to a propagate, there can be a
;; lot of them, but we only really need to see the revs since the
;; propagate. So dvc-log-last-n is appropriate. We use
@ -475,12 +504,28 @@ from the merge."
nil)
;;;###autoload
(defun xmtn-review-update (root)
(defun xmtn-update-review (root)
"Review revisions in last update of ROOT workspace."
(interactive "D")
(xmtn--setup-revlist
root
<<<<<<< TREE
'xmtn--revlist--review-update-info
=======
(lambda (root)
(let ((revs
(xmtn-automate-command-output-lines
root
(cons (list "from" "w:" "to" "u:") (list "log")))))
(list
(list ;; header
(format "workspace %s" root)
nil ;; blank line
"Revisions in last update")
'() ;; footer
revs)))
nil ;; path
>>>>>>> MERGE-SOURCE
nil ;; first-line-only-p
dvc-log-last-n)
nil)
@ -494,9 +539,9 @@ from the merge."
root
(lambda (root)
(let* ((branch (xmtn--tree-default-branch root))
(head-revision-hash-ids (xmtn--heads root branch))
(head-count (length head-revision-hash-ids)))
(head-revision-hash-ids (xmtn--heads root branch)))
(list
<<<<<<< TREE
branch
(list (format "Tree %s" root)
(format "Branch %s" branch)
@ -505,6 +550,12 @@ from the merge."
(1 "1 head revision:")
(t (format "%s head revisions: " head-count))))
'()
=======
(list ; header
(format "workspace %s" root)
"Head revisions")
'() ; footer
>>>>>>> MERGE-SOURCE
head-revision-hash-ids)))
;; Passing nil as first-line-only-p, last-n is arbitrary here.
nil nil))
@ -566,6 +617,7 @@ to the base revision of the current tree."
(revision-hash-ids (xmtn--expand-selector root selector))
(count (length revision-hash-ids)))
(list
<<<<<<< TREE
branch
(list (format "Tree %s" root)
(format "Default branch %s" branch)
@ -579,6 +631,16 @@ to the base revision of the current tree."
(t (format "%s revisions matching selector: "
count))))
'()
=======
(list ; header
(format "workspace %s" root)
(if (with-syntax-table (standard-syntax-table)
(string-match "\\`\\s *\\'" selector))
"Blank selector"
(format "Selector %s" selector))
"Revisions matching selector")
'() ; footer
>>>>>>> MERGE-SOURCE
revision-hash-ids)))
;; Passing nil as first-line-only-p is arbitrary here.
nil

View File

@ -1,6 +1,6 @@
;;; xmtn-run.el --- Functions for runnning monotone commands
;; Copyright (C) 2008 - 2010 Stephen Leake
;; Copyright (C) 2008 - 2011 Stephen Leake
;; Copyright (C) 2006, 2007 Christian M. Ohler
;; Author: Christian M. Ohler
@ -43,6 +43,11 @@
(define-coding-system-alias 'xmtn--monotone-normal-form 'utf-8-unix)
(defun xmtn-dvc-prepare-environment (env)
"Prepare the environment to run mtn."
;; DVC expects monotone messages in the C locale
(cons "LC_MESSAGES=C" env))
(defun* xmtn--run-command-sync (root arguments)
(xmtn--check-cached-command-version)
(let ((default-directory (file-truename (or root default-directory))))
@ -71,6 +76,7 @@
,@arguments)
dvc-run-keys)))
<<<<<<< TREE
(defun xmtn--command-output-lines (root arguments)
"Run mtn in ROOT with ARGUMENTS and return its output as a list of strings."
(xmtn--check-cached-command-version)
@ -107,6 +113,9 @@ Signals an error if more (or fewer) than one line is output."
(first lines)))
(defconst xmtn--minimum-required-command-version '(0 46))
=======
(defconst xmtn--minimum-required-command-version '(0 99))
>>>>>>> MERGE-SOURCE
;; see also xmtn-sync.el xmtn-sync-required-command-version
(defconst xmtn--required-automate-format-version "2")
@ -139,10 +148,11 @@ Sets cache if not already set."
(defun xmtn--command-version (executable)
"Return EXECUTABLE's version as a list (MAJOR MINOR REVISION VERSION-STRING).
VERSION-STRING is the string printed by mtn --version (with no
VERSION-STRING is the string printed by `mtn version' (with no
trailing newline). MAJOR and MINOR are integers, a parsed
representation of the version number. REVISION is the revision
id."
<<<<<<< TREE
(let (
;; Cache a fake version number to avoid infinite mutual
;; recursion.
@ -163,6 +173,28 @@ id."
(minor (parse-integer string (match-beginning 2) (match-end 2)))
(revision (match-string 4 string)))
(list major minor revision string)))))
=======
(let ((version-string))
(dvc-run-dvc-sync
'xmtn
'("version")
:finished
(lambda (output error status arguments)
(with-current-buffer output
(setq version-string (buffer-substring-no-properties (point-min) (1- (point-max)))))))
(unless (string-match
(concat "\\`monotone \\([0-9]+\\)\\.\\([0-9]+\\)\\(\\.[0-9]+\\)?\\(dev\\)?"
" (base revision: \\(unknown\\|\\([0-9a-f]\\{40\\}\\)\\))\\'")
version-string)
(error (concat "Version output from monotone version"
" did not match expected pattern: %S")
version-string))
(let ((major (parse-integer version-string (match-beginning 1) (match-end 1)))
(minor (parse-integer version-string (match-beginning 2) (match-end 2)))
(revision (match-string 4 version-string)))
(list major minor revision version-string))))
>>>>>>> MERGE-SOURCE
(defun xmtn--check-cached-command-version ()
(let ((minimum-version xmtn--minimum-required-command-version)

View File

@ -1,6 +1,6 @@
;;; xmtn-sync.el --- database sync handling for DVC backend for monotone
;;
;; Copyright (C) 2010 Stephen Leake
;; Copyright (C) 2010, 2011 Stephen Leake
;;
;; Author: Stephen Leake
;; Keywords: tools
@ -47,6 +47,12 @@
(defvar xmtn-sync-config "xmtn-sync-config"
"File to store `xmtn-sync-branch-alist' and `xmtn-sync-remote-exec-alist'; relative to `dvc-config-directory'.")
(defvar xmtn-sync-sort nil
"User-supplied function to sort branches.
Called with a string containing the mtn branch name; return
'(node key) where node is the ewoc node to insert before (nil to
insert at end), key is the sort-key. Sync buffer is current.")
;;; Internal variables
<<<<<<< TREE
(defconst xmtn-sync-required-command-version '(0 46)
@ -119,10 +125,80 @@ All xmtn-sync functions operate on this ewoc.
The elements must all be of type xmtn-sync-sync.")
(make-variable-buffer-local 'xmtn-sync-ewoc)
<<<<<<< TREE
=======
(defstruct (xmtn-sync-branch
(:copier nil))
;; ewoc element; data for a branch that was received
name ;; monotone branch name
rev-alist ;; alist of '(revid (date author changelog)) for received revs
send-count ;; integer count of sent revs
print-mode ;; 'summary | 'brief | 'full | 'started
sort-key ;; for use by xmtn-sync-sort
)
(defun xmtn-sync-print-rev (rev print-mode)
"Print a REV (element of branch rev-alist) according to PRINT-MODE ('brief or 'full)."
(let ((date (nth 0 (cadr rev)))
(author (nth 1 (cadr rev)))
(changelog (nth 2 (cadr rev))))
(insert (dvc-face-add (format "\n %s %s\n" date author) 'dvc-header))
(ecase print-mode
(brief
(insert (substring changelog 0 (string-match "\n" changelog))))
(full
(insert changelog)))))
(defun xmtn-sync-printer (branch)
"Print an ewoc element; BRANCH must be of type xmtn-sync-branch."
;; sometimes mtn will allow a revision with no branch!
(if (xmtn-sync-branch-name branch)
(insert (dvc-face-add (xmtn-sync-branch-name branch) 'dvc-keyword))
(insert (dvc-face-add "<no branch>" 'dvc-keyword)))
(insert (format " rx %d tx %d\n"
(length (xmtn-sync-branch-rev-alist branch))
(xmtn-sync-branch-send-count branch)))
(ecase (xmtn-sync-branch-print-mode branch)
(summary nil)
((brief full)
(loop for rev in (xmtn-sync-branch-rev-alist branch) do
(xmtn-sync-print-rev rev (xmtn-sync-branch-print-mode branch))))
(started
(insert " started\n")))
)
(defun xmtn-sync-brief ()
"Set display mode for current item to brief."
(interactive)
(let* ((elem (ewoc-locate xmtn-sync-ewoc))
(data (ewoc-data elem)))
(setf (xmtn-sync-branch-print-mode data) 'brief)
(ewoc-invalidate xmtn-sync-ewoc elem)))
(defun xmtn-sync-full ()
"Set display mode for current item to full."
(interactive)
(let* ((elem (ewoc-locate xmtn-sync-ewoc))
(data (ewoc-data elem)))
(setf (xmtn-sync-branch-print-mode data) 'full)
(ewoc-invalidate xmtn-sync-ewoc elem)))
(defun xmtn-sync-summary ()
"Set display mode for current item to summary."
(interactive)
(let* ((elem (ewoc-locate xmtn-sync-ewoc))
(data (ewoc-data elem)))
(setf (xmtn-sync-branch-print-mode data) 'summary)
(ewoc-invalidate xmtn-sync-ewoc elem)))
>>>>>>> MERGE-SOURCE
(defun xmtn-sync-status ()
"Start xmtn-status-one for current ewoc element."
(let* ((data (ewoc-data (ewoc-locate xmtn-sync-ewoc)))
(branch (xmtn-sync-branch-name data))
<<<<<<< TREE
(work (assoc branch xmtn-sync-branch-alist)))
(if (not work)
(progn
@ -134,21 +210,105 @@ The elements must all be of type xmtn-sync-sync.")
(let ((map (make-sparse-keymap)))
(define-key map [?0] '(menu-item "0) status"
'xmtn-sync-status))
=======
save-work
(work (or
(cadr (assoc branch xmtn-sync-branch-alist))
(if (functionp xmtn-sync-guess-workspace)
(funcall xmtn-sync-guess-workspace branch))
(prog1
(read-directory-name (format "workspace root for %s: " branch))
(setq save-work t))
)))
(setf (xmtn-sync-branch-print-mode data) 'started) ; indicate we've started work on it
(ewoc-invalidate xmtn-sync-ewoc elem)
(condition-case err
(xmtn-status-one work)
('error
(if (and (not save-work) (functionp xmtn-sync-guess-workspace))
;; xmtn-sync-guess-workspace guessed wrong; prompt and try again
(progn
(setq work (read-directory-name (format "workspace root for %s: " branch)))
(setq save-work t)
(xmtn-status-one work)))))
;; don't save the workspace association until it is validated by xmtn-status-one
(if save-work
(progn
(push (list branch work) xmtn-sync-branch-alist)
(dvc-save-state
(list 'xmtn-sync-branch-alist)
(expand-file-name xmtn-sync-branch-file dvc-config-directory))))))
(defun xmtn-sync-update ()
"Start xmtn-status-on for current ewoc element, do update if possible."
(interactive)
(xmtn-sync-status)
(if (xmtn-status-updatep)
(xmtn-status-update)))
(defun xmtn-sync-clean ()
"Clean and delete current ewoc element."
(interactive)
(let* ((elem (ewoc-locate xmtn-sync-ewoc))
(status-buffer (get-buffer-create "*xmtn-multi-status*"))
(inhibit-read-only t))
(if (buffer-live-p status-buffer)
(kill-buffer status-buffer))
(ewoc-delete xmtn-sync-ewoc elem)))
(dvc-make-ewoc-next xmtn-sync-next xmtn-sync-ewoc)
(dvc-make-ewoc-prev xmtn-sync-prev xmtn-sync-ewoc)
(defvar xmtn-sync-kbd-map
(let ((map (make-sparse-keymap "action")))
;; last defined is first in displayed menu
(define-key map [?c] '(menu-item "c) clean" xmtn-sync-clean))
(define-key map [?f] '(menu-item "f) full" xmtn-sync-full))
(define-key map [?b] '(menu-item "b) brief" xmtn-sync-brief))
(define-key map [?s] '(menu-item "s) status" xmtn-sync-status))
(define-key map [?u] '(menu-item "u) update" xmtn-sync-update))
>>>>>>> MERGE-SOURCE
map)
"Keyboard menu keymap for xmtn-sync-ewoc.")
(defvar xmtn-sync-mode-map
(let ((map (make-sparse-keymap)))
<<<<<<< TREE
(define-key map [?q] 'dvc-buffer-quit)
(define-key map "\M-d" xmtn-sync-ewoc-map)
=======
(define-key map "\M-d" xmtn-sync-kbd-map)
(define-key map [?b] 'xmtn-sync-brief)
(define-key map [?c] 'xmtn-sync-clean)
(define-key map [?f] 'xmtn-sync-full)
(define-key map [?n] 'xmtn-sync-next)
(define-key map [?p] 'xmtn-sync-prev)
(define-key map [?q] 'dvc-buffer-quit)
(define-key map [?s] 'xmtn-sync-status)
(define-key map [?u] 'xmtn-sync-update)
(define-key map [?S] 'xmtn-sync-save)
>>>>>>> MERGE-SOURCE
map)
"Keymap used in `xmtn-sync-mode'.")
(easy-menu-define xmtn-sync-mode-menu xmtn-sync-mode-map
"`xmtn-sync' menu"
`("Xmtn-sync"
<<<<<<< TREE
["Do the right thing" xmtn-sync-ewoc-map t]
["Quit" dvc-buffer-quit t]
=======
;; first item is top in display
["Status" xmtn-sync-status t]
["Update" xmtn-sync-update t]
["Brief display" xmtn-sync-brief t]
["Full display" xmtn-sync-full t]
["Clean/delete" xmtn-sync-clean t]
["Save" xmtn-sync-save t]
["Save and Quit" (lambda () (kill-buffer (current-buffer))) t]
>>>>>>> MERGE-SOURCE
))
;; derive from nil causes no keymap to be used, but still have self-insert keys
@ -160,12 +320,21 @@ The elements must all be of type xmtn-sync-sync.")
(setq xmtn-sync-ewoc (ewoc-create 'xmtn-sync-printer))
(setq dvc-buffer-refresh-function nil)
(dvc-install-buffer-menu)
<<<<<<< TREE
<<<<<<< TREE
(setq buffer-read-only t)
(buffer-disable-undo)
(set-buffer-modified-p nil))
=======
(buffer-disable-undo))
=======
(add-hook 'kill-buffer-hook 'xmtn-sync-save nil t)
(buffer-disable-undo)
(unless xmtn-sync-branch-alist
(let ((branch-file (expand-file-name xmtn-sync-branch-file dvc-config-directory)))
(if (file-exists-p branch-file)
(load branch-file)))))
>>>>>>> MERGE-SOURCE
(defun xmtn-sync-parse-revision-certs (direction)
"Parse certs associated with a revision; return (branch changelog date author)."
@ -226,21 +395,29 @@ The elements must all be of type xmtn-sync-sync.")
xmtn-sync-ewoc)
(if (not old-branch)
(ewoc-enter-last
xmtn-sync-ewoc
(ecase direction
('receive
(make-xmtn-sync-branch
:name branch
:rev-alist (list (list revid (list date author changelog)))
:send-count 0
:print-mode 'summary))
('send
(make-xmtn-sync-branch
:name branch
:rev-alist nil
:send-count 1
:print-mode 'summary)))))))
(let*
((node-key (and (functionp xmtn-sync-sort)
(funcall xmtn-sync-sort branch)))
(data
(ecase direction
('receive
(make-xmtn-sync-branch
:name branch
:rev-alist (list (list revid (list date author changelog)))
:send-count 0
:print-mode 'summary
:sort-key (nth 1 node-key)))
('send
(make-xmtn-sync-branch
:name branch
:rev-alist nil
:send-count 1
:print-mode 'summary
:sort-key (nth 1 node-key))))))
(if (nth 0 node-key)
(ewoc-enter-before xmtn-sync-ewoc (nth 0 node-key) data)
(ewoc-enter-last xmtn-sync-ewoc data))
))))
(defun xmtn-sync-parse-revisions (direction)
"Parse revisions with associated certs."
@ -260,7 +437,6 @@ The elements must all be of type xmtn-sync-sync.")
(defun xmtn-sync-parse-certs (direction)
"Parse certs not associated with revisions."
;; The only case we care about is a new branch created from an existing revision.
(let ((keyword (ecase direction
('receive "receive_cert")
('send "send_cert")))
@ -269,12 +445,14 @@ The elements must all be of type xmtn-sync-sync.")
branch
(date "")
(author "")
(changelog "create branch\n")
(changelog "create or propagate branch\n")
old-branch)
(while (xmtn-basic-io-optional-line keyword (setq cert-label (cadar value)))
(cond
((string= cert-label "branch")
;; This happens when a new branch is created, or a branch is
;; propagated without any conflicts.
(xmtn-basic-io-check-line "value" (setq branch (cadar value)))
(xmtn-basic-io-skip-line "key")
(xmtn-basic-io-check-line "revision" (setq revid (cadar value)))
@ -300,7 +478,8 @@ The elements must all be of type xmtn-sync-sync.")
(while (xmtn-basic-io-optional-skip-line keyword))))
(defun xmtn-sync-parse (begin)
"Parse current buffer starting at BEGIN, fill in `xmtn-sync-ewoc' in current buffer, erase parsed text."
"Parse current buffer starting at BEGIN, fill in `xmtn-sync-ewoc' in current buffer, erase parsed text.
Return non-nil if anything parsed."
(set-syntax-table xmtn-basic-io--*syntax-table*)
(goto-char begin)
@ -358,7 +537,9 @@ The elements must all be of type xmtn-sync-sync.")
(xmtn-sync-parse-revisions 'send)
(xmtn-sync-parse-keys 'send)
(delete-region begin (point))
(let ((result (not (= begin (point)))))
(delete-region begin (point))
result)
)
(defun xmtn-sync-load-file (&optional noerror)
@ -371,10 +552,14 @@ The elements must all be of type xmtn-sync-sync.")
(setq buffer-read-only nil)
(dolist (data stuff) (ewoc-enter-last xmtn-sync-ewoc data))
(setq buffer-read-only t)
<<<<<<< TREE
(set-buffer-modified-p nil))
(unless noerror
(error "%s file not found" save-file)))))
>>>>>>> MERGE-SOURCE
=======
(set-buffer-modified-p nil)))))
>>>>>>> MERGE-SOURCE
;;;###autoload
(defun xmtn-sync-sync (local-db remote-host remote-db)
@ -463,10 +648,6 @@ Remote-db should include branch pattern in URI syntax."
(setq buffer-read-only t)
(set-buffer-modified-p nil)
(xmtn-sync-save)
(unless xmtn-sync-branch-alist
(let ((branch-file (expand-file-name xmtn-sync-branch-file dvc-config-directory)))
(if (file-exists-p branch-file)
(load branch-file))))
))
(defun xmtn-sync-save ()
@ -492,14 +673,18 @@ Remote-db should include branch pattern in URI syntax."
"Display sync results in FILE (defaults to `xmtn-sync-review-file'), appended to content of `xmtn-sync-save-file'.
FILE should be output of 'automate sync'. (external sync handles tickers better)."
(interactive)
;; first load xmtn-sync-save-file
(pop-to-buffer (get-buffer-create "*xmtn-sync*"))
(setq buffer-read-only nil)
(delete-region (point-min) (point-max))
(xmtn-sync-mode)
(xmtn-sync-load-file)
(if (buffer-live-p (get-buffer "*xmtn-sync*"))
(progn
(pop-to-buffer "*xmtn-sync*")
(xmtn-sync-save))
;; else create
(pop-to-buffer (get-buffer-create "*xmtn-sync*"))
(setq buffer-read-only nil)
(delete-region (point-min) (point-max))
(xmtn-sync-mode)
(xmtn-sync-load-file file))
;; now add file
;; now add FILE
(setq file (or file
(expand-file-name xmtn-sync-review-file dvc-config-directory)))
(if (file-exists-p file)
@ -507,8 +692,12 @@ FILE should be output of 'automate sync'. (external sync handles tickers better)
(goto-char (point-min))
(setq buffer-read-only nil)
(insert-file-contents-literally file)
(xmtn-sync-parse (point-min))
;; user may have run several syncs, dumping each output into FILE; loop thru each.
(while (xmtn-sync-parse (point-min)))
(setq buffer-read-only t)
(set-buffer-modified-p nil)
(xmtn-sync-save)
(delete-file file))))
>>>>>>> MERGE-SOURCE

View File

@ -50,7 +50,11 @@ uninstall:
info: dvc.info dvc-intro.info
<<<<<<< TREE
alldeps = $(srcdir)/dvc.texinfo dvc-version.texinfo
=======
alldeps = $(srcdir)/dvc.texinfo dvc-version.texinfo $(srcdir)/dvc-intro.texinfo
>>>>>>> MERGE-SOURCE
dvc.info: $(alldeps)
$(MAKEINFO) $(srcdir)/dvc.texinfo

View File

@ -14,7 +14,7 @@ distributed version control systems.
@smallexample
@group
Copyright (C) 2007, 2008, 2009, 2010 Stephen Leake
Copyright (C) 2007 - 2011 Stephen Leake
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
@ -48,6 +48,10 @@ Invoking
* xmtn-status-one::
* xmtn-propagate-one::
<<<<<<< TREE
=======
* xmtn-sync-review::
>>>>>>> MERGE-SOURCE
Key bindings
@ -102,6 +106,9 @@ and managing branches require command line operations.
This manual describes the DVC user interface, and gives examples of
some required command line operations, using the monotone backend.
It also describes some DVC extensions that are specific to the
monotone backend.
@menu
* Basic DVC::
* Compare to CVS::
@ -116,7 +123,7 @@ use DVC, and providing common terminology.
Each backend will have its own documentation, and terminology that
differs from this. The terms here are taken mostly from the monotone
backend, since it has the most readable user manual.
backend.
Let's start with some definitions:
@ -144,9 +151,10 @@ The user interacts with the remote database in order to retrieve other
user's files, or deliver files to them.
@item revision
A set of changes to files that are applied together. Most operations
on the database involve revisions, and all changes to files are part
of a revision.
The state of the entire workspace, usually including the set of
changes to the workspace that transform it from the previous
revision. Most operations on the database involve revisions, and all
changes to files are part of a revision.
@item branch
A label for distinct trees of revisions. There are two main uses for
@ -159,7 +167,7 @@ A database can store any number of branches.
@item heads
The revisions that are the leaves of the history tree on a single
branch. In monotone, there can be any number of heads (see
branch. In monotone, there can be any number of heads on a branch (see
@ref{Merging}).
@item merge
@ -190,7 +198,7 @@ The name of the buffer is not literally @dfn{*dvc-status*}; instead,
@dfn{*dvc-status*}.
@item *dvc-diff* buffer
Another main user interface buffer. It shows the files involved in a
Another main user interface buffer. It shows the files changed in a
particular revision, together with the diffs of the changes. Single
keystrokes invoke various operations.
@ -284,31 +292,40 @@ Similar to @command{xmtn-status-one}, but shows all workspaces
immediately under a root directory.
@item xmtn-propagate-one
Summarizes the status of several workspaces
Supervises propagating one workspace.
@item xmtn-propagate-multiple
Supervises propagating several workspaces
Supervises propagating several workspaces.
<<<<<<< TREE
=======
@item xmtn-sync-sync
Syncs a local database with a remote database, displays branches that
have been transferred.
Syncs the local database with a remote database, then runs
xmtn-sync-review.
@item xmtn-sync-review
Reviews saved output of an external @command{mtn automate sync},
Reviews saved output of a command-line @command{mtn automate sync},
displays branches that have been transferred. This is useful for syncs
<<<<<<< TREE
that take a long time, because external commands display the tickers
much better than DVC does.
The external sync should redirect stdout to @file{~/.dvc/sync.basic_io}.
>>>>>>> MERGE-SOURCE
=======
that take a long time, because the command-line displays progress
tickers.
>>>>>>> MERGE-SOURCE
@end table
@menu
* xmtn-status-one::
* xmtn-propagate-one::
<<<<<<< TREE
=======
* xmtn-sync-review::
>>>>>>> MERGE-SOURCE
@end menu
@node xmtn-status-one
@ -344,9 +361,13 @@ Perform the merge, using the conflict resolutions.
@item update
Update the workspace to the current head revision (must be merged).
@item review update
Open an @dfn{*xmtn-revlist*} buffer to review the revisions in the
most recent update.
@item update preview
Open an @dfn{*xmtn-revlist*} buffer to review the revisions that will
be included in the next update.
@item update review
Open an @dfn{*xmtn-revlist*} buffer to review the revisions that were
included in the most recent update.
@item ignore local changes
Don't show @dfn{commit}.
@ -374,10 +395,6 @@ propagation of all workspaces immediately under two root
directories. This is useful when several related projects branch
together.
Before displaying actions, each branch pair is examined to see if
propagate is necessary. If it is not, the workspace is not examined
for changes (since that can take a long time).
In the list of actions, ``from'' stands for the name of the source
branch, ``to'' the name of the destination branch.
@ -388,18 +405,18 @@ The possible actions are:
@item status ``from''
@itemx status ``to''
Start an @dfn{xmtn-multi-status} buffer for the specified workspace,
to allow commit, update followed by update review, or merge with
to allow commit, update preview, or merge with
conflict resolution.
@itemx update ``to''
Update the specified workspace to the current head revision (must be
merged). This bypasses the @dfn{xmtn-multi-status} buffer, and
therefore does not provide for update review. Useful when you don't
need to review the changes, which is the typical case for propagate.
therefore does not provide for update preview. It does allow for
update review.
@item ignore local changes ``from''
@item ignore local changes ``to''
Don't show @dfn{local changes unknown}; assume the workspace is
Don't show @dfn{need commit}; assume the workspace is
committed. Useful when you know that any local changes won't interfere
with the propagate.
@ -420,6 +437,80 @@ the workspace from the display.
@end table
<<<<<<< TREE
=======
@node xmtn-sync-review
@section xmtn-sync-review
@command{xmtn-sync-review} supervises the process of updating local
workspaces after a command line operation that synchronizes the local
and remote databases.
The command line operation should redirect stdout to
@file{~/.dvc/sync.basic_io}. Most users will want to define shell
functions to invoke common syncs. For example:
@example
mtn --db ~/monotone-dbs/gds.db automate sync --ticker=count "ssh:user@@host/gds.db?*" >> ~/.dvc/sync.basic_io
@end example
The @command{xmtn-sync-review} display shows each branch that was
transferred, with a count of how many revisions were sent and
received.
The user may set the variable @code{xmtn-sync-sort} to a function that
indicates how to order the branches in the display.
Actions on branches are invoked with @key{M-d}.
The possible branch actions are:
@table @command
@item status
Start an @dfn{xmtn-multi-status} buffer for the workspace assoicated
with the specified branch, to allow commit, update preview, update
followed by update review, or merge with conflict resolution.
The user may set the variable @code{xmtn-sync-guess-workspace} to a
function that returns a workspace given a branch. Otherwise, the user
is prompted for the workspace location; the location is cached for
future use.
@item update
Start an @dfn{xmtn-multi-status} buffer for the workspace assoicated
with the specified branch, then perform @command{update} (if
appropriate). This is often convenient when you know the workspace has
no local changes.
@itemx brief
Show the first line of the changelog for each revision received.
@itemx full
Show the complete changelog for each revision received.
@item clean
Delete the branch from the display.
Branches that are not cleaned are cached; they will reappear the next
time @code{xmtn-sync-review} is run.
@end table
In addition, there are global actions:
@table @command
@item next
Move to the next branch
@item prev
Move to the previous branch
@item save-quit
Save the displayed branches, quit.
@item save
Save the displayed branches.
@end table
>>>>>>> MERGE-SOURCE
@node Status Display
@chapter Status Display