update dvc
This commit is contained in:
parent
0c9e5fe4b8
commit
ec24bef5a4
@ -554,10 +554,11 @@ used to get more info about the process.")
|
||||
(defun dvc-build-dvc-command (dvc list-args)
|
||||
"Build a shell command to run DVC with args LIST-ARGS.
|
||||
DVC can be one of 'baz, 'xhg, ..."
|
||||
(let ((executable (executable-find (dvc-variable dvc "executable"))))
|
||||
(let* ((name (dvc-variable dvc "executable"))
|
||||
(executable (executable-find name)))
|
||||
;; 'executable-find' allows leading ~
|
||||
(if (not executable)
|
||||
(error "executable for %s not found" (symbol-name dvc)))
|
||||
(error "executable %s for %s not found" name (symbol-name dvc)))
|
||||
(mapconcat 'shell-quote-argument
|
||||
(cons executable
|
||||
(remq nil list-args))
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
;; is options, cdr is the command and arguments. Options are always
|
||||
;; specified as pairs of keyword and value, and without the leading
|
||||
;; "--". If an option has no value, use ""; see
|
||||
;; xmtn-automate-local-changes for an example.
|
||||
;; xmtn--status-inventory-sync in xmtn-dvc for an example.
|
||||
;;
|
||||
;; `xmtn-automate-new-command' returns a command handle. You use this
|
||||
;; handle to check the error code of the command and obtain its
|
||||
@ -74,6 +74,9 @@
|
||||
(require 'xmtn-run)
|
||||
(require 'xmtn-compat))
|
||||
|
||||
(defconst xmtn-automate-arguments (list "--rcfile" (locate-library "xmtn-hooks.lua"))
|
||||
"Arguments and options for 'mtn automate stdio' sessions.")
|
||||
|
||||
(defun xmtn-automate-command-buffer (command)
|
||||
(xmtn-automate--command-handle-buffer command))
|
||||
|
||||
@ -92,7 +95,10 @@
|
||||
(goto-char (point-max))
|
||||
(newline)
|
||||
(insert (format "command: %s" (xmtn-automate--command-handle-command handle)))
|
||||
(error "mtn error %s" (xmtn-automate--command-handle-error-code handle))))
|
||||
(error "mtn error %s" (xmtn-automate--command-handle-error-code handle)))
|
||||
(if (xmtn-automate--command-handle-warnings handle)
|
||||
(display-buffer (format dvc-error-buffer 'xmtn) t))
|
||||
)
|
||||
nil)
|
||||
|
||||
(defvar xmtn-automate--*sessions* '()
|
||||
@ -132,7 +138,7 @@ workspace root."
|
||||
(xmtn-automate-command-wait-until-finished command-handle)
|
||||
(xmtn-automate--command-output-as-string command-handle)))
|
||||
|
||||
(defun xmtn-automate-simple-command-output-insert-into-buffer
|
||||
(defun xmtn-automate-command-output-buffer
|
||||
(root buffer command)
|
||||
"Send COMMAND to session for ROOT, insert result into BUFFER."
|
||||
(let* ((session (xmtn-automate-cache-session root))
|
||||
@ -217,7 +223,8 @@ Signals an error if output contains zero lines or more than one line."
|
||||
(buffer)
|
||||
(write-marker)
|
||||
(finished-p nil)
|
||||
(error-code nil))
|
||||
(error-code nil)
|
||||
(warnings nil))
|
||||
|
||||
(defun* xmtn-automate--initialize-session (session &key root name)
|
||||
(xmtn--assert-optional (equal root (file-name-as-directory root)) t)
|
||||
@ -281,9 +288,11 @@ Signals an error if output contains zero lines or more than one line."
|
||||
"Kill session for ROOT."
|
||||
(interactive)
|
||||
(let ((temp (assoc (dvc-uniquify-file-name root) xmtn-automate--*sessions*)))
|
||||
(xmtn-automate--close-session (cdr temp))
|
||||
(setq xmtn-automate--*sessions*
|
||||
(delete temp xmtn-automate--*sessions* ))))
|
||||
;; session may have already been killed
|
||||
(when temp
|
||||
(xmtn-automate--close-session (cdr temp))
|
||||
(setq xmtn-automate--*sessions*
|
||||
(delete temp xmtn-automate--*sessions* )))))
|
||||
|
||||
(defun xmtn-kill-all-sessions ()
|
||||
"Kill all xmtn-automate sessions."
|
||||
@ -305,7 +314,7 @@ Signals an error if output contains zero lines or more than one line."
|
||||
(default-directory root))
|
||||
(let ((process
|
||||
(apply 'start-process name buffer xmtn-executable
|
||||
"automate" "stdio" xmtn-additional-arguments)))
|
||||
"automate" "stdio" xmtn-automate-arguments)))
|
||||
(ecase (process-status process)
|
||||
(run
|
||||
;; If the process started ok, it outputs the stdio
|
||||
@ -472,11 +481,14 @@ Return non-nil if some text copied."
|
||||
(?m
|
||||
(xmtn-automate--command-handle-buffer command))
|
||||
((?e ?w ?p ?t)
|
||||
(if (equal ?w (xmtn-automate--decoder-state-stream state))
|
||||
(setf (xmtn-automate--command-handle-warnings command) t))
|
||||
;; probably ought to do something else with p and t, but
|
||||
;; this is good enough for now.
|
||||
(get-buffer-create (format dvc-error-buffer 'xmtn)))))
|
||||
(write-marker
|
||||
(xmtn-automate--command-handle-write-marker command)))
|
||||
|
||||
(with-current-buffer session-buffer
|
||||
(let* ((end (min (+ (xmtn-automate--decoder-state-read-marker state)
|
||||
(xmtn-automate--decoder-state-remaining-chars state))
|
||||
@ -535,16 +547,19 @@ Return non-nil if some text copied."
|
||||
(if (= (xmtn-automate--decoder-state-read-marker state) write-marker)
|
||||
(setq tag 'exit-loop)
|
||||
(setq tag 'again)))
|
||||
|
||||
(again
|
||||
(cond
|
||||
((> (xmtn-automate--decoder-state-remaining-chars state) 0)
|
||||
;; copy more output from the current packet
|
||||
(if (xmtn-automate--process-new-output--copy session)
|
||||
(setq tag 'again)
|
||||
(setq tag 'check-for-more)))
|
||||
(if (= ?l (xmtn-automate--decoder-state-stream state))
|
||||
;; got the rest of the last packet; process in t branch next loop
|
||||
(setf (xmtn-automate--decoder-state-remaining-chars state) 0)
|
||||
(if (xmtn-automate--process-new-output--copy session)
|
||||
(setq tag 'again)
|
||||
(setq tag 'check-for-more))))
|
||||
|
||||
(t
|
||||
;; new packet
|
||||
;; new packet, or final packet
|
||||
(goto-char (xmtn-automate--decoder-state-read-marker state))
|
||||
;; A packet has the structure:
|
||||
;; <command number>:<stream>:<size>:<output>
|
||||
@ -555,46 +570,50 @@ Return non-nil if some text copied."
|
||||
;; p progress
|
||||
;; t ticker
|
||||
;; l last
|
||||
;;
|
||||
;; If size is large, we may not have all of the output in new-string
|
||||
(cond
|
||||
((looking-at "\\([0-9]+\\):\\([mewptl]\\):\\([0-9]+\\):")
|
||||
(let ((command-number (parse-integer (match-string 1)))
|
||||
(stream (aref (match-string 2) 0))
|
||||
(let ((stream (aref (match-string 2) 0))
|
||||
(size (parse-integer (match-string 3))))
|
||||
(setf (xmtn-automate--decoder-state-read-marker state) (match-end 0))
|
||||
(setf (xmtn-automate--decoder-state-stream state) stream)
|
||||
(setf (xmtn-automate--decoder-state-remaining-chars state) size)
|
||||
(setf (xmtn-automate--decoder-state-stream state) stream)
|
||||
(ecase stream
|
||||
((?m ?e ?w ?t ?p)
|
||||
(setf (xmtn-automate--decoder-state-remaining-chars state) size)
|
||||
(setf (xmtn-automate--decoder-state-read-marker state) (match-end 0))
|
||||
(setq tag 'again) )
|
||||
|
||||
(?l
|
||||
(setf (xmtn-automate--decoder-state-read-marker state) (+ size (match-end 0)))
|
||||
(setf (xmtn-automate--command-handle-error-code command)
|
||||
(parse-integer
|
||||
(buffer-substring-no-properties
|
||||
(match-end 0) (xmtn-automate--decoder-state-read-marker state)) ))
|
||||
(setf (xmtn-automate--command-handle-finished-p command) t)
|
||||
(with-no-warnings
|
||||
;; suppress compiler warning about discarding result
|
||||
(pop (xmtn-automate--session-remaining-command-handles session)))
|
||||
(if (xmtn-automate--session-closed-p session)
|
||||
(setq tag 'exit-loop)
|
||||
(setq tag 'check-for-more))
|
||||
(if (> (+ size (match-end 0)) (point-max))
|
||||
;; do not have the error code yet
|
||||
(setq tag 'exit-loop)
|
||||
(setf (xmtn-automate--decoder-state-read-marker state) (+ size (match-end 0)))
|
||||
(setf (xmtn-automate--command-handle-error-code command)
|
||||
(parse-integer
|
||||
(buffer-substring-no-properties
|
||||
(match-end 0) (xmtn-automate--decoder-state-read-marker state)) ))
|
||||
(setf (xmtn-automate--command-handle-finished-p command) t)
|
||||
(with-no-warnings
|
||||
;; suppress compiler warning about discarding result
|
||||
(pop (xmtn-automate--session-remaining-command-handles session)))
|
||||
(if (xmtn-automate--session-closed-p session)
|
||||
(setq tag 'exit-loop)
|
||||
(setq tag 'check-for-more)))
|
||||
)
|
||||
)))
|
||||
|
||||
(t
|
||||
;; Not a packet. Most likely we are at the end of the
|
||||
;; buffer, and there is more output coming soon. FIXME:
|
||||
;; this means the loop logic screwed up.
|
||||
(if (= (point) (point-max))
|
||||
;; Not a packet yet, or garbage in the stream from some
|
||||
;; Lua hook. Most likely we are at the end of the
|
||||
;; buffer, don't have a complete header, and there is
|
||||
;; more output coming soon. A packet header has at least
|
||||
;; 6 bytes; allowing 4 digits per integer takes that to
|
||||
;; 12.
|
||||
(if (> 12 (- (point-max) (point)))
|
||||
(setq tag 'exit-loop)
|
||||
(error "Unexpected output from mtn at '%s':%d:'%s'"
|
||||
(current-buffer)
|
||||
(point)
|
||||
(buffer-substring (point) (line-end-position)))))))))
|
||||
(buffer-substring (point) (min (point-max) (+ (point) 100))))
|
||||
))))))
|
||||
|
||||
(exit-loop (return))))))
|
||||
nil)
|
||||
@ -652,11 +671,13 @@ Each element of the list is a list; key, signature, name, value, trust."
|
||||
accu))
|
||||
|
||||
(defun xmtn--heads (root branch)
|
||||
;; apparently stdio automate doesn't default arguments properly;
|
||||
;; this fails if branch is not passed to mtn.
|
||||
(xmtn-automate-simple-command-output-lines root (list "heads"
|
||||
(or branch
|
||||
(xmtn--tree-default-branch root)))))
|
||||
(xmtn-automate-simple-command-output-lines
|
||||
root
|
||||
(cons
|
||||
(list "ignore-suspend-certs" "")
|
||||
(list "heads"
|
||||
(or branch
|
||||
(xmtn--tree-default-branch root))))))
|
||||
|
||||
(defun xmtn--tree-default-branch (root)
|
||||
(xmtn-automate-simple-command-output-line root `("get_option" "branch")))
|
||||
@ -677,24 +698,6 @@ Each element of the list is a list; key, signature, name, value, trust."
|
||||
(assert (null (funcall next-stanza)))
|
||||
result))))
|
||||
|
||||
|
||||
(defun xmtn-automate-local-changes (work)
|
||||
"Summary of status for WORK; 'ok if no changes, 'need-commit if changes."
|
||||
(let ((default-directory work)
|
||||
(msg "checking %s for local changes ..."))
|
||||
(message msg work)
|
||||
|
||||
(let ((result (xmtn-automate-simple-command-output-string
|
||||
default-directory
|
||||
(list (list "no-unchanged" "" "no-ignored" "")
|
||||
"inventory"))))
|
||||
|
||||
(message (concat msg " done") work)
|
||||
|
||||
(if (> (length result) 0)
|
||||
'need-commit
|
||||
'ok))))
|
||||
|
||||
(provide 'xmtn-automate)
|
||||
|
||||
;;; xmtn-automate.el ends here
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
;;; xmtn-base.el --- Basic definitions for accessing monotone
|
||||
|
||||
;; Copyright (C) 2009 Stephen Leake
|
||||
;; Copyright (C) 2009, 2010 Stephen Leake
|
||||
;; Copyright (C) 2006, 2007, 2009 Christian M. Ohler
|
||||
|
||||
;; Author: Christian M. Ohler
|
||||
@ -35,11 +35,7 @@
|
||||
(require 'cl))
|
||||
|
||||
(defvar xmtn-executable "mtn"
|
||||
"*The monotone executable command.
|
||||
|
||||
After changing the value of this variable, be sure to run
|
||||
`xmtn-check-command-version' to clear xmtn's command version
|
||||
cache.")
|
||||
"*The monotone executable command.")
|
||||
|
||||
(defvar xmtn-additional-arguments '()
|
||||
"*Additional arguments to pass to monotone.
|
||||
@ -59,15 +55,16 @@ A list of strings.")
|
||||
(save-match-data
|
||||
(string-match "\\`[0-9a-f]\\{40\\}\\'" thing))))
|
||||
|
||||
(defun xmtn--filter-non-dir (dir)
|
||||
"Return list of all directories in DIR, excluding '.', '..'."
|
||||
(defun xmtn--filter-non-ws (dir)
|
||||
"Return list of all mtn workspaces in DIR."
|
||||
(let ((default-directory dir)
|
||||
(subdirs (directory-files dir)))
|
||||
(setq subdirs
|
||||
(mapcar (lambda (filename)
|
||||
(if (and (file-directory-p filename)
|
||||
(not (string= "." filename))
|
||||
(not (string= ".." filename)))
|
||||
(not (string= ".." filename))
|
||||
(file-directory-p (concat filename "/_MTN")))
|
||||
filename))
|
||||
subdirs))
|
||||
(delq nil subdirs)))
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
;; Boston, MA 02110-1301 USA.
|
||||
|
||||
(eval-and-compile
|
||||
(eval-when-compile
|
||||
;; these have macros we use
|
||||
(require 'cl)
|
||||
(require 'dvc-utils)
|
||||
@ -29,7 +29,7 @@
|
||||
(require 'xmtn-ids)
|
||||
(require 'xmtn-run))
|
||||
|
||||
(eval-when-compile
|
||||
(eval-and-compile
|
||||
;; these have functions we use
|
||||
(require 'dired))
|
||||
|
||||
@ -103,8 +103,8 @@
|
||||
(defstruct (xmtn-conflicts-conflict
|
||||
(:copier nil))
|
||||
;; not worth splitting this into a type hierarchy; differences are
|
||||
;; minor some fields are nil for some conflict types
|
||||
;; single file conflicts only set left_resolution
|
||||
;; minor. Some fields are nil for some conflict types.
|
||||
;; Single file conflicts only set left_resolution
|
||||
|
||||
conflict_type ;; 'content | 'duplicate_name | 'orphaned_node
|
||||
ancestor_name
|
||||
@ -278,6 +278,16 @@ header."
|
||||
;; right_type "added directory"
|
||||
;; right_name "utils"
|
||||
;;
|
||||
;; conflict duplicate_name
|
||||
;; left_type "added file"
|
||||
;; left_name "build/x86_gnu_windows_release/gds_mms_test.gpr"
|
||||
;; left_file_id [8d5d8fd099442bfb5d636d6435c241c8cd83f4f9]
|
||||
;; right_type "renamed file"
|
||||
;; ancestor_name "build/x86_gnu_windows_release/gds_test.gpr"
|
||||
;; ancestor_file_id [e2eb7393d9cda23a467622744a392adde63fc850]
|
||||
;; right_name "build/x86_gnu_windows_release/gds_mms_test.gpr"
|
||||
;; right_file_id [cec70e80402418bb95dcdeb6abe1356084ff5ece]
|
||||
;;
|
||||
;; optional left and right resolutions:
|
||||
;; resolved_keep{_left | _right}
|
||||
;; resolved_drop{_left | _right}
|
||||
@ -286,24 +296,39 @@ header."
|
||||
(let ((conflict (make-xmtn-conflicts-conflict)))
|
||||
(setf (xmtn-conflicts-conflict-conflict_type conflict) 'duplicate_name)
|
||||
(xmtn-basic-io-check-line "left_type" (setf (xmtn-conflicts-conflict-left_type conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "left_name" (setf (xmtn-conflicts-conflict-left_name conflict) (cadar value)))
|
||||
(xmtn-basic-io-parse-line
|
||||
(cond
|
||||
((string= "left_file_id" symbol)
|
||||
(setf (xmtn-conflicts-conflict-left_file_id conflict) (cadar value))
|
||||
(xmtn-basic-io-check-line "right_type"
|
||||
(setf (xmtn-conflicts-conflict-right_type conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "right_name"
|
||||
(setf (xmtn-conflicts-conflict-right_name conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "right_file_id"
|
||||
(setf (xmtn-conflicts-conflict-right_file_id conflict) (cadar value))))
|
||||
(cond
|
||||
((string= "added file" (xmtn-conflicts-conflict-left_type conflict))
|
||||
(xmtn-basic-io-check-line "left_name" (setf (xmtn-conflicts-conflict-left_name conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "left_file_id" (setf (xmtn-conflicts-conflict-left_file_id conflict) (cadar value))))
|
||||
|
||||
((string= "right_type" symbol)
|
||||
(setf (xmtn-conflicts-conflict-right_type conflict) (cadar value))
|
||||
(xmtn-basic-io-check-line "right_name"
|
||||
(setf (xmtn-conflicts-conflict-right_name conflict) (cadar value))))
|
||||
(t
|
||||
(error "found %s" symbol))))
|
||||
((string= "added directory" (xmtn-conflicts-conflict-left_type conflict))
|
||||
(xmtn-basic-io-check-line "left_name" (setf (xmtn-conflicts-conflict-left_name conflict) (cadar value))))
|
||||
|
||||
((string= "renamed file" (xmtn-conflicts-conflict-left_type conflict))
|
||||
(xmtn-basic-io-check-line "ancestor_name" (setf (xmtn-conflicts-conflict-ancestor_name conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "ancestor_file_id" (setf (xmtn-conflicts-conflict-ancestor_file_id conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "left_name" (setf (xmtn-conflicts-conflict-left_name conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "left_file_id" (setf (xmtn-conflicts-conflict-left_file_id conflict) (cadar value))))
|
||||
|
||||
(t
|
||||
(error "unsupported left_type %s" (xmtn-conflicts-conflict-left_type conflict))))
|
||||
|
||||
(xmtn-basic-io-check-line "right_type" (setf (xmtn-conflicts-conflict-right_type conflict) (cadar value)))
|
||||
(cond
|
||||
((string= "added file" (xmtn-conflicts-conflict-right_type conflict))
|
||||
(xmtn-basic-io-check-line "right_name" (setf (xmtn-conflicts-conflict-right_name conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "right_file_id" (setf (xmtn-conflicts-conflict-right_file_id conflict) (cadar value))))
|
||||
|
||||
((string= "added directory" (xmtn-conflicts-conflict-right_type conflict))
|
||||
(xmtn-basic-io-check-line "right_name" (setf (xmtn-conflicts-conflict-right_name conflict) (cadar value))))
|
||||
|
||||
((string= "renamed file" (xmtn-conflicts-conflict-right_type conflict))
|
||||
(xmtn-basic-io-check-line "ancestor_name" (setf (xmtn-conflicts-conflict-ancestor_name conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "ancestor_file_id" (setf (xmtn-conflicts-conflict-ancestor_file_id conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "right_name" (setf (xmtn-conflicts-conflict-right_name conflict) (cadar value)))
|
||||
(xmtn-basic-io-check-line "right_file_id" (setf (xmtn-conflicts-conflict-right_file_id conflict) (cadar value))))
|
||||
(t
|
||||
(error "unsupported right_type %s" (xmtn-conflicts-conflict-right_type conflict))))
|
||||
|
||||
;; look for a left resolution
|
||||
(case (xmtn-basic-io--peek)
|
||||
@ -531,13 +556,38 @@ header."
|
||||
(insert ?\n)
|
||||
(xmtn-basic-io-write-sym "conflict" "duplicate_name")
|
||||
(xmtn-basic-io-write-str "left_type" (xmtn-conflicts-conflict-left_type conflict))
|
||||
(xmtn-basic-io-write-str "left_name" (xmtn-conflicts-conflict-left_name conflict))
|
||||
(if (xmtn-conflicts-conflict-left_file_id conflict)
|
||||
(xmtn-basic-io-write-id "left_file_id" (xmtn-conflicts-conflict-left_file_id conflict)))
|
||||
(cond
|
||||
((string= "added file" (xmtn-conflicts-conflict-left_type conflict))
|
||||
(xmtn-basic-io-write-str "left_name" (xmtn-conflicts-conflict-left_name conflict))
|
||||
(xmtn-basic-io-write-id "left_file_id" (xmtn-conflicts-conflict-left_file_id conflict)))
|
||||
|
||||
((string= "added directory" (xmtn-conflicts-conflict-left_type conflict))
|
||||
(xmtn-basic-io-write-str "left_name" (xmtn-conflicts-conflict-left_name conflict)))
|
||||
|
||||
((string= "renamed file" (xmtn-conflicts-conflict-left_type conflict))
|
||||
(xmtn-basic-io-write-str "ancestor_name" (xmtn-conflicts-conflict-ancestor_name conflict))
|
||||
(xmtn-basic-io-write-id "ancestor_file_id" (xmtn-conflicts-conflict-ancestor_file_id conflict))
|
||||
(xmtn-basic-io-write-str "left_name" (xmtn-conflicts-conflict-left_name conflict))
|
||||
(xmtn-basic-io-write-id "left_file_id" (xmtn-conflicts-conflict-left_file_id conflict)))
|
||||
(t
|
||||
(error "unsupported left_type %s" (xmtn-conflicts-conflict-left_type conflict))))
|
||||
|
||||
(xmtn-basic-io-write-str "right_type" (xmtn-conflicts-conflict-right_type conflict))
|
||||
(xmtn-basic-io-write-str "right_name" (xmtn-conflicts-conflict-right_name conflict))
|
||||
(if (xmtn-conflicts-conflict-right_file_id conflict)
|
||||
(xmtn-basic-io-write-id "right_file_id" (xmtn-conflicts-conflict-right_file_id conflict)))
|
||||
(cond
|
||||
((string= "added file" (xmtn-conflicts-conflict-right_type conflict))
|
||||
(xmtn-basic-io-write-str "right_name" (xmtn-conflicts-conflict-right_name conflict))
|
||||
(xmtn-basic-io-write-id "right_file_id" (xmtn-conflicts-conflict-right_file_id conflict)))
|
||||
|
||||
((string= "added directory" (xmtn-conflicts-conflict-right_type conflict))
|
||||
(xmtn-basic-io-write-str "right_name" (xmtn-conflicts-conflict-right_name conflict)))
|
||||
|
||||
((string= "renamed file" (xmtn-conflicts-conflict-right_type conflict))
|
||||
(xmtn-basic-io-write-str "ancestor_name" (xmtn-conflicts-conflict-ancestor_name conflict))
|
||||
(xmtn-basic-io-write-id "ancestor_file_id" (xmtn-conflicts-conflict-ancestor_file_id conflict))
|
||||
(xmtn-basic-io-write-str "right_name" (xmtn-conflicts-conflict-right_name conflict))
|
||||
(xmtn-basic-io-write-id "right_file_id" (xmtn-conflicts-conflict-right_file_id conflict)))
|
||||
(t
|
||||
(error "unsupported right_type %s" (xmtn-conflicts-conflict-right_type conflict))))
|
||||
|
||||
(if (xmtn-conflicts-conflict-left_resolution conflict)
|
||||
(ecase (car (xmtn-conflicts-conflict-left_resolution conflict))
|
||||
@ -987,6 +1037,17 @@ header."
|
||||
;; if no file_id, it's a directory; can't drop if not empty
|
||||
(xmtn-conflicts-conflict-right_file_id conflict))))
|
||||
|
||||
(defun xmtn-conflicts-left-label ()
|
||||
"Return 'left: ' or '' as appropriate for current conflict."
|
||||
(let* ((conflict (ewoc-data (ewoc-locate xmtn-conflicts-ewoc)))
|
||||
(type (xmtn-conflicts-conflict-conflict_type conflict)))
|
||||
|
||||
;; duplicate_name is the only conflict type that needs a right
|
||||
;; resolution, and thus a 'left' label
|
||||
(if (equal type 'duplicate_name)
|
||||
"left: "
|
||||
"")))
|
||||
|
||||
(defvar xmtn-conflicts-resolve-map
|
||||
(let ((map (make-sparse-keymap "resolution")))
|
||||
(define-key map [?c] '(menu-item "c) clear resolution"
|
||||
@ -995,55 +1056,55 @@ header."
|
||||
;; Don't need 'left' or 'right' in menu, since only one is
|
||||
;; visible; then this works better for single file conflicts.
|
||||
|
||||
(define-key map [?b] '(menu-item "b) drop"
|
||||
(define-key map [?b] '(menu-item "b) right: drop"
|
||||
xmtn-conflicts-resolve-drop_right
|
||||
:visible (xmtn-conflicts-resolve-drop_rightp)))
|
||||
(define-key map [?a] '(menu-item "a) rename"
|
||||
(define-key map [?a] '(menu-item "a) right: rename"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-rename 'right))
|
||||
:visible (xmtn-conflicts-resolve-rename_rightp)))
|
||||
(define-key map [?9] '(menu-item "9) right file"
|
||||
(define-key map [?9] '(menu-item "9) right: right file"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-user 'right 'right))
|
||||
:visible (xmtn-conflicts-resolve-user_rightp)))
|
||||
(define-key map [?8] '(menu-item "8) left file"
|
||||
(define-key map [?8] '(menu-item "8) right: left file"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-user 'right 'left))
|
||||
:visible (xmtn-conflicts-resolve-user_rightp)))
|
||||
(define-key map [?7] '(menu-item "7) keep"
|
||||
(define-key map [?7] '(menu-item "7) right: keep"
|
||||
xmtn-conflicts-resolve-keep_right
|
||||
:visible (xmtn-conflicts-resolve-keep_rightp)))
|
||||
(define-key map [?6] '(menu-item "6) ediff"
|
||||
(define-key map [?6] '(menu-item "6) right: ediff"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-ediff 'right))
|
||||
:visible (xmtn-conflicts-resolve-user_rightp)))
|
||||
|
||||
(define-key map [?5] '(menu-item "5) right file"
|
||||
(define-key map [?5] '(menu-item (concat "5) " (xmtn-conflicts-left-label) "right file")
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-user 'left 'right))
|
||||
:visible (xmtn-conflicts-resolve-user_leftp)))
|
||||
(define-key map [?4] '(menu-item "4) left file"
|
||||
(define-key map [?4] '(menu-item (concat "4) " (xmtn-conflicts-left-label) "left file")
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-user 'left 'left))
|
||||
:visible (xmtn-conflicts-resolve-user_leftp)))
|
||||
(define-key map [?3] '(menu-item "3) drop"
|
||||
(define-key map [?3] '(menu-item (concat "3) " (xmtn-conflicts-left-label) "drop")
|
||||
xmtn-conflicts-resolve-drop_left
|
||||
:visible (xmtn-conflicts-resolve-drop_leftp)))
|
||||
(define-key map [?2] '(menu-item "2) rename"
|
||||
(define-key map [?2] '(menu-item (concat "2) " (xmtn-conflicts-left-label) "rename")
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-rename 'left))
|
||||
:visible (xmtn-conflicts-resolve-rename_leftp)))
|
||||
(define-key map [?1] '(menu-item "1) keep"
|
||||
(define-key map [?1] '(menu-item (concat "1) " (xmtn-conflicts-left-label) "keep")
|
||||
xmtn-conflicts-resolve-keep_left
|
||||
:visible (xmtn-conflicts-resolve-keep_leftp)))
|
||||
(define-key map [?0] '(menu-item "0) ediff"
|
||||
(define-key map [?0] '(menu-item (concat "0) " (xmtn-conflicts-left-label) "ediff")
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-ediff 'left))
|
||||
@ -1147,10 +1208,6 @@ non-nil, show log-edit buffer in other frame."
|
||||
;; Arrange for `revert-buffer' to do the right thing
|
||||
(set (make-local-variable 'after-insert-file-functions) '(xmtn-conflicts-after-insert-file))
|
||||
|
||||
;; don't do normal clean up stuff
|
||||
(set (make-local-variable 'before-save-hook) nil)
|
||||
(set (make-local-variable 'write-file-functions) nil)
|
||||
|
||||
(dvc-install-buffer-menu)
|
||||
(setq buffer-read-only t)
|
||||
(buffer-disable-undo)
|
||||
|
||||
@ -583,12 +583,10 @@ otherwise newer."
|
||||
|
||||
|
||||
(rename-source
|
||||
(setq more-status
|
||||
(concat "to " new-path)))
|
||||
(setq more-status new-path))
|
||||
|
||||
(rename-target
|
||||
(setq more-status
|
||||
(concat "from " old-path)))
|
||||
(setq more-status old-path))
|
||||
|
||||
(modified
|
||||
(if (and (equal status '(known))
|
||||
@ -724,13 +722,7 @@ otherwise newer."
|
||||
(dvc-save-some-buffers root)
|
||||
(lexical-let* ((status-buffer status-buffer))
|
||||
(xmtn--run-command-async
|
||||
root `("automate" "inventory"
|
||||
,@(and (xmtn--have-no-ignore)
|
||||
(not dvc-status-display-known)
|
||||
'("--no-unchanged"))
|
||||
,@(and (xmtn--have-no-ignore)
|
||||
(not dvc-status-display-ignored)
|
||||
'("--no-ignored")))
|
||||
root (list "automate" "inventory" "--no-unchanged" "--no-ignored")
|
||||
:finished (lambda (output error status arguments)
|
||||
(dvc-status-inventory-done status-buffer)
|
||||
(with-current-buffer status-buffer
|
||||
@ -769,6 +761,75 @@ otherwise newer."
|
||||
arguments)
|
||||
(current-buffer) error)))))))
|
||||
|
||||
(defun xmtn--status-inventory-sync (root)
|
||||
"Create a status buffer for ROOT; return (buffer status), where status is 'ok or 'need-commit."
|
||||
(let*
|
||||
((orig-buffer (current-buffer))
|
||||
(msg (concat "running inventory for " root " ..."))
|
||||
(base-revision (xmtn--get-base-revision-hash-id-or-null root))
|
||||
(branch (xmtn--tree-default-branch root))
|
||||
(head-revisions (xmtn--heads root branch))
|
||||
(head-count (length head-revisions))
|
||||
(output-buffer (generate-new-buffer " *xmtn-inventory*"))
|
||||
status
|
||||
(dvc-switch-to-buffer-first nil)
|
||||
(status-buffer
|
||||
(dvc-status-prepare-buffer
|
||||
'xmtn
|
||||
root
|
||||
;; base-revision
|
||||
(if base-revision (format "%s" base-revision) "none")
|
||||
;; branch
|
||||
(format "%s" branch)
|
||||
;; header-more
|
||||
(lambda ()
|
||||
(concat
|
||||
(case head-count
|
||||
(0 " branch is empty\n")
|
||||
(1 " branch is merged\n")
|
||||
(t (dvc-face-add (format " branch has %s heads; need merge\n" head-count) 'dvc-conflict)))
|
||||
(if (member base-revision head-revisions)
|
||||
" base revision is a head revision\n"
|
||||
(dvc-face-add " base revision is not a head revision; need update\n" 'dvc-conflict))))
|
||||
;; refresh
|
||||
'xmtn-dvc-status)))
|
||||
(dvc-save-some-buffers root)
|
||||
(message msg)
|
||||
(xmtn-automate-command-output-buffer
|
||||
root output-buffer
|
||||
(list (list "no-unchanged" "" "no-ignored" "")
|
||||
"inventory"))
|
||||
(with-current-buffer output-buffer
|
||||
(setq status
|
||||
(if (> (point-max) (point-min))
|
||||
'need-commit
|
||||
'ok)))
|
||||
(dvc-status-inventory-done status-buffer)
|
||||
(with-current-buffer status-buffer
|
||||
(let ((excluded-files (dvc-default-excluded-files)))
|
||||
(xmtn-basic-io-with-stanza-parser
|
||||
(parser output-buffer)
|
||||
(xmtn--parse-inventory
|
||||
parser
|
||||
(lambda (path status changes old-path new-path
|
||||
old-type new-type fs-type)
|
||||
(xmtn--status-process-entry dvc-fileinfo-ewoc
|
||||
path status
|
||||
changes
|
||||
old-path new-path
|
||||
old-type new-type
|
||||
fs-type
|
||||
excluded-files))))
|
||||
(when (not (ewoc-locate dvc-fileinfo-ewoc))
|
||||
(ewoc-enter-last dvc-fileinfo-ewoc
|
||||
(make-dvc-fileinfo-message
|
||||
:text (concat " no changes in workspace")))
|
||||
(ewoc-refresh dvc-fileinfo-ewoc))))
|
||||
(kill-buffer output-buffer)
|
||||
(set-buffer orig-buffer)
|
||||
(message (concat msg " done"))
|
||||
(list status-buffer status)))
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-dvc-status ()
|
||||
"Display status of monotone tree at `default-directory'."
|
||||
@ -876,19 +937,8 @@ otherwise newer."
|
||||
(let ((default-directory root))
|
||||
(mapcan (lambda (file-name)
|
||||
(if (or (file-symlink-p file-name)
|
||||
(xmtn--have-no-ignore)
|
||||
(not (file-directory-p file-name)))
|
||||
(list (xmtn--perl-regexp-for-file-name file-name))
|
||||
|
||||
;; If mtn automate inventory doesn't support
|
||||
;; --no-ignore, it also recurses into unknown
|
||||
;; directories, so we need to ignore files in
|
||||
;; this directory as well as the directory
|
||||
;; itself.
|
||||
(setq file-name (directory-file-name file-name))
|
||||
(list
|
||||
(xmtn--perl-regexp-for-file-name file-name)
|
||||
(xmtn--perl-regexp-for-files-in-directory file-name))))
|
||||
(list (xmtn--perl-regexp-for-file-name file-name))))
|
||||
normalized-file-names))
|
||||
t))))
|
||||
|
||||
@ -1117,6 +1167,8 @@ finished."
|
||||
(progn
|
||||
"--resolve-conflicts-file=_MTN/conflicts")))
|
||||
(cmd (list "propagate" other local-branch resolve-conflicts
|
||||
;; may be resurrecting a suspended branch; doesn't hurt otherwise.
|
||||
"--ignore-suspend-certs"
|
||||
(xmtn-dvc-log-message)))
|
||||
(prompt
|
||||
(if resolve-conflicts
|
||||
@ -1431,18 +1483,24 @@ finished."
|
||||
|
||||
(defun xmtn--insert-file-contents (root content-hash-id buffer)
|
||||
(check-type content-hash-id xmtn--hash-id)
|
||||
(xmtn-automate-simple-command-output-insert-into-buffer
|
||||
(xmtn-automate-command-output-buffer
|
||||
root buffer `("get_file" ,content-hash-id)))
|
||||
|
||||
(defun xmtn--insert-file-contents-by-name (root backend-id normalized-file-name buffer)
|
||||
(let* ((resolved-id (xmtn--resolve-backend-id root backend-id))
|
||||
(hash-id (case (car resolved-id)
|
||||
(local-tree nil)
|
||||
(revision (cadr resolved-id))))
|
||||
(cmd (if hash-id
|
||||
(revision (cadr resolved-id)))))
|
||||
(case (car backend-id)
|
||||
((local-tree last-revision)
|
||||
;; file may have been renamed but not committed
|
||||
(setq normalized-file-name (xmtn--get-rename-in-workspace-to root normalized-file-name)))
|
||||
(t nil))
|
||||
|
||||
(let ((cmd (if hash-id
|
||||
(cons (list "revision" hash-id) (list "get_file_of" normalized-file-name))
|
||||
(list "get_file_of" normalized-file-name))))
|
||||
(xmtn-automate-simple-command-output-insert-into-buffer root buffer cmd)))
|
||||
(xmtn-automate-command-output-buffer root buffer cmd))))
|
||||
|
||||
(defun xmtn--same-tree-p (a b)
|
||||
(equal (file-truename a) (file-truename b)))
|
||||
|
||||
40
dvc/lisp/xmtn-hooks.lua
Normal file
40
dvc/lisp/xmtn-hooks.lua
Normal file
@ -0,0 +1,40 @@
|
||||
-- xmtn-hooks.lua --- mtn Lua hook functions used in all xmtn automate
|
||||
-- stdio sessions
|
||||
--
|
||||
-- Copyright (C) 2010 Stephen Leake
|
||||
--
|
||||
-- Author: Stephen Leake
|
||||
-- Keywords: tools
|
||||
--
|
||||
-- This file is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This file is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this file; see the file COPYING. If not, write to
|
||||
-- the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
-- Boston, MA 02110-1301 USA.
|
||||
|
||||
function get_mtn_command(host)
|
||||
-- Return a mtn command line for the remote host.
|
||||
--
|
||||
-- If the remote host is a Windows machine (ie file: on a Windows
|
||||
-- machine), we need the Cygwin mtn executable, since the Win32
|
||||
-- executable does not support file: or ssh:.
|
||||
--
|
||||
-- But we have no way to tell what the remote machine is. So we let
|
||||
-- the lisp code figure that out from user options, and it provides
|
||||
-- the mtn command to this hook by defining the XMTN_SYNC_MTN
|
||||
-- environment variable.
|
||||
|
||||
return os.getenv("XMTN_SYNC_MTN");
|
||||
end
|
||||
|
||||
|
||||
-- end of file
|
||||
@ -20,34 +20,38 @@
|
||||
;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
;; Boston, MA 02110-1301 USA.
|
||||
|
||||
(eval-and-compile
|
||||
(eval-when-compile
|
||||
;; these have macros we use
|
||||
(require 'xmtn-ids))
|
||||
|
||||
(eval-when-compile
|
||||
(eval-and-compile
|
||||
;; these have functions we use
|
||||
(require 'xmtn-base)
|
||||
(require 'xmtn-conflicts))
|
||||
(require 'xmtn-conflicts)
|
||||
(require 'xmtn-revlist))
|
||||
|
||||
(defvar xmtn-status-root ""
|
||||
"Buffer-local variable holding root directory.")
|
||||
"Buffer-local variable holding multi-workspace root directory.")
|
||||
(make-variable-buffer-local 'xmtn-status-root)
|
||||
(put 'xmtn-status-root 'permanent-local t)
|
||||
|
||||
(defvar xmtn-status-ewoc nil
|
||||
"Buffer-local ewoc for displaying propagations.
|
||||
"Buffer-local ewoc for displaying multi-workspace status.
|
||||
All xmtn-status functions operate on this ewoc.
|
||||
The elements must all be of class xmtn-status-data.")
|
||||
(make-variable-buffer-local 'xmtn-status-ewoc)
|
||||
(put 'xmtn-status-ewoc 'permanent-local t)
|
||||
|
||||
(defstruct (xmtn-status-data (:copier nil))
|
||||
work ; directory name relative to xmtn-status-root
|
||||
branch ; branch name (assumed never changes)
|
||||
work ; workspace directory name relative to xmtn-status-root
|
||||
branch ; 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
|
||||
conflicts-buffer ; *xmtn-conflicts* buffer for merge
|
||||
heads ; 'need-scan | 'at-head | 'need-update | 'need-merge)
|
||||
status-buffer ; *xmtn-status* buffer for commit
|
||||
heads ; 'need-scan | 'at-head | 'need-update | 'need-merge
|
||||
(update-review
|
||||
'pending) ; 'pending | 'need-review | 'done
|
||||
(local-changes
|
||||
'need-scan) ; 'need-scan | 'need-commit | 'ok
|
||||
(conflicts
|
||||
@ -75,13 +79,13 @@ 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 " from local changes unknown\n"))
|
||||
(need-commit (insert (dvc-face-add " need dvc-status\n" 'dvc-header)))
|
||||
(need-scan (insert " local changes unknown\n"))
|
||||
(need-commit (insert (dvc-face-add " need commit\n" 'dvc-header)))
|
||||
(ok nil))
|
||||
|
||||
(ecase (xmtn-status-data-conflicts data)
|
||||
(need-scan
|
||||
(insert "conflicts need scan\n"))
|
||||
(insert " conflicts need scan\n"))
|
||||
(need-resolve
|
||||
(insert (dvc-face-add " need resolve conflicts\n" 'dvc-conflict)))
|
||||
(need-review-resolve-internal
|
||||
@ -92,10 +96,16 @@ The elements must all be of class xmtn-status-data.")
|
||||
|
||||
(ecase (xmtn-status-data-heads data)
|
||||
(at-head nil)
|
||||
(need-update (insert (dvc-face-add " need update\n" 'dvc-conflict)))
|
||||
(need-update
|
||||
(insert (dvc-face-add " need update\n" 'dvc-conflict)))
|
||||
(need-merge
|
||||
(insert (dvc-face-add " need merge\n" 'dvc-conflict)))
|
||||
)))
|
||||
(insert (dvc-face-add " need merge\n" 'dvc-conflict))))
|
||||
|
||||
(ecase (xmtn-status-data-update-review data)
|
||||
(pending nil)
|
||||
(need-review (insert " need update review\n"))
|
||||
(done nil))
|
||||
))
|
||||
|
||||
(defun xmtn-status-kill-conflicts-buffer (data)
|
||||
(if (buffer-live-p (xmtn-status-data-conflicts-buffer data))
|
||||
@ -103,6 +113,10 @@ The elements must all be of class xmtn-status-data.")
|
||||
(with-current-buffer buffer (save-buffer))
|
||||
(kill-buffer buffer))))
|
||||
|
||||
(defun xmtn-status-kill-status-buffer (data)
|
||||
(if (buffer-live-p (xmtn-status-data-status-buffer data))
|
||||
(kill-buffer (xmtn-status-data-status-buffer data))))
|
||||
|
||||
(defun xmtn-status-save-conflicts-buffer (data)
|
||||
(if (buffer-live-p (xmtn-status-data-conflicts-buffer data))
|
||||
(with-current-buffer (xmtn-status-data-conflicts-buffer data) (save-buffer))))
|
||||
@ -111,6 +125,7 @@ The elements must all be of class xmtn-status-data.")
|
||||
"Clean DATA workspace."
|
||||
(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)))
|
||||
|
||||
(defun xmtn-status-clean ()
|
||||
@ -158,6 +173,7 @@ The elements must all be of class xmtn-status-data.")
|
||||
(let* ((elem (ewoc-locate xmtn-status-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-status-need-refresh elem data)
|
||||
(setf (xmtn-status-data-update-review data) 'need-review)
|
||||
(let ((default-directory (xmtn-status-work data)))
|
||||
(xmtn-dvc-update))
|
||||
(xmtn-status-refresh-one data nil)
|
||||
@ -186,13 +202,13 @@ The elements must all be of class xmtn-status-data.")
|
||||
'(need-resolve need-review-resolve-internal)))))
|
||||
|
||||
(defun xmtn-status-status ()
|
||||
"Run xmtn-status on current workspace."
|
||||
"Show status buffer for current workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-status-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-status-need-refresh elem data)
|
||||
(setf (xmtn-status-data-local-changes data) 'ok)
|
||||
(xmtn-status (xmtn-status-work data))
|
||||
(pop-to-buffer (xmtn-status-data-status-buffer data))
|
||||
;; IMPROVEME: create a log-edit buffer now, since we have both a
|
||||
;; status and conflict buffer, and that confuses dvc-log-edit
|
||||
))
|
||||
@ -203,11 +219,6 @@ The elements must all be of class xmtn-status-data.")
|
||||
(let* ((elem (ewoc-locate xmtn-status-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(setf (xmtn-status-data-local-changes data) 'ok)
|
||||
|
||||
(if (buffer-live-p (xmtn-status-data-conflicts-buffer data))
|
||||
;; creating the log-edit buffer requires a single status/diff/conflicts buffer
|
||||
(kill-buffer (xmtn-status-data-conflicts-buffer data)))
|
||||
|
||||
(ewoc-invalidate xmtn-status-ewoc elem)))
|
||||
|
||||
(defun xmtn-status-statusp ()
|
||||
@ -217,22 +228,23 @@ The elements must all be of class xmtn-status-data.")
|
||||
(member (xmtn-status-data-local-changes data)
|
||||
'(need-scan need-commit)))))
|
||||
|
||||
(defun xmtn-status-missing ()
|
||||
"Run xmtn-missing on current workspace."
|
||||
(defun xmtn-status-review-update ()
|
||||
"Review last update for current workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-status-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-status-need-refresh elem data)
|
||||
(xmtn-missing nil (xmtn-status-work data))))
|
||||
(setf (xmtn-status-data-update-review data) 'done)
|
||||
(xmtn-review-update (xmtn-status-work data))))
|
||||
|
||||
(defun xmtn-status-missingp ()
|
||||
"Non-nil if xmtn-missing is appropriate for current workspace."
|
||||
(defun xmtn-status-review-updatep ()
|
||||
"Non-nil if xmtn-status-review-update is appropriate for current workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-status-ewoc))))
|
||||
(and (not (xmtn-status-data-need-refresh data))
|
||||
(eq 'need-update (xmtn-status-data-heads data)))))
|
||||
(eq 'need-review (xmtn-status-data-update-review data)))))
|
||||
|
||||
(defun xmtn-status-merge ()
|
||||
"Run dvc-merge on current workspace."
|
||||
"Run merge on current workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-status-ewoc))
|
||||
(data (ewoc-data elem))
|
||||
@ -243,7 +255,7 @@ The elements must all be of class xmtn-status-data.")
|
||||
(ewoc-invalidate xmtn-status-ewoc elem)))
|
||||
|
||||
(defun xmtn-status-heads ()
|
||||
"Run xmtn-heads on current workspace."
|
||||
"Show heads for current workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-status-ewoc))
|
||||
(data (ewoc-data elem))
|
||||
@ -268,22 +280,22 @@ 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) update"
|
||||
(define-key map [?5] '(menu-item "5) review update"
|
||||
xmtn-status-review-update
|
||||
:visible (xmtn-status-review-updatep)))
|
||||
(define-key map [?4] '(menu-item "4) update"
|
||||
xmtn-status-update
|
||||
:visible (xmtn-status-updatep)))
|
||||
(define-key map [?4] '(menu-item "4) merge"
|
||||
(define-key map [?3] '(menu-item "3) merge"
|
||||
xmtn-status-merge
|
||||
:visible (xmtn-status-headsp)))
|
||||
(define-key map [?3] '(menu-item "3) show heads"
|
||||
(define-key map [?2] '(menu-item "2) show heads"
|
||||
xmtn-status-heads
|
||||
:visible (xmtn-status-headsp)))
|
||||
(define-key map [?2] '(menu-item "2) resolve conflicts"
|
||||
(define-key map [?1] '(menu-item "1) resolve conflicts"
|
||||
xmtn-status-resolve-conflicts
|
||||
:visible (xmtn-status-resolve-conflictsp)))
|
||||
(define-key map [?1] '(menu-item "1) show missing"
|
||||
xmtn-status-missing
|
||||
:visible (xmtn-status-missingp)))
|
||||
(define-key map [?0] '(menu-item "0) status"
|
||||
(define-key map [?0] '(menu-item "0) commit"
|
||||
xmtn-status-status
|
||||
:visible (xmtn-status-statusp)))
|
||||
map)
|
||||
@ -319,8 +331,6 @@ The elements must all be of class xmtn-status-data.")
|
||||
|
||||
(defun xmtn-status-conflicts (data)
|
||||
"Return value for xmtn-status-data-conflicts for DATA."
|
||||
;; Can't check for "current heads", since there could be more than
|
||||
;; 2, so just recreate conflicts
|
||||
(let* ((work (xmtn-status-work data))
|
||||
(default-directory work))
|
||||
|
||||
@ -379,11 +389,24 @@ The elements must all be of class xmtn-status-data.")
|
||||
(message "")
|
||||
|
||||
(if refresh-local-changes
|
||||
(setf (xmtn-status-data-local-changes data) 'need-scan))
|
||||
(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))))
|
||||
|
||||
(case (xmtn-status-data-local-changes data)
|
||||
(need-scan
|
||||
(setf (xmtn-status-data-local-changes data) (xmtn-automate-local-changes work)))
|
||||
(if (buffer-live-p (xmtn-status-data-status-buffer data))
|
||||
(with-current-buffer (xmtn-status-data-status-buffer data)
|
||||
(xmtn-dvc-status)
|
||||
(setf (xmtn-status-data-local-changes data)
|
||||
(if (not (ewoc-locate dvc-fileinfo-ewoc))
|
||||
'ok
|
||||
'need-commit)))
|
||||
(let ((result (xmtn--status-inventory-sync (xmtn-status-work data))))
|
||||
(setf (xmtn-status-data-status-buffer data) (car result)
|
||||
(xmtn-status-data-local-changes data) (cadr result))) ))
|
||||
(t nil))
|
||||
|
||||
(case (xmtn-status-data-conflicts data)
|
||||
@ -398,7 +421,7 @@ The elements must all be of class xmtn-status-data.")
|
||||
t)
|
||||
|
||||
(defun xmtn-status-refresh ()
|
||||
"Refresh status of each ewoc element. With prefix arg, reset local changes status to `unknown'."
|
||||
"Refresh status of each ewoc element. With prefix arg, re-scan for local changes."
|
||||
(interactive)
|
||||
(ewoc-map 'xmtn-status-refresh-one xmtn-status-ewoc current-prefix-arg)
|
||||
(message "done"))
|
||||
@ -407,9 +430,9 @@ The elements must all be of class xmtn-status-data.")
|
||||
(defun xmtn-update-multiple (dir &optional workspaces)
|
||||
"Update all projects under DIR."
|
||||
(interactive "DUpdate all in (root directory): ")
|
||||
(let ((root (file-name-as-directory (substitute-in-file-name dir))))
|
||||
(let ((root (file-name-as-directory (expand-file-name (substitute-in-file-name dir)))))
|
||||
|
||||
(if (not workspaces) (setq workspaces (xmtn--filter-non-dir root)))
|
||||
(if (not workspaces) (setq workspaces (xmtn--filter-non-ws root)))
|
||||
|
||||
(dolist (workspace workspaces)
|
||||
(let ((default-directory (concat root workspace)))
|
||||
@ -421,8 +444,8 @@ The elements must all be of class xmtn-status-data.")
|
||||
"Show actions to update all projects under DIR."
|
||||
(interactive "DStatus for all (root directory): \ni\nP")
|
||||
(pop-to-buffer (get-buffer-create "*xmtn-multi-status*"))
|
||||
(setq default-directory (file-name-as-directory (substitute-in-file-name dir)))
|
||||
(if (not workspaces) (setq workspaces (xmtn--filter-non-dir default-directory)))
|
||||
(setq default-directory (file-name-as-directory (expand-file-name (substitute-in-file-name dir))))
|
||||
(if (not workspaces) (setq workspaces (xmtn--filter-non-ws default-directory)))
|
||||
(setq xmtn-status-root (file-name-as-directory default-directory))
|
||||
(setq xmtn-status-ewoc (ewoc-create 'xmtn-status-printer))
|
||||
(let ((inhibit-read-only t)) (delete-region (point-min) (point-max)))
|
||||
@ -461,6 +484,29 @@ The elements must all be of class xmtn-status-data.")
|
||||
(xmtn-status-refresh)
|
||||
(xmtn-status-next))
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-status-one-1 (root name head-rev 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))
|
||||
(setq xmtn-status-root root)
|
||||
(setq xmtn-status-ewoc (ewoc-create 'xmtn-status-printer))
|
||||
(let ((inhibit-read-only t)) (delete-region (point-min) (point-max)))
|
||||
(ewoc-set-hf xmtn-status-ewoc (format "Root : %s\n" xmtn-status-root) "")
|
||||
(ewoc-enter-last xmtn-status-ewoc
|
||||
(make-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
|
||||
:conflicts-buffer nil
|
||||
:status-buffer status-buffer
|
||||
:heads heads
|
||||
:local-changes local-changes
|
||||
:conflicts 'need-scan))
|
||||
(xmtn-multiple-status-mode)
|
||||
(xmtn-status-refresh))
|
||||
|
||||
(provide 'xmtn-multi-status)
|
||||
|
||||
;; end of 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 - 2010 Stephen Leake
|
||||
|
||||
;; Author: Stephen Leake
|
||||
;; Keywords: tools
|
||||
@ -20,12 +20,13 @@
|
||||
;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
;; Boston, MA 02110-1301 USA.
|
||||
|
||||
(eval-and-compile
|
||||
(eval-when-compile
|
||||
;; these have macros we use
|
||||
(require 'xmtn-ids))
|
||||
|
||||
(eval-when-compile
|
||||
(eval-and-compile
|
||||
;; these have functions we use
|
||||
(require 'xmtn-automate)
|
||||
(require 'xmtn-base)
|
||||
(require 'xmtn-conflicts))
|
||||
|
||||
@ -49,7 +50,8 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(defstruct (xmtn-propagate-data (:copier nil))
|
||||
from-work ; directory name relative to xmtn-propagate-from-root
|
||||
to-work ; directory name relative to xmtn-propagate-to-root
|
||||
from-name ; display name, in buffer and menus
|
||||
; from-work is often the same as to-work
|
||||
from-name ; display name, in buffer and menus; usually root dir name
|
||||
to-name ;
|
||||
from-branch ; branch name (assumed never changes)
|
||||
to-branch ;
|
||||
@ -57,6 +59,8 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
from-head-rev ; nil | mtn rev string; current head revision; nil if multiple heads
|
||||
to-head-rev ;
|
||||
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
|
||||
propagate-needed ; nil | t
|
||||
from-heads ; 'at-head | 'need-update | 'need-merge)
|
||||
to-heads ;
|
||||
@ -66,6 +70,7 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
'need-scan) ;
|
||||
(conflicts
|
||||
'need-scan) ; 'need-scan | 'need-resolve | 'need-review-resolve-internal | 'ok
|
||||
; for propagate
|
||||
)
|
||||
|
||||
(defun xmtn-propagate-from-work (data)
|
||||
@ -162,11 +167,44 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(if (buffer-live-p (xmtn-propagate-data-conflicts-buffer data))
|
||||
(with-current-buffer (xmtn-propagate-data-conflicts-buffer data) (save-buffer))))
|
||||
|
||||
(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))) ))
|
||||
|
||||
(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))) ))
|
||||
|
||||
(defun xmtn-propagate-kill-status-buffers (data)
|
||||
(if (buffer-live-p (xmtn-propagate-data-from-status-buffer data))
|
||||
(kill-buffer (xmtn-propagate-data-from-status-buffer 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"
|
||||
(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)))
|
||||
|
||||
(defun xmtn-propagate-clean ()
|
||||
@ -211,8 +249,36 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(eq 'need-scan (xmtn-propagate-data-from-local-changes data))
|
||||
(eq 'need-scan (xmtn-propagate-data-to-local-changes data)))))
|
||||
|
||||
(defun xmtn-propagate-commit-to ()
|
||||
"Show commit buffer for `to' workspace, so it can be committed, updated, or merged."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(pop-to-buffer (xmtn-propagate-data-to-status-buffer data))))
|
||||
|
||||
(defun xmtn-propagate-commit-top ()
|
||||
"Non-nil if commit is appropriate for current `to' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(eq (xmtn-propagate-data-to-local-changes data) 'need-commit))))
|
||||
|
||||
(defun xmtn-propagate-commit-from ()
|
||||
"Show commit buffer for `from' workspace, so it can be committed, updated, or merged."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(pop-to-buffer (xmtn-propagate-data-from-status-buffer data))))
|
||||
|
||||
(defun xmtn-propagate-commit-fromp ()
|
||||
"Non-nil if commit 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-local-changes data) 'need-commit))))
|
||||
|
||||
(defun xmtn-propagate-update-to ()
|
||||
"Update current workspace."
|
||||
"Update current `to' workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
@ -223,17 +289,12 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(xmtn-propagate-refresh-one data nil)
|
||||
(ewoc-invalidate xmtn-propagate-ewoc elem)))
|
||||
|
||||
(defun xmtn-propagate-update-from ()
|
||||
"Update current 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-rev data)
|
||||
nil t)
|
||||
(xmtn-propagate-refresh-one data nil)
|
||||
(ewoc-invalidate xmtn-propagate-ewoc elem)))
|
||||
(defun xmtn-propagate-update-top ()
|
||||
"Non-nil if update is appropriate for current `to' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(eq (xmtn-propagate-data-to-heads data)
|
||||
'need-update))))
|
||||
|
||||
(defun xmtn-propagate-propagate ()
|
||||
"Propagate current workspace."
|
||||
@ -282,22 +343,7 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(member (xmtn-propagate-data-conflicts data)
|
||||
'(need-resolve need-review-resolve-internal)))))
|
||||
|
||||
(defun xmtn-propagate-status-to ()
|
||||
"Run xmtn-status on current `to' workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
|
||||
;; can't create log-edit buffer with both conflicts and status
|
||||
;; buffer open, and we'll be killing this as part of the refresh
|
||||
;; anyway.
|
||||
(xmtn-propagate-kill-conflicts-buffer data)
|
||||
|
||||
(setf (xmtn-propagate-data-to-local-changes data) 'ok)
|
||||
(xmtn-status (xmtn-propagate-to-work data))))
|
||||
|
||||
(defun xmtn-propagate-status-to-ok ()
|
||||
(defun xmtn-propagate-local-changes-to-ok ()
|
||||
"Ignore local changes in current `to' workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
@ -305,23 +351,14 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(setf (xmtn-propagate-data-to-local-changes data) 'ok)
|
||||
(ewoc-invalidate xmtn-propagate-ewoc elem)))
|
||||
|
||||
(defun xmtn-propagate-status-top ()
|
||||
"Non-nil if xmtn-status is appropriate for current `to' workspace."
|
||||
(defun xmtn-propagate-local-changes-top ()
|
||||
"Non-nil if local-changes-to-ok is appropriate for current `to' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(member (xmtn-propagate-data-to-local-changes data)
|
||||
'(need-scan need-commit)))))
|
||||
|
||||
(defun xmtn-propagate-status-from ()
|
||||
"Run xmtn-status on current `from' workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(setf (xmtn-propagate-data-from-local-changes data) 'ok)
|
||||
(xmtn-status (xmtn-propagate-from-work data))))
|
||||
|
||||
(defun xmtn-propagate-status-from-ok ()
|
||||
(defun xmtn-propagate-local-changes-from-ok ()
|
||||
"Ignore local changes in current `from' workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
@ -329,70 +366,63 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(setf (xmtn-propagate-data-from-local-changes data) 'ok)
|
||||
(ewoc-invalidate xmtn-propagate-ewoc elem)))
|
||||
|
||||
(defun xmtn-propagate-status-fromp ()
|
||||
"Non-nil if xmtn-status is appropriate for current `from' workspace."
|
||||
(defun xmtn-propagate-local-changes-fromp ()
|
||||
"Non-nil if local-changes-from-ok is appropriate for current `from' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(member (xmtn-propagate-data-from-local-changes data)
|
||||
'(need-scan need-commit)))))
|
||||
|
||||
(defun xmtn-propagate-missing-to ()
|
||||
"Run xmtn-missing on current `to' workspace."
|
||||
(defun xmtn-propagate-status-to ()
|
||||
"Show status buffer for `to' workspace, so it can be committed, updated, or merged."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(xmtn-missing nil (xmtn-propagate-to-work 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-status-buffer data)
|
||||
(xmtn-propagate-data-to-heads data)
|
||||
(xmtn-propagate-data-to-local-changes data))
|
||||
|
||||
(defun xmtn-propagate-missing-top ()
|
||||
"Non-nil if xmtn-missing is appropriate for current `to' workspace."
|
||||
;; Assume the user completely handles the local changes in the
|
||||
;; status buffer, so they are now ok
|
||||
(setf (xmtn-propagate-data-to-local-changes data) 'ok)))
|
||||
|
||||
(defun xmtn-propagate-status-top ()
|
||||
"Non-nil if xmtn-status is appropriate for current `to' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(eq 'need-update (xmtn-propagate-data-to-heads data)))))
|
||||
(or
|
||||
(member (xmtn-propagate-data-to-heads data)
|
||||
'(need-update need-merge))
|
||||
(eq (xmtn-propagate-data-to-local-changes data) 'need-commit)))))
|
||||
|
||||
(defun xmtn-propagate-missing-from ()
|
||||
"Run xmtn-missing on current `from' workspace."
|
||||
(defun xmtn-propagate-status-from ()
|
||||
"Show status buffer for `from' workspace, so it can be committed, updated, or merged."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(xmtn-missing nil (xmtn-propagate-from-work 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-status-buffer data)
|
||||
(xmtn-propagate-data-from-heads data)
|
||||
(xmtn-propagate-data-from-local-changes data))
|
||||
(setf (xmtn-propagate-data-from-local-changes data) 'ok)))
|
||||
|
||||
(defun xmtn-propagate-missing-fromp ()
|
||||
"Non-nil if xmtn-missing is appropriate for current `from' workspace."
|
||||
(defun xmtn-propagate-status-fromp ()
|
||||
"Non-nil if xmtn-status-one is appropriate for current `from' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(eq 'need-update (xmtn-propagate-data-from-heads data)))))
|
||||
|
||||
(defun xmtn-propagate-heads-to ()
|
||||
"Run xmtn-heads on current `to' workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem))
|
||||
(default-directory (xmtn-propagate-to-work data)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(xmtn-view-heads-revlist)))
|
||||
|
||||
(defun xmtn-propagate-heads-top ()
|
||||
"Non-nil if xmtn-heads is appropriate for current `to' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(eq 'need-merge (xmtn-propagate-data-to-heads data)))))
|
||||
|
||||
(defun xmtn-propagate-heads-from ()
|
||||
"Run xmtn-heads on current `from' workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem))
|
||||
(default-directory (xmtn-propagate-from-work data)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(xmtn-view-heads-revlist)))
|
||||
|
||||
(defun xmtn-propagate-heads-fromp ()
|
||||
"Non-nil if xmtn-heads is appropriate for current `from' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(eq 'need-merge (xmtn-propagate-data-from-heads data)))))
|
||||
(or
|
||||
(member (xmtn-propagate-data-from-heads data)
|
||||
'(need-update need-merge))
|
||||
(eq (xmtn-propagate-data-from-local-changes data) 'need-commit)))))
|
||||
|
||||
(defvar xmtn-propagate-actions-map
|
||||
(let ((map (make-sparse-keymap "actions")))
|
||||
@ -402,42 +432,33 @@ 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 [?b] '(menu-item "b) propagate"
|
||||
(define-key map [?8] '(menu-item (concat "8) 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 [?5] '(menu-item "5) propagate"
|
||||
xmtn-propagate-propagate
|
||||
:visible (xmtn-propagate-propagatep)))
|
||||
(define-key map [?a] '(menu-item "a) resolve conflicts"
|
||||
(define-key map [?4] '(menu-item "4) resolve conflicts"
|
||||
xmtn-propagate-resolve-conflicts
|
||||
:visible (xmtn-propagate-resolve-conflictsp)))
|
||||
(define-key map [?9] '(menu-item (concat "9) ignore local changes " (xmtn-propagate-to-name))
|
||||
xmtn-propagate-status-to-ok
|
||||
:visible (xmtn-propagate-status-top)))
|
||||
(define-key map [?8] '(menu-item (concat "8) ignore local changes " (xmtn-propagate-from-name))
|
||||
xmtn-propagate-status-from-ok
|
||||
:visible (xmtn-propagate-status-fromp)))
|
||||
(define-key map [?7] '(menu-item (concat "7) show missing " (xmtn-propagate-to-name))
|
||||
xmtn-propagate-missing-to
|
||||
:visible (xmtn-propagate-missing-top)))
|
||||
(define-key map [?6] '(menu-item (concat "6) show missing " (xmtn-propagate-from-name))
|
||||
xmtn-propagate-missing-from
|
||||
:visible (xmtn-propagate-missing-fromp)))
|
||||
(define-key map [?5] '(menu-item (concat "5) update " (xmtn-propagate-to-name))
|
||||
xmtn-propagate-update-to
|
||||
:visible (xmtn-propagate-missing-top)))
|
||||
(define-key map [?4] '(menu-item (concat "4) update " (xmtn-propagate-from-name))
|
||||
xmtn-propagate-update-from
|
||||
:visible (xmtn-propagate-missing-fromp)))
|
||||
(define-key map [?3] '(menu-item (concat "3) commit " (xmtn-propagate-to-name))
|
||||
(define-key map [?3] '(menu-item (concat "3) ignore local changes " (xmtn-propagate-to-name))
|
||||
xmtn-propagate-local-changes-to-ok
|
||||
:visible (xmtn-propagate-local-changes-top)))
|
||||
(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 [?2] '(menu-item (concat "2) commit " (xmtn-propagate-from-name))
|
||||
(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) show heads " (xmtn-propagate-to-name))
|
||||
xmtn-propagate-heads-to
|
||||
:visible (xmtn-propagate-heads-top)))
|
||||
(define-key map [?0] '(menu-item (concat "0) show heads " (xmtn-propagate-from-name))
|
||||
xmtn-propagate-heads-from
|
||||
:visible (xmtn-propagate-heads-fromp)))
|
||||
map)
|
||||
"Keyboard menu keymap used to manage propagates.")
|
||||
|
||||
@ -572,11 +593,6 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
|
||||
(dvc-trace "xmtn-propagate-refresh-one: %s" from-work)
|
||||
|
||||
(if refresh-local-changes
|
||||
(progn
|
||||
(setf (xmtn-propagate-data-from-local-changes data) 'need-scan)
|
||||
(setf (xmtn-propagate-data-to-local-changes data) 'need-scan)))
|
||||
|
||||
(let ((heads (xmtn--heads from-work (xmtn-propagate-data-from-branch data)))
|
||||
(from-base-rev (xmtn--get-base-revision-hash-id-or-null from-work)))
|
||||
(case (length heads)
|
||||
@ -604,19 +620,24 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(setf (xmtn-propagate-data-propagate-needed data)
|
||||
(xmtn-propagate-needed data))
|
||||
|
||||
(if refresh-local-changes
|
||||
(progn
|
||||
(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 need-commit)
|
||||
(setf (xmtn-propagate-data-from-local-changes data) (xmtn-automate-local-changes from-work)))
|
||||
(ok nil))
|
||||
(need-scan
|
||||
(xmtn-propagate-create-from-status-buffer data))
|
||||
(t nil))
|
||||
|
||||
(ecase (xmtn-propagate-data-to-local-changes data)
|
||||
((need-scan need-commit)
|
||||
(setf (xmtn-propagate-data-to-local-changes data) (xmtn-automate-local-changes to-work)))
|
||||
(ok nil))))
|
||||
(need-scan
|
||||
(xmtn-propagate-create-to-status-buffer data))
|
||||
(t nil))))
|
||||
|
||||
(if (xmtn-propagate-data-propagate-needed data)
|
||||
(progn
|
||||
@ -641,7 +662,7 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(interactive)
|
||||
(ewoc-map 'xmtn-propagate-refresh-one xmtn-propagate-ewoc current-prefix-arg)
|
||||
;; leaves point at (point-min)
|
||||
(xmtn-propagate-next t)
|
||||
(xmtn-propagate-next nil t)
|
||||
(message "done"))
|
||||
|
||||
(defun xmtn-propagate-make-data (from-workspace to-workspace from-name to-name)
|
||||
@ -668,16 +689,16 @@ to TO-DIR. WORKSPACES (default nil) is a list of workspaces
|
||||
common to from-dir and to-dir; if nil, the directories are
|
||||
scanned and all common ones found are used."
|
||||
(interactive "DPropagate all from (root directory): \nDto (root directory): ")
|
||||
(setq from-dir (substitute-in-file-name from-dir))
|
||||
(setq to-dir (substitute-in-file-name to-dir))
|
||||
(pop-to-buffer (get-buffer-create "*xmtn-propagate*"))
|
||||
;; xmtn-propagate-*-root are buffer-local. Note that we don't care
|
||||
;; what 'default-directory' is for xmtn-propagate buffer.
|
||||
(setq xmtn-propagate-from-root (file-name-as-directory (expand-file-name (substitute-in-file-name from-dir))))
|
||||
(setq xmtn-propagate-to-root (file-name-as-directory (expand-file-name (substitute-in-file-name to-dir))))
|
||||
(let ((from-workspaces (or workspaces
|
||||
(xmtn--filter-non-dir from-dir)))
|
||||
(xmtn--filter-non-ws xmtn-propagate-from-root)))
|
||||
(to-workspaces (or workspaces
|
||||
(xmtn--filter-non-dir to-dir))))
|
||||
(xmtn--filter-non-ws xmtn-propagate-to-root))))
|
||||
|
||||
(pop-to-buffer (get-buffer-create "*xmtn-propagate*"))
|
||||
(setq xmtn-propagate-from-root (file-name-as-directory from-dir))
|
||||
(setq xmtn-propagate-to-root (file-name-as-directory to-dir))
|
||||
(setq xmtn-propagate-ewoc (ewoc-create 'xmtn-propagate-printer))
|
||||
(let ((inhibit-read-only t)) (delete-region (point-min) (point-max)))
|
||||
(ewoc-set-hf
|
||||
@ -701,29 +722,27 @@ scanned and all common ones found are used."
|
||||
(defun xmtn-propagate-one (from-work to-work)
|
||||
"Show all actions needed to propagate FROM-WORK to TO-WORK."
|
||||
(interactive "DPropagate all from (workspace): \nDto (workspace): ")
|
||||
(setq from-work (substitute-in-file-name from-work))
|
||||
(setq to-work (substitute-in-file-name to-work))
|
||||
(let ((default-directory to-work))
|
||||
(pop-to-buffer (get-buffer-create "*xmtn-propagate*"))
|
||||
;; default-directory is wrong if buffer is reused
|
||||
(setq default-directory to-work)
|
||||
(setq xmtn-propagate-from-root (expand-file-name (concat (file-name-as-directory from-work) "../")))
|
||||
(setq xmtn-propagate-to-root (expand-file-name (concat (file-name-as-directory to-work) "../")))
|
||||
(setq xmtn-propagate-ewoc (ewoc-create 'xmtn-propagate-printer))
|
||||
(let ((inhibit-read-only t)) (delete-region (point-min) (point-max)))
|
||||
(ewoc-set-hf
|
||||
xmtn-propagate-ewoc
|
||||
(concat
|
||||
(format "From root : %s\n" xmtn-propagate-from-root)
|
||||
(format " To root : %s\n" xmtn-propagate-to-root)
|
||||
)
|
||||
"")
|
||||
(xmtn-propagate-make-data
|
||||
(file-name-nondirectory (directory-file-name from-work))
|
||||
(file-name-nondirectory (directory-file-name to-work))
|
||||
(file-name-nondirectory (directory-file-name from-work))
|
||||
(file-name-nondirectory (directory-file-name to-work)))
|
||||
(xmtn-propagate-mode)))
|
||||
(setq from-work (file-name-as-directory (expand-file-name (substitute-in-file-name from-work))))
|
||||
(setq to-work (file-name-as-directory (expand-file-name (substitute-in-file-name to-work))))
|
||||
(pop-to-buffer (get-buffer-create "*xmtn-propagate*"))
|
||||
(setq default-directory to-work)
|
||||
(setq xmtn-propagate-from-root (expand-file-name (concat from-work "../")))
|
||||
(setq xmtn-propagate-to-root (expand-file-name (concat to-work "../")))
|
||||
(setq xmtn-propagate-ewoc (ewoc-create 'xmtn-propagate-printer))
|
||||
(let ((inhibit-read-only t)) (delete-region (point-min) (point-max)))
|
||||
(ewoc-set-hf
|
||||
xmtn-propagate-ewoc
|
||||
(concat
|
||||
(format "From root : %s\n" xmtn-propagate-from-root)
|
||||
(format " To root : %s\n" xmtn-propagate-to-root)
|
||||
)
|
||||
"")
|
||||
(xmtn-propagate-make-data
|
||||
(file-name-nondirectory (directory-file-name from-work))
|
||||
(file-name-nondirectory (directory-file-name to-work))
|
||||
(file-name-nondirectory (directory-file-name from-work))
|
||||
(file-name-nondirectory (directory-file-name to-work)))
|
||||
(xmtn-propagate-mode))
|
||||
|
||||
(provide 'xmtn-propagate)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
;;; xmtn-revlist.el --- Interactive display of revision histories for monotone
|
||||
|
||||
;; Copyright (C) 2008, 2009 Stephen Leake
|
||||
;; Copyright (C) 2008 - 2010 Stephen Leake
|
||||
;; Copyright (C) 2006, 2007 Christian M. Ohler
|
||||
|
||||
;; Author: Christian M. Ohler
|
||||
@ -341,6 +341,33 @@ arg; root. Result is of the form:
|
||||
'()
|
||||
difference)))
|
||||
|
||||
(defun xmtn--revlist--review-update-info (root)
|
||||
(let* ((branch (xmtn--tree-default-branch root))
|
||||
(last-update
|
||||
(xmtn-automate-simple-command-output-line
|
||||
root
|
||||
(list "select" "u:")))
|
||||
(base-revision-hash-id (xmtn--get-base-revision-hash-id root))
|
||||
(difference
|
||||
;; FIXME: replace with automate log
|
||||
(xmtn-automate-simple-command-output-lines
|
||||
root
|
||||
(list "ancestry_difference" base-revision-hash-id last-update))))
|
||||
(list
|
||||
branch
|
||||
`(,(format "Tree %s" root)
|
||||
,(format "Branch %s" branch)
|
||||
,(format "Base %s" base-revision-hash-id)
|
||||
nil
|
||||
,(case (length difference)
|
||||
(0 "No revisions in last update")
|
||||
(1 "1 revision in last update:")
|
||||
(t (format
|
||||
"%s revisions in last update:"
|
||||
(length difference)))))
|
||||
'()
|
||||
difference)))
|
||||
|
||||
(defun xmtn-revlist-show-conflicts ()
|
||||
"If point is on a revision that has two parents, show conflicts
|
||||
from the merge."
|
||||
@ -447,6 +474,17 @@ from the merge."
|
||||
nil dvc-log-last-n))
|
||||
nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-review-update (root)
|
||||
"Review revisions in last update of ROOT workspace."
|
||||
(interactive "D")
|
||||
(xmtn--setup-revlist
|
||||
root
|
||||
'xmtn--revlist--review-update-info
|
||||
nil ;; first-line-only-p
|
||||
dvc-log-last-n)
|
||||
nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-view-heads-revlist ()
|
||||
"Display a revlist buffer showing the heads of the current branch."
|
||||
|
||||
@ -112,21 +112,27 @@ Signals an error if more (or fewer) than one line is output."
|
||||
(first lines)))
|
||||
|
||||
(defconst xmtn--minimum-required-command-version '(0 46))
|
||||
;; see also xmtn-sync.el xmtn-sync-required-command-version
|
||||
(defconst xmtn--required-automate-format-version "2")
|
||||
|
||||
(defun xmtn--have-no-ignore ()
|
||||
"Non-nil if mtn automate inventory supports --no-ignore, --no-unknown, --no-unchanged options."
|
||||
(>= (xmtn-dvc-automate-version) 7.0))
|
||||
(defvar xmtn--*cached-command-version* nil
|
||||
;; compare with (xmtn-version-<= required)
|
||||
"(MAJOR MINOR REVISION VERSION-STRING).")
|
||||
|
||||
(defvar xmtn--*cached-command-version* nil)
|
||||
(defvar xmtn--*command-version-cached-for-executable* nil)
|
||||
|
||||
(defun xmtn-version-<= (required)
|
||||
"Nonnil if REQUIRED (list of major, minor) is <= cached version."
|
||||
(version-list-<= required (butlast (xmtn--cached-command-version) 2)))
|
||||
|
||||
(defun xmtn--clear-command-version-cache ()
|
||||
(setq xmtn--*command-version-cached-for-executable* nil
|
||||
;; This is redundant but neater.
|
||||
xmtn--*cached-command-version* nil))
|
||||
|
||||
(defun xmtn--cached-command-version ()
|
||||
"Return mtn version as a list (MAJOR MINOR REVISION VERSION-STRING).
|
||||
Sets cache if not already set."
|
||||
(if (equal xmtn--*command-version-cached-for-executable* xmtn-executable)
|
||||
xmtn--*cached-command-version*
|
||||
(let ((executable xmtn-executable))
|
||||
@ -164,127 +170,19 @@ id."
|
||||
(list major minor revision string)))))
|
||||
|
||||
(defun xmtn--check-cached-command-version ()
|
||||
(let ((minimum-version xmtn--minimum-required-command-version))
|
||||
(destructuring-bind (major minor revision string)
|
||||
(xmtn--cached-command-version)
|
||||
(unless (or (> major (car minimum-version))
|
||||
(and (= major (car minimum-version))
|
||||
(>= minor (cadr minimum-version))))
|
||||
;; Clear cache now since the user is somewhat likely to
|
||||
;; upgrade mtn (or change the value of `xmtn-executable')
|
||||
;; after this message.
|
||||
(xmtn--clear-command-version-cache)
|
||||
(error (concat "xmtn does not work with mtn versions below %s.%s"
|
||||
" (%s is %s)")
|
||||
(car minimum-version) (cadr minimum-version)
|
||||
xmtn-executable string)))
|
||||
nil))
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-check-command-version ()
|
||||
"Check and display the version identifier of the mtn command.
|
||||
|
||||
This command resets xmtn's command version cache."
|
||||
(interactive)
|
||||
(xmtn--clear-command-version-cache)
|
||||
(destructuring-bind (major minor revision version-string)
|
||||
(xmtn--cached-command-version)
|
||||
(let* ((latest (xmtn--latest-mtn-release))
|
||||
(latest-major (first latest))
|
||||
(latest-minor (second latest)))
|
||||
(if (eval `(xmtn--version-case
|
||||
((and (= ,latest-major latest-minor)
|
||||
(mainline> latest-major latest-minor))
|
||||
t)
|
||||
(t
|
||||
nil)))
|
||||
(message "%s (xmtn considers this version newer than %s.%s)"
|
||||
version-string major minor)
|
||||
(message "%s" version-string))))
|
||||
(let ((minimum-version xmtn--minimum-required-command-version)
|
||||
(string (nth 3 (xmtn--cached-command-version))))
|
||||
(unless (xmtn-version-<= xmtn--minimum-required-command-version)
|
||||
;; Clear cache now since the user is somewhat likely to
|
||||
;; upgrade mtn (or change the value of `xmtn-executable')
|
||||
;; after this message.
|
||||
(xmtn--clear-command-version-cache)
|
||||
(error (concat "xmtn does not work with mtn versions below %s.%s"
|
||||
" (%s is %s)")
|
||||
(car minimum-version) (cadr minimum-version)
|
||||
xmtn-executable string)))
|
||||
nil)
|
||||
|
||||
(defun xmtn--make-version-check-form (version-var condition)
|
||||
;; The expression (mainline> X Y) matches all command versions
|
||||
;; strictly newer than X.Y, and, if X.Y is the latest version
|
||||
;; according to (xmtn--latest-mtn-release), command versions that
|
||||
;; report version X.Y with a revision ID different from what
|
||||
;; (xmtn--latest-mtn-release) returns. This is a kludge to attempt
|
||||
;; to distinguish the latest mtn release from the current
|
||||
;; bleeding-edge ("mainline") version. (Bleeding-edge mtn versions
|
||||
;; always report a version equal to the last release, while they
|
||||
;; generally have syntax and semantics that match the upcoming
|
||||
;; release; i.e., their syntax and semantics don't match the version
|
||||
;; number they report.)
|
||||
(case condition
|
||||
((t) `t)
|
||||
((nil) `nil)
|
||||
(t
|
||||
(let ((operator (car condition))
|
||||
(arguments (cdr condition)))
|
||||
(ecase operator
|
||||
((< <= > >= = /= mainline>)
|
||||
(let ((target-version arguments))
|
||||
(assert (eql (length arguments) 2))
|
||||
(ecase operator
|
||||
((=)
|
||||
`(and (= (car ,version-var) ,(car target-version))
|
||||
(= (cadr ,version-var) ,(cadr target-version))))
|
||||
((< >)
|
||||
`(or (,operator (car ,version-var) ,(car target-version))
|
||||
(and
|
||||
(= (car ,version-var) ,(car target-version))
|
||||
(,operator (cadr ,version-var) ,(cadr target-version)))))
|
||||
((mainline>)
|
||||
`(or (> (car ,version-var) ,(car target-version))
|
||||
(and (= (car ,version-var) ,(car target-version))
|
||||
(or (> (cadr ,version-var) ,(cadr target-version))
|
||||
(and (= (cadr ,version-var) ,(cadr target-version))
|
||||
(let ((-latest- (xmtn--latest-mtn-release)))
|
||||
(and (= (car -latest-) ,(car target-version))
|
||||
(= (cadr -latest-)
|
||||
,(cadr target-version))
|
||||
(not (equal (caddr ,version-var)
|
||||
(caddr -latest-))))))))))
|
||||
((/= <= >=)
|
||||
(let ((negated-operator (ecase operator
|
||||
(/= '=)
|
||||
(<= '>)
|
||||
(>= '<))))
|
||||
`(not ,(xmtn--make-version-check-form version-var
|
||||
`(,negated-operator
|
||||
,@arguments))))))))
|
||||
((not)
|
||||
(assert (eql (length arguments) 1))
|
||||
`(not ,(xmtn--make-version-check-form version-var (first arguments))))
|
||||
((and or)
|
||||
`(,operator
|
||||
,@(loop for subform in arguments
|
||||
collect
|
||||
(xmtn--make-version-check-form version-var subform)))))))))
|
||||
|
||||
(defun xmtn--signal-unsupported-version (version supported-conditions)
|
||||
(error "Operation only implemented for monotone versions matching %S"
|
||||
;; This message is probably not very helpful to users who
|
||||
;; don't know xmtn's internals.
|
||||
`(or ,@supported-conditions)))
|
||||
|
||||
(defmacro* xmtn--version-case (&body clauses)
|
||||
(let ((version (gensym)))
|
||||
`(let ((,version (xmtn--cached-command-version)))
|
||||
(cond ,@(loop for (condition . body) in clauses
|
||||
collect `(,(xmtn--make-version-check-form version
|
||||
condition)
|
||||
,@body))
|
||||
(t (xmtn--signal-unsupported-version
|
||||
,version
|
||||
',(loop for (condition . nil) in clauses
|
||||
collect condition)))))))
|
||||
|
||||
(defun xmtn--latest-mtn-release ()
|
||||
;; Version number and revision id of the latest mtn release at the
|
||||
;; time of this xmtn release.
|
||||
'(0 35 "f92dd754bf5c1e6eddc9c462b8d68691cfeb7f8b"))
|
||||
|
||||
(provide 'xmtn-run)
|
||||
|
||||
;;; xmtn-run.el ends here
|
||||
|
||||
175
dvc/lisp/xmtn-sync.el
Normal file
175
dvc/lisp/xmtn-sync.el
Normal file
@ -0,0 +1,175 @@
|
||||
;;; xmtn-sync.el --- database sync handling for DVC backend for monotone
|
||||
;;
|
||||
;; Copyright (C) 2010 Stephen Leake
|
||||
;;
|
||||
;; Author: Stephen Leake
|
||||
;; Keywords: tools
|
||||
;;
|
||||
;; This file is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation; either version 2 of the License, or
|
||||
;; (at your option) any later version.
|
||||
;;
|
||||
;; This file is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this file; see the file COPYING. If not, write to
|
||||
;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
;; Boston, MA 02110-1301 USA.
|
||||
|
||||
(eval-when-compile
|
||||
;; these have macros we use
|
||||
)
|
||||
|
||||
(eval-and-compile
|
||||
;; these have functions we use
|
||||
(require 'xmtn-automate)
|
||||
)
|
||||
|
||||
;;; User variables
|
||||
(defvar xmtn-sync-branch-file "~/.dvc/branches"
|
||||
"File associating branch name with workspace root")
|
||||
|
||||
(defvar xmtn-sync-executable
|
||||
(cond
|
||||
((equal system-type 'windows-nt)
|
||||
;; Native MinGW does not support file: or ssh: - assume Cygwin is
|
||||
;; installed, but not first in path
|
||||
"c:/bin/mtn")
|
||||
(t
|
||||
;; Unix or Cygwin; assume mtn is in path
|
||||
"mtn"))
|
||||
"Executable for running sync command on local db; overrides xmtn-executable.")
|
||||
|
||||
(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'.")
|
||||
|
||||
;;; Internal variables
|
||||
(defconst xmtn-sync-required-command-version '(0 46)
|
||||
"Minimum mtn version for automate sync; overrides xmtn--minimum-required-command-version.")
|
||||
|
||||
(defconst xmtn-sync-remote-exec-default "mtn"
|
||||
"Default executable command to run on remote host for file: or ssh:; see `xmtn-sync-remote-exec-alist'.")
|
||||
|
||||
;; loaded from xmtn-sync-config
|
||||
(defvar xmtn-sync-branch-alist nil
|
||||
"Alist associating branch name with workspace root")
|
||||
|
||||
(defvar xmtn-sync-remote-exec-alist
|
||||
(list
|
||||
(list "file://" xmtn-sync-executable))
|
||||
"Alist of host and remote command. Overrides `xmtn-sync-remote-exec-default'.")
|
||||
|
||||
;; buffer-local
|
||||
(defvar xmtn-sync-local-db nil
|
||||
"Absolute path to local database.")
|
||||
(make-variable-buffer-local 'xmtn-sync-local-db)
|
||||
|
||||
(defvar xmtn-sync-remote-db nil
|
||||
"Absolute path to remote database.")
|
||||
(make-variable-buffer-local 'xmtn-sync-remote-db)
|
||||
|
||||
(defstruct (xmtn-sync-branch
|
||||
(:copier nil))
|
||||
;; ewoc element; data for a branch that was received
|
||||
name)
|
||||
|
||||
(defun xmtn-sync-set-hf ()
|
||||
"Set ewoc header and footer."
|
||||
(ewoc-set-hf
|
||||
xmtn-sync-ewoc
|
||||
(concat
|
||||
(format " local database : %s\n" xmtn-sync-local-db)
|
||||
(format "remote database : %s\n" xmtn-sync-remote-db)
|
||||
)
|
||||
""))
|
||||
|
||||
(defun xmtn-sync-printer (branch)
|
||||
"Print an ewoc element; BRANCH must be of type xmtn-sync-branch."
|
||||
(insert "branch: ")
|
||||
(insert (xmtn-sync-branch-name branch))
|
||||
(insert "\n")
|
||||
)
|
||||
|
||||
(defvar xmtn-sync-ewoc nil
|
||||
"Buffer-local ewoc for displaying sync.
|
||||
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)
|
||||
|
||||
(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))
|
||||
(work (assoc branch xmtn-sync-branch-alist)))
|
||||
(if (not work)
|
||||
(progn
|
||||
(setq work (read-directory-name (format "workspace root for %s: " branch)))
|
||||
(push (list branch work) xmtn-sync-branch-alist)))
|
||||
(xmtn-status-one work)))
|
||||
|
||||
(defvar xmtn-sync-ewoc-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [?0] '(menu-item "0) status"
|
||||
'xmtn-sync-status))
|
||||
map)
|
||||
"Keyboard menu keymap for xmtn-sync-ewoc.")
|
||||
|
||||
(defvar xmtn-sync-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [?q] 'dvc-buffer-quit)
|
||||
(define-key map "\M-d" xmtn-sync-ewoc-map)
|
||||
map)
|
||||
"Keymap used in `xmtn-sync-mode'.")
|
||||
|
||||
(easy-menu-define xmtn-sync-mode-menu xmtn-sync-mode-map
|
||||
"`xmtn-sync' menu"
|
||||
`("Xmtn-sync"
|
||||
["Do the right thing" xmtn-sync-ewoc-map t]
|
||||
["Quit" dvc-buffer-quit t]
|
||||
))
|
||||
|
||||
;; derive from nil causes no keymap to be used, but still have self-insert keys
|
||||
;; derive from fundamental-mode causes self-insert keys
|
||||
(define-derived-mode xmtn-sync-mode fundamental-mode "xmtn-sync"
|
||||
"Major mode to specify conflict resolutions."
|
||||
(setq dvc-buffer-current-active-dvc 'xmtn)
|
||||
(setq buffer-read-only nil)
|
||||
(setq xmtn-sync-ewoc (ewoc-create 'xmtn-sync-printer))
|
||||
(setq dvc-buffer-refresh-function nil)
|
||||
(dvc-install-buffer-menu)
|
||||
(setq buffer-read-only t)
|
||||
(buffer-disable-undo)
|
||||
(set-buffer-modified-p nil))
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-sync-sync (local-db remote-host remote-db)
|
||||
"Sync LOCAL-DB with REMOTE-HOST REMOTE-DB, display sent and received branches.
|
||||
Remote-db should include branch pattern in URI syntax."
|
||||
(interactive "flocal db: \nMremote-host: \nMremote-db: ")
|
||||
(pop-to-buffer (get-buffer-create "*xmtn-sync*"))
|
||||
(let ((xmtn-executable xmtn-sync-executable)
|
||||
(xmtn--minimum-required-command-version xmtn-sync-required-command-version))
|
||||
|
||||
;; pass remote command to mtn via Lua hook get_mtn_command; see
|
||||
;; xmtn-hooks.lua
|
||||
(setenv "XMTN_SYNC_MTN"
|
||||
(or (cadr (assoc remote-host xmtn-sync-remote-exec-alist))
|
||||
xmtn-sync-remote-exec-default))
|
||||
|
||||
(xmtn-automate-command-output-buffer
|
||||
default-directory ; root
|
||||
(current-buffer) ; output-buffer
|
||||
(list (list
|
||||
"ticker" "count"
|
||||
"db" local-db
|
||||
) ;; options
|
||||
"sync" (concat remote-host remote-db)) ;; command, args
|
||||
)))
|
||||
|
||||
(provide 'xmtn-sync)
|
||||
|
||||
;; end of file
|
||||
@ -34,7 +34,7 @@ ii = install-info
|
||||
|
||||
install: uninstall info
|
||||
$(MKDIR_P) -m 0755 $(info_dir)
|
||||
@for i in dvc.info* ; do \
|
||||
@for i in dvc.info* dvc-intro.info* ; do \
|
||||
echo Installing $$i ; \
|
||||
$(INSTALL_DATA) $$i $(info_dir) ; \
|
||||
done
|
||||
@ -48,13 +48,16 @@ install: uninstall info
|
||||
uninstall:
|
||||
rm -f $(info_dir)/dvc.info*
|
||||
|
||||
info: dvc.info
|
||||
info: dvc.info dvc-intro.info
|
||||
|
||||
alldeps = $(srcdir)/dvc.texinfo dvc-version.texinfo
|
||||
|
||||
dvc.info: $(alldeps)
|
||||
$(MAKEINFO) $(srcdir)/dvc.texinfo
|
||||
|
||||
dvc-intro.info: $(alldeps)
|
||||
$(MAKEINFO) $(srcdir)/dvc-intro.texinfo
|
||||
|
||||
dvc.html: $(alldeps)
|
||||
$(MAKEINFO) --html --no-split $(srcdir)/dvc.texinfo
|
||||
|
||||
|
||||
940
dvc/texinfo/dvc-intro.texinfo
Normal file
940
dvc/texinfo/dvc-intro.texinfo
Normal file
@ -0,0 +1,940 @@
|
||||
\input texinfo
|
||||
|
||||
@c Author : Stephen Leake <stephen_leake@stephe-leake.org>
|
||||
@c Web : http://www.stephe-leake.org/
|
||||
|
||||
@setfilename dvc-intro.info
|
||||
@settitle DVC: Introduction to the GNU Emacs interface to
|
||||
distributed version control systems.
|
||||
|
||||
@setchapternewpage off
|
||||
|
||||
@node Top
|
||||
@top DVC Intro
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
Copyright (C) 2007, 2008, 2009, 2010 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;
|
||||
with no Invariant Sections, with no Front-Cover Texts, and with no
|
||||
Back-Cover Texts. A copy of the license is included in the section
|
||||
entitled ``GNU Free Documentation License''.
|
||||
@end group
|
||||
@end smallexample
|
||||
|
||||
@menu
|
||||
* Overview::
|
||||
* Installing::
|
||||
* Invoking::
|
||||
* Status Display::
|
||||
* Key bindings::
|
||||
* Previewing updates::
|
||||
* Merging::
|
||||
* mtn command line::
|
||||
* Common Errors and Solutions::
|
||||
* GNU Free Documentation License::
|
||||
|
||||
@detailmenu
|
||||
--- The Detailed Node Listing ---
|
||||
|
||||
Overview
|
||||
|
||||
* Basic DVC::
|
||||
* Compare to CVS::
|
||||
|
||||
Invoking
|
||||
|
||||
* xmtn-status-one::
|
||||
* xmtn-propagate-one::
|
||||
|
||||
Key bindings
|
||||
|
||||
* status buffer keys::
|
||||
* Ediff keys::
|
||||
* Log edit keys::
|
||||
* DVC log keys::
|
||||
* DVC diff keys::
|
||||
* mtn conflicts keys::
|
||||
|
||||
Common Errors and Solutions
|
||||
|
||||
* Attach blocked by unversioned path::
|
||||
* Revision id does not match conflict file::
|
||||
|
||||
@end detailmenu
|
||||
@end menu
|
||||
|
||||
@node Overview
|
||||
@chapter Overview
|
||||
|
||||
DVC is a common interface to several extremely powerful and flexible
|
||||
version control systems, such as Gnu arch, monotone, bzr, and others
|
||||
(known as 'backends' to DVC).
|
||||
|
||||
DVC provides the same (or at least similar) user interface for each
|
||||
backend, making it easier to use multiple backends in related
|
||||
projects. It also automates some tasks, and provides guidance to the
|
||||
user as to what needs to be done.
|
||||
|
||||
DVC is not included with the standard Gnu emacs distribution. It is
|
||||
provided in source form via a bzr repository (see @ref{Installing}).
|
||||
|
||||
If you are not already familiar with version control systems, please
|
||||
read @ref{Basic DVC}.
|
||||
|
||||
One of the most important features of the DVC user interface is that
|
||||
it identifies what files in a project need attention of some sort; you
|
||||
have changed them in your working directory, or someone else has
|
||||
changed them in the repository, or they've been deleted or are new,
|
||||
etc. DVC presents a list of all such files, and makes it easy to see
|
||||
what needs to be done for each file.
|
||||
|
||||
When committing files, ediff is used to allow reviewing the changes,
|
||||
so an appropriate change comment can be written.
|
||||
|
||||
DVC replaces the command-line interface to the backends for the most
|
||||
common operations, but it is still necessary to use the command line
|
||||
at times. Creating a repository, starting a project in a repository,
|
||||
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.
|
||||
|
||||
@menu
|
||||
* Basic DVC::
|
||||
* Compare to CVS::
|
||||
@end menu
|
||||
|
||||
@node Basic DVC
|
||||
@section Basic DVC
|
||||
|
||||
Here we give a brief introduction to general concepts of distributed
|
||||
version control systems, focusing on the concepts that are needed to
|
||||
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.
|
||||
|
||||
Let's start with some definitions:
|
||||
|
||||
@table @dfn
|
||||
@item workspace
|
||||
Each user has a workspace, containing a copy of the files she is
|
||||
working on. This is typically a directory tree. In the root directory
|
||||
of the tree there is typically a directory containing backend control
|
||||
files, used only by the backend.
|
||||
|
||||
@item database
|
||||
The database stores copies of all files in the workspace (and typically
|
||||
more than one workspace), together with all of the change history and
|
||||
other meta-information. The database is never edited directly; only
|
||||
the backends modify it.
|
||||
|
||||
@item local database
|
||||
A database on the user's machine. This database is used to
|
||||
control all workspaces on the user's machine.
|
||||
|
||||
@item remote database
|
||||
A database on a remote machine. This may be another user's local
|
||||
database, or a central database set up specifically for sharing files.
|
||||
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.
|
||||
|
||||
@item branch
|
||||
A label for distinct trees of revisions. There are two main uses for
|
||||
branches; parallel development on a single project, and completely
|
||||
separate projects. Branches of a single project are typically merged
|
||||
back together (this is called ``propagating''), while completely
|
||||
separate projects are not.
|
||||
|
||||
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
|
||||
@ref{Merging}).
|
||||
|
||||
@item merge
|
||||
The process of combining multiple heads of a branch into one
|
||||
head. This can encounter conflicts that require user resolution; see
|
||||
@ref{Merging}.
|
||||
|
||||
@item propagate
|
||||
One branch can be ``propagated'' to another. This is a form of
|
||||
merging; it merges all the changes from one branch into another,
|
||||
starting from their common ancestor (which is usually the previous
|
||||
propagate between the two branches).
|
||||
|
||||
This is how changes in a development branch are promoted to the main
|
||||
branch.
|
||||
|
||||
Since propagating is a form of merging, it can encounter all of the
|
||||
same conflicts that merging can.
|
||||
|
||||
@item *dvc-status* buffer
|
||||
A main user interface buffer. It shows all files in the workspace that
|
||||
need attention. Single keystrokes invoke various operations.
|
||||
@xref{Status Display}, for more details.
|
||||
|
||||
The name of the buffer is not literally @dfn{*dvc-status*}; instead,
|
||||
@dfn{dvc} is replaced by the backend name; @dfn{xmtn} for monotone,
|
||||
@dfn{bzr} for bzr, etc. But in this document, we will use the name
|
||||
@dfn{*dvc-status*}.
|
||||
|
||||
@item *dvc-diff* buffer
|
||||
Another main user interface buffer. It shows the files involved in a
|
||||
particular revision, together with the diffs of the changes. Single
|
||||
keystrokes invoke various operations.
|
||||
|
||||
@end table
|
||||
|
||||
Users edit files in their workspace, then use DVC to synchronize the
|
||||
workspace with the local database. Later, they use the command line to
|
||||
synchronize their local database with a remote database. This allows
|
||||
each user to make changes locally but still under change control,
|
||||
without affecting other users until they each choose to synchronize.
|
||||
|
||||
@node Compare to CVS
|
||||
@section Compare to CVS
|
||||
Since many people are familiar with the CVS version control system, we
|
||||
compare that with DVC, and monotone in particular.
|
||||
|
||||
In CVS, each file is committed separately; in DVC, all files in a
|
||||
workspace are committed together. This makes sure that all changes
|
||||
that are related are committed together.
|
||||
|
||||
This means the commit log message mentions all files that have
|
||||
changes; it is a much longer message, but there are fewer of them, and
|
||||
the message can more easily describe changes that affect more than one
|
||||
file.
|
||||
|
||||
In CVS, you must always have access to the remote server. In DVC, you
|
||||
work with a local database, then separately sync that database with a
|
||||
remote server. Thus DVC is useful when not on a network; monotone can
|
||||
even sync via USB disk rather than a network connection.
|
||||
|
||||
This means there are two steps to syncing a workspace with the central
|
||||
server, which can be annoying. On the other hand, the sync process
|
||||
syncs all projects in the database at once; with monotone, it lets you
|
||||
know what projects have changes.
|
||||
|
||||
Otherwise the primary Emacs interface to CVS and DVC are very similar,
|
||||
although DVC has many secondary interfaces that CVS does not have.
|
||||
|
||||
@node Installing
|
||||
@chapter Installing
|
||||
Install bzr; see @url{http://bazaar.canonical.com/en/}.
|
||||
|
||||
Retrieve the DCV source; see
|
||||
@url{https://gna.org/projects/dvc#options} for general information.
|
||||
|
||||
In a bash shell:
|
||||
@example
|
||||
cd ~
|
||||
bzr get http://bzr.xsteve.at/dvc/
|
||||
cd ~/dvc
|
||||
autoconf
|
||||
./configure
|
||||
make
|
||||
@end example
|
||||
|
||||
In your @file{.emacs}, add @code{(load-file (expand-file-name "~/dvc/dvc-load.el"))}
|
||||
|
||||
@node Invoking
|
||||
@chapter Invoking
|
||||
|
||||
Before invoking DVC, you may want to ensure that the local database is
|
||||
synchronized with the central database, via a backend-specific
|
||||
command line.
|
||||
|
||||
You typically invoke DVC with the Emacs command @command{dvc-status}
|
||||
or @command{dvc-diff}. This prompts for a workspace; it should be the
|
||||
top level directory in your working directory tree.
|
||||
|
||||
You can also create shortcuts in text files to invoke dvc:
|
||||
|
||||
@example
|
||||
(dvc-status (expand-file-name "~/dvc"))
|
||||
(dvc-diff nil (expand-file-name "~/dvc"))
|
||||
@end example
|
||||
|
||||
These can be executed with @key{C-x C-e}, and are a handy way of
|
||||
keeping track of several workspaces.
|
||||
|
||||
@command{dvc-status} or @command{dvc-diff} run the corresponding
|
||||
backend command, comparing the workspace against the local database,
|
||||
and presenting the information in the @dfn{*dvc-status*} or
|
||||
@dfn{*dvc-diff*} buffer.
|
||||
|
||||
For monotone, there are higher-level starting points:
|
||||
@table @command
|
||||
@item xmtn-status-one
|
||||
Summarizes the status of one workspace.
|
||||
|
||||
@item xmtn-status-multiple
|
||||
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
|
||||
|
||||
@item xmtn-propagate-multiple
|
||||
Supervises propagating several workspaces
|
||||
|
||||
@end table
|
||||
|
||||
@menu
|
||||
* xmtn-status-one::
|
||||
* xmtn-propagate-one::
|
||||
@end menu
|
||||
|
||||
@node xmtn-status-one
|
||||
@section xmtn-status-one
|
||||
Summarizes the status of one workspace, in a @dfn{xmtn-multi-status}
|
||||
buffer. The branch name is shown, followed by possible appropriate
|
||||
actions. As each action is performed, it is replaced by the next
|
||||
action, until there are none left.
|
||||
|
||||
Similarly, @command{xmtn-status-multiple} shows the status of all
|
||||
workspaces immediately under a root directory.
|
||||
|
||||
Actions are invoked with @key{M-d}.
|
||||
|
||||
The possible actions are:
|
||||
@table @dfn
|
||||
@item need-refresh
|
||||
Shown while the backend is computing, or the user is performing
|
||||
operations in an associated @dfn{*xmtn-multi-status*} buffer.
|
||||
|
||||
@item commit
|
||||
Open an @dfn{*xmtn-status*} buffer to commit changes.
|
||||
|
||||
@item resolve conflicts
|
||||
Open an @dfn{*xmtn-conflicts*} buffer to resolve conflicts; see @ref{Merging}.
|
||||
|
||||
@item show heads
|
||||
Open an @dfn{*xmtn-revlist*} buffer to show the current head revisions.
|
||||
|
||||
@item merge
|
||||
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 ignore local changes
|
||||
Don't show @dfn{commit}.
|
||||
|
||||
@item refresh
|
||||
Recompute the @dfn{*xmtn-multi-status*} display.
|
||||
|
||||
@item clean/delete
|
||||
Delete conflicts and conflict resolution files, and delete
|
||||
the workspace from the display.
|
||||
|
||||
@end table
|
||||
|
||||
@node xmtn-propagate-one
|
||||
@section xmtn-propagate-one
|
||||
@command{xmtn-propagate-one} supervises the process of propagating
|
||||
from one workspace to another, in an @dfn{xmtn-propagate} buffer.
|
||||
|
||||
The display shows one source and destination branch pair, and possible
|
||||
appropriate actions. As each action is performed, it is replaced by
|
||||
the next action, until there are none left.
|
||||
|
||||
Similarly, @command{xmtn-propagate-multiple} supervises the
|
||||
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.
|
||||
|
||||
Actions are invoked with @key{M-d}.
|
||||
|
||||
The possible actions are:
|
||||
@table @command
|
||||
@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
|
||||
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.
|
||||
|
||||
@item ignore local changes ``from''
|
||||
@item ignore local changes ``to''
|
||||
Don't show @dfn{local changes unknown}; assume the workspace is
|
||||
committed. Useful when you know that any local changes won't interfere
|
||||
with the propagate.
|
||||
|
||||
@item resolve conflicts
|
||||
Open an @dfn{*xmtn-conflicts*} buffer in the destination workspace to
|
||||
resolve propagate conflicts; see @ref{Merging}.
|
||||
|
||||
@item propagate
|
||||
Propagate the branch pair, using the conflict resolutions.
|
||||
|
||||
@item refresh
|
||||
Recompute the display. If prefixed with @key{C-u}, force examining
|
||||
workspaces for local changes.
|
||||
|
||||
@item clean/delete
|
||||
Delete conflicts and conflict resolution files, and delete
|
||||
the workspace from the display.
|
||||
|
||||
@end table
|
||||
|
||||
@node Status Display
|
||||
@chapter Status Display
|
||||
|
||||
After invoking @command{dvc-status}, you are presented with the
|
||||
@dfn{*dvc-status*} buffer.
|
||||
|
||||
The detailed format differs depending on the backend. This
|
||||
presentation is close to the bzr and mtn formats.
|
||||
|
||||
The buffer contains a header, such as:
|
||||
|
||||
@example
|
||||
Status for c:/Projects/GDS/common/main/:
|
||||
base revision : e946839c833b15e6bf12bd1536764e1106c41924
|
||||
branch : common.main
|
||||
branch is merged
|
||||
base revision is a head revision
|
||||
@end example
|
||||
|
||||
The last two lines are important; either may have ``not'' in it.
|
||||
|
||||
If the branch is not merged, it must be merged before an update can be
|
||||
done; see @ref{Merging}. However, commits can be done when the branch
|
||||
is not merged; this allows saving work before attempting the merge.
|
||||
|
||||
If the base revision is not a head revision, there are updates that
|
||||
need to be applied to the workspace. The updates may be reviewed first
|
||||
using @key{M m}; they may be applied using @key{M u}.
|
||||
|
||||
In the main body of the buffer, there is one line for each file in the
|
||||
workspace that needs attention. For example:
|
||||
|
||||
@example
|
||||
* modified hardware/gds-hardware-pmrd_wrapper.adb
|
||||
unknown build/ip1k110_quartus/serv_req_info.txt
|
||||
E modified hardware/test/test_hardware-one_harness.adb
|
||||
@end example
|
||||
|
||||
Each line has three fields:
|
||||
|
||||
@table @dfn
|
||||
@item Mark
|
||||
Either blank (not marked), '*' (marked), or 'E' (excluded). Most
|
||||
commands can apply to a group of marked files, but some cannot (they
|
||||
warn if a group is marked).
|
||||
|
||||
Excluded files are under configuration management, but are excluded
|
||||
from commits. This is used for files that each user modifies, such as
|
||||
development test drivers.
|
||||
|
||||
@item Status
|
||||
A phrase indicating the status of the file; see the table below.
|
||||
|
||||
@item File name
|
||||
Gives the file name of the working file, with a path relative to the
|
||||
root directory.
|
||||
|
||||
@end table
|
||||
|
||||
In addition, some files will have extra status information that
|
||||
appears on the next line, indented.
|
||||
|
||||
The following table defines each status phrase, and gives the set of
|
||||
actions that can be taken for each. The action shown is from the DVC
|
||||
menu; the equivalent key is also given.
|
||||
|
||||
Other actions (such as commit) apply to all files; they are discussed
|
||||
later.
|
||||
|
||||
@table @samp
|
||||
@c the list of status phrases is in
|
||||
@c /Gnu/dvc/lisp/dvc-fileinfo.el dvc-fileinfo-status-image
|
||||
@c keep this list in the same order
|
||||
@item Added
|
||||
Working file has been added, but not committed.
|
||||
@table @samp
|
||||
@item @key{r} Delete
|
||||
Remove the file from the workspace, do not commit it.
|
||||
Do this if you've changed your mind.
|
||||
@end table
|
||||
|
||||
@item Conflict
|
||||
A conflict was detected while merging.
|
||||
The same lines have been edited differently by different people.
|
||||
|
||||
This status does not appear with the monotone back-end.
|
||||
|
||||
@table @samp
|
||||
@item @key{<enter>} Edit the file.
|
||||
Either resolve the conflict
|
||||
manually, or use @code{M-x smerge-ediff}. Execute @code{M-x
|
||||
dvc-resolve} when finished to inform the back-end that the
|
||||
conflict is resolved.
|
||||
@item @key{U} Revert
|
||||
Delete the working copy, replace it with the database copy. Do
|
||||
this if you decide the changes are not correct.
|
||||
@end table
|
||||
|
||||
@item Deleted
|
||||
Working file has been marked for deletion, but not committed.
|
||||
@table @samp
|
||||
@item @key{a} Add
|
||||
Undo the removal.
|
||||
@end table
|
||||
|
||||
@item Ignored
|
||||
Working file is ignored by the back-end. Files with this status
|
||||
are not typically shown - ignored files are ignored by DVC as well.
|
||||
They can be enabled by setting @code{dvc-status-display-ignored} to
|
||||
nil.
|
||||
@table @samp
|
||||
@item @key{# e}
|
||||
Edit the back-end ignore file.
|
||||
@end table
|
||||
|
||||
@item Known
|
||||
Working file is known to the back-end, and unchanged. Files with
|
||||
this status are not typically shown. They can be enabled by setting
|
||||
@code{dvc-status-display-known} to nil. There are no appropriate
|
||||
actions.
|
||||
|
||||
@item Missing
|
||||
A previously known file has been deleted from the workspace, but
|
||||
not marked for deletion.
|
||||
@table @samp
|
||||
@key{U} Revert
|
||||
Restore the file to the workspace from the database.
|
||||
@item @key{r} Delete
|
||||
Mark the file for deletion.
|
||||
@end table
|
||||
|
||||
@item Modified
|
||||
A changed file in the workspace.
|
||||
@table @samp
|
||||
@item @key{e} ediff
|
||||
Review differences and collect a change comment.
|
||||
@item @key{U} Revert
|
||||
Delete the working copy, replace it with the database copy. Do
|
||||
this if you decide your changes are not correct.
|
||||
@end table
|
||||
|
||||
@item Rename-source
|
||||
Working file has been marked as renamed but not committed. No
|
||||
appropriate actions.
|
||||
|
||||
@item Rename-target
|
||||
Working file has been marked as renamed but not committed. No
|
||||
appropriate actions.
|
||||
|
||||
@item Unknown
|
||||
Working file is unknown.
|
||||
@table @samp
|
||||
@item @key{a} Add
|
||||
The file is a new source file; add it to the current revision. This will
|
||||
change the status to 'Added'.
|
||||
@item @key{i} Ignore
|
||||
The file is an output file of some sort (ie object file, test output).
|
||||
Ignore it in all future DVC sessions.
|
||||
@item @key{I} Ignore extension in dir
|
||||
Ignore all files with this extension in this directory.
|
||||
@item @key{M-I} Ignore extension
|
||||
Ignore all files with this extension in all directories.
|
||||
@item @key{r} Delete
|
||||
The file is a scratch file, or was created by mistake. Remove it from
|
||||
the workspace.
|
||||
@end table
|
||||
@end table
|
||||
|
||||
Changes are committed all at once; the set of changes to the entire
|
||||
workspace is called a ``revision''. @key{c} opens the
|
||||
@code{*dvc-log-edit*} buffer, where you can write a change comment.
|
||||
Then @key{C-c C-c} commits all changes.
|
||||
|
||||
The key @key{M-d} invokes a function called ``Do the Right Thing''. If
|
||||
there is only a single choice (or an extremely common choice) in the
|
||||
table above, it does that action. Otherwise, it presents a short list
|
||||
of the actions, in the message buffer, reminding the user of the
|
||||
appropriate options. Note that @key{M-d} means meta-d (alt-d on most
|
||||
PC keyboards))
|
||||
|
||||
@node Key bindings
|
||||
@chapter Key bindings
|
||||
|
||||
Here is a summary of the most useful key bindings in the various
|
||||
buffers associated with DVC.
|
||||
|
||||
@menu
|
||||
* status buffer keys::
|
||||
* Ediff keys::
|
||||
* Log edit keys::
|
||||
* DVC log keys::
|
||||
* DVC diff keys::
|
||||
* mtn conflicts keys::
|
||||
@end menu
|
||||
|
||||
@node status buffer keys
|
||||
@section status buffer keys
|
||||
In a @code{*dvc-status*} buffer:
|
||||
|
||||
@table @key
|
||||
@item M-d
|
||||
Do the right thing for the current file.
|
||||
|
||||
@item c
|
||||
Open a @code{*dvc-log-edit*} buffer to accumulate comments for a
|
||||
commit.
|
||||
|
||||
@item M m
|
||||
Show missing revisions; changes that will be applied by update.
|
||||
|
||||
@item M M
|
||||
Merge current heads; see @ref{Merging}.
|
||||
|
||||
@item M u
|
||||
Update to the current head.
|
||||
|
||||
@item R
|
||||
Rename a missing to an unknown file. The two files must be marked
|
||||
first, and they must be the only files marked.
|
||||
|
||||
@item t
|
||||
Create an entry in the @code{*dvc-log-edit*} for the current diff.
|
||||
|
||||
@end table
|
||||
|
||||
@node Ediff keys
|
||||
@section Ediff keys
|
||||
In an Ediff control buffer (the small window with Ediff in the title bar):
|
||||
|
||||
@table @key
|
||||
@item a
|
||||
Copy from buffer A to buffer B.
|
||||
|
||||
@item b
|
||||
Copy from buffer B to buffer A.
|
||||
|
||||
@item n
|
||||
Move to next diff.
|
||||
|
||||
@item p
|
||||
Move to previous diff.
|
||||
|
||||
@item q
|
||||
Quit Ediff.
|
||||
|
||||
@item t
|
||||
Create an entry in the @code{*dvc-log-edit*} for the current diff.
|
||||
|
||||
@item $$
|
||||
Focus on conflicts in a merge.
|
||||
|
||||
@item ?
|
||||
Show the help summary for Ediff. @key{?} hides it again.
|
||||
|
||||
@end table
|
||||
|
||||
@node Log edit keys
|
||||
@section log edit keys
|
||||
In the @code{*dvc-log-edit*} buffer:
|
||||
|
||||
@table @key
|
||||
@item C-c C-c
|
||||
Commit. Note that this is the only way to actually commit.
|
||||
|
||||
@end table
|
||||
|
||||
@node DVC log keys
|
||||
@section DVC log keys
|
||||
In a @code{*xmtn-log*} buffer:
|
||||
|
||||
@table @key
|
||||
@item n
|
||||
move to the next revision
|
||||
|
||||
@item p
|
||||
move to the previous revision
|
||||
|
||||
@item =
|
||||
show a diff of the changes in a single revision
|
||||
|
||||
@item C-=
|
||||
show a diff between the revision and the workspace
|
||||
|
||||
@end table
|
||||
|
||||
@node DVC diff keys
|
||||
@section DVC diff keys
|
||||
In a @code{*dvc-diff*} buffer:
|
||||
|
||||
@table @key
|
||||
@item e
|
||||
show ediff for current file
|
||||
|
||||
@item j
|
||||
jump between file list and diff hunks
|
||||
|
||||
@item n
|
||||
move to the next diff hunk
|
||||
|
||||
@item p
|
||||
move to the previous diff hunk
|
||||
|
||||
@end table
|
||||
|
||||
@node mtn conflicts keys
|
||||
@section mtn conflicts keys
|
||||
In a @code{*xmtn-conflicts*} buffer:
|
||||
|
||||
@table @key
|
||||
@item C
|
||||
Delete conflicts file and any resolution files.
|
||||
|
||||
@item c
|
||||
Clear the current resolution, so you can specify a different one.
|
||||
|
||||
@item n
|
||||
Move to the next conflict.
|
||||
|
||||
@item N
|
||||
Move to the next unresolved conflict.
|
||||
|
||||
@item p
|
||||
Move to the previous conflict.
|
||||
|
||||
@item P
|
||||
Move to the previous unresolved conflict.
|
||||
|
||||
@item q
|
||||
Quit the @code{*xmtn-conflicts*} buffer. The conflicts file and
|
||||
associated resolution files are saved.
|
||||
|
||||
@item r
|
||||
Specify a resolution for the current conflict. This prompts with a
|
||||
choice of resolutions appropriate for the current conflict; select the
|
||||
appropriate resolution by number. See @ref{Merging}, for information
|
||||
on the possible resolutions.
|
||||
|
||||
@item M-d
|
||||
Same as @key{r}
|
||||
|
||||
@end table
|
||||
|
||||
@node Previewing updates
|
||||
@chapter Previewing updates
|
||||
To preview updates before applying them to your workspace, use the
|
||||
@code{dvc-missing} command; it's on the status buffer menu at
|
||||
@code{DVC | Merge/Update | show missing}.
|
||||
|
||||
@code{dvc-missing} can also be invoked via the Emacs command line
|
||||
(@key{M-x}); that prompts for a local tree.
|
||||
|
||||
Invoking @code{dvc-missing} brings up an @code{*dvc-log*} window,
|
||||
showing revisions that are in your local database but not yet applied
|
||||
to the workspace.
|
||||
|
||||
The revisions are listed oldest first.
|
||||
|
||||
You can view the changes made in a single revision, or from that
|
||||
revision to the current workspace.
|
||||
|
||||
See @xref{Log edit keys}, for key bindings.
|
||||
|
||||
@key{=} and @key{C-=} bring up a @code{*dvc-diff*} buffer for the
|
||||
revision selected. The diffs are shown in Gnu diff format; all files
|
||||
in one @code{*dvc-diff*} buffer. There is a list of the files at the
|
||||
top of the buffer. See @xref{DVC diff keys}, for key bindings.
|
||||
|
||||
Note that you can also review updates after they have been
|
||||
applied. This is often more useful, because you can edit the workspace
|
||||
file to fix problems caused by the update, or just to see the final
|
||||
state after all revisions have been applied.
|
||||
|
||||
@node Merging
|
||||
@chapter Merging
|
||||
Monotone allows multiple people to each commit to their local
|
||||
database. Then when the databases are synced, there are multiple heads
|
||||
for the branch; one head for each developer that commited since the
|
||||
last sync.
|
||||
|
||||
These multiple heads must be merged before a local workspace can be
|
||||
updated to the head of the branch; there must be only one head to
|
||||
update to. The monotone command line allows updating to one head of an
|
||||
unmerged branch, but DVC does not support this.
|
||||
|
||||
When the changes in the different heads are to different files, or to
|
||||
different parts of the same file, monotone can perform the merge
|
||||
itself. However, when there are changes to the same parts of one file,
|
||||
it needs help; this is called a content conflict.
|
||||
|
||||
An @code{*xmtn-conflicts*} buffer shows all conflicts in a merge or
|
||||
propagate. You can work thru the list one a time, using @key{M-d}
|
||||
to specify conflict resolutions. The list is saved in a file, so you
|
||||
can come back to it later.
|
||||
|
||||
The conflicts that monotone knows how to resolve internally have
|
||||
resolutions of @code{resolved-internal}; the others have no
|
||||
resolutions.
|
||||
|
||||
The conflicts file and associated resolution files are stored in the
|
||||
monotone bookkeeping area. They must be deleted when you are done with
|
||||
them; use @key{C C} for that.
|
||||
|
||||
@key{M-d} prompts with a list of appropriate resolutions for the
|
||||
current conflict; select the appropriate resolution by number. The
|
||||
possible resolutions are:
|
||||
|
||||
@table @asis
|
||||
@item right: drop
|
||||
@itemx left: drop
|
||||
Resolve one side of a duplicate name conflict by dropping it.
|
||||
|
||||
@itemx drop
|
||||
Resolve an orphaned node conflict by dropping it.
|
||||
|
||||
@item right: rename
|
||||
@itemx left: rename
|
||||
Resolve one side of a duplicate name conflict by specifying a new name.
|
||||
|
||||
@item rename
|
||||
Resolve an orphaned node conflict by specifying a new name.
|
||||
|
||||
@item right: right file
|
||||
@itemx right: left file
|
||||
@itemx left: right file
|
||||
@itemx left: left file
|
||||
Resolve one side of a duplicate name conflict by specifying a file.
|
||||
|
||||
The other side must be dropped or renamed.
|
||||
|
||||
@itemx left file
|
||||
Resolve a content conflict by specifying a file. The file defaults to
|
||||
the current workspace file.
|
||||
|
||||
@item right: keep
|
||||
@itemx left: keep
|
||||
Resolve one side of a duplicate name conflict by keeping it as is.
|
||||
|
||||
The other side must be dropped or renamed.
|
||||
|
||||
@item right: ediff
|
||||
@itemx left: ediff
|
||||
Resolve one side of a duplicate name conflict by ediff. This brings up
|
||||
an ediff merge of the two files, and saves the result in the
|
||||
resolution file area.
|
||||
|
||||
The other side must be dropped or renamed.
|
||||
|
||||
@item ediff
|
||||
Resolve a content conflict via ediff. This brings up an ediff merge of
|
||||
the two files, and saves the result in the resolution file area.
|
||||
|
||||
@end table
|
||||
|
||||
See @xref{mtn conflicts keys}, for a summary of key bindings.
|
||||
|
||||
@node mtn command line
|
||||
@chapter mtn command line
|
||||
Sometimes, especially over NFS, the Emacs DVC interface can be
|
||||
painfully slow, and it is appropriate to use the mtn command line
|
||||
instead.
|
||||
|
||||
Other times, the mtn command line is just simpler.
|
||||
|
||||
So we list the most useful mtn commands here. See the monotone command
|
||||
line help or manual for more information.
|
||||
|
||||
@table @code
|
||||
@item status
|
||||
@code{mtn status}
|
||||
|
||||
@item commit
|
||||
@code{mtn commit --message="<message>"}
|
||||
|
||||
@code{mtn commit --message-file=_MTN/log}
|
||||
|
||||
@item rename
|
||||
@code{mtn rename <file> <new-file>}
|
||||
|
||||
@item update
|
||||
@code{mtn update --move-conflicting-paths}
|
||||
|
||||
@end table
|
||||
|
||||
@node Common Errors and Solutions
|
||||
@chapter Common Errors and Solutions
|
||||
|
||||
@menu
|
||||
* Attach blocked by unversioned path::
|
||||
* Revision id does not match conflict file::
|
||||
@end menu
|
||||
|
||||
@node Attach blocked by unversioned path
|
||||
@section Attach blocked by unversioned path
|
||||
Problem: When attempting to update a directory, this warning appears:
|
||||
|
||||
@example
|
||||
$ mtn update
|
||||
...
|
||||
mtn: warning: attach node 2147486644 blocked by unversioned path '<file path>'
|
||||
mtn: misuse: 1 workspace conflict
|
||||
@end example
|
||||
|
||||
Explanation: "Unversioned path" means the indicated file is not in the
|
||||
current revision, however the file already exists on the disk. The
|
||||
revision you are updating to contains the file, but it can't be
|
||||
updated because it would overwrite the unknown file on the disk
|
||||
|
||||
Solution: Delete the indicated files from the disk and retry the
|
||||
update, or specify the @command{--move-conflicting-paths} option.
|
||||
|
||||
@node Revision id does not match conflict file
|
||||
@section Revision id does not match conflict file
|
||||
Problem: When attempting to propagate from one branch to another, this message appears:
|
||||
|
||||
@example
|
||||
$ mtn: propagating common.main -> common.work_user
|
||||
mtn: [left] 48b675060af47a02bc6f773bd63647726f96cbd5
|
||||
mtn: [right] 94ffd0b529dfb44c3ab122fe6c514b5f2e857104
|
||||
mtn: misuse: left revision id does not match conflict file
|
||||
@end example
|
||||
|
||||
Explanation: It means you have some conflict files left over from a
|
||||
previous propagation or merge.
|
||||
|
||||
Solution: In a buffer showing the ``from'' workspace, run: M-x
|
||||
xmtn-conflicts-clean. Repeat in the ``to'' workspace, then propagate
|
||||
again.
|
||||
|
||||
@node GNU Free Documentation License, , Common Errors and Solutions, Top
|
||||
@appendix GNU Free Documentation License
|
||||
|
||||
@include fdl.texinfo
|
||||
@bye
|
||||
409
dvc/texinfo/fdl.texinfo
Normal file
409
dvc/texinfo/fdl.texinfo
Normal file
@ -0,0 +1,409 @@
|
||||
@c This file is derived from the GNU file fdl.texi, by deleting the
|
||||
@c addendum "How to use this License for your documents" and by deleting
|
||||
@c the @node and @appendixsec commands. The later need to be in the main
|
||||
@c texinfo file for the Emacs automatic menu-building commands to work.
|
||||
|
||||
@cindex FDL, GNU Free Documentation License
|
||||
@center Version 1.2, November 2002
|
||||
|
||||
@display
|
||||
Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
@end display
|
||||
|
||||
@enumerate 0
|
||||
@item
|
||||
PREAMBLE
|
||||
|
||||
The purpose of this License is to make a manual, textbook, or other
|
||||
functional and useful document @dfn{free} in the sense of freedom: to
|
||||
assure everyone the effective freedom to copy and redistribute it,
|
||||
with or without modifying it, either commercially or noncommercially.
|
||||
Secondarily, this License preserves for the author and publisher a way
|
||||
to get credit for their work, while not being considered responsible
|
||||
for modifications made by others.
|
||||
|
||||
This License is a kind of ``copyleft'', which means that derivative
|
||||
works of the document must themselves be free in the same sense. It
|
||||
complements the GNU General Public License, which is a copyleft
|
||||
license designed for free software.
|
||||
|
||||
We have designed this License in order to use it for manuals for free
|
||||
software, because free software needs free documentation: a free
|
||||
program should come with manuals providing the same freedoms that the
|
||||
software does. But this License is not limited to software manuals;
|
||||
it can be used for any textual work, regardless of subject matter or
|
||||
whether it is published as a printed book. We recommend this License
|
||||
principally for works whose purpose is instruction or reference.
|
||||
|
||||
@item
|
||||
APPLICABILITY AND DEFINITIONS
|
||||
|
||||
This License applies to any manual or other work, in any medium, that
|
||||
contains a notice placed by the copyright holder saying it can be
|
||||
distributed under the terms of this License. Such a notice grants a
|
||||
world-wide, royalty-free license, unlimited in duration, to use that
|
||||
work under the conditions stated herein. The ``Document'', below,
|
||||
refers to any such manual or work. Any member of the public is a
|
||||
licensee, and is addressed as ``you''. You accept the license if you
|
||||
copy, modify or distribute the work in a way requiring permission
|
||||
under copyright law.
|
||||
|
||||
A ``Modified Version'' of the Document means any work containing the
|
||||
Document or a portion of it, either copied verbatim, or with
|
||||
modifications and/or translated into another language.
|
||||
|
||||
A ``Secondary Section'' is a named appendix or a front-matter section
|
||||
of the Document that deals exclusively with the relationship of the
|
||||
publishers or authors of the Document to the Document's overall
|
||||
subject (or to related matters) and contains nothing that could fall
|
||||
directly within that overall subject. (Thus, if the Document is in
|
||||
part a textbook of mathematics, a Secondary Section may not explain
|
||||
any mathematics.) The relationship could be a matter of historical
|
||||
connection with the subject or with related matters, or of legal,
|
||||
commercial, philosophical, ethical or political position regarding
|
||||
them.
|
||||
|
||||
The ``Invariant Sections'' are certain Secondary Sections whose titles
|
||||
are designated, as being those of Invariant Sections, in the notice
|
||||
that says that the Document is released under this License. If a
|
||||
section does not fit the above definition of Secondary then it is not
|
||||
allowed to be designated as Invariant. The Document may contain zero
|
||||
Invariant Sections. If the Document does not identify any Invariant
|
||||
Sections then there are none.
|
||||
|
||||
The ``Cover Texts'' are certain short passages of text that are listed,
|
||||
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
|
||||
the Document is released under this License. A Front-Cover Text may
|
||||
be at most 5 words, and a Back-Cover Text may be at most 25 words.
|
||||
|
||||
A ``Transparent'' copy of the Document means a machine-readable copy,
|
||||
represented in a format whose specification is available to the
|
||||
general public, that is suitable for revising the document
|
||||
straightforwardly with generic text editors or (for images composed of
|
||||
pixels) generic paint programs or (for drawings) some widely available
|
||||
drawing editor, and that is suitable for input to text formatters or
|
||||
for automatic translation to a variety of formats suitable for input
|
||||
to text formatters. A copy made in an otherwise Transparent file
|
||||
format whose markup, or absence of markup, has been arranged to thwart
|
||||
or discourage subsequent modification by readers is not Transparent.
|
||||
An image format is not Transparent if used for any substantial amount
|
||||
of text. A copy that is not ``Transparent'' is called ``Opaque''.
|
||||
|
||||
Examples of suitable formats for Transparent copies include plain
|
||||
@sc{ascii} without markup, Texinfo input format, La@TeX{} input
|
||||
format, @acronym{SGML} or @acronym{XML} using a publicly available
|
||||
@acronym{DTD}, and standard-conforming simple @acronym{HTML},
|
||||
PostScript or @acronym{PDF} designed for human modification. Examples
|
||||
of transparent image formats include @acronym{PNG}, @acronym{XCF} and
|
||||
@acronym{JPG}. Opaque formats include proprietary formats that can be
|
||||
read and edited only by proprietary word processors, @acronym{SGML} or
|
||||
@acronym{XML} for which the @acronym{DTD} and/or processing tools are
|
||||
not generally available, and the machine-generated @acronym{HTML},
|
||||
PostScript or @acronym{PDF} produced by some word processors for
|
||||
output purposes only.
|
||||
|
||||
The ``Title Page'' means, for a printed book, the title page itself,
|
||||
plus such following pages as are needed to hold, legibly, the material
|
||||
this License requires to appear in the title page. For works in
|
||||
formats which do not have any title page as such, ``Title Page'' means
|
||||
the text near the most prominent appearance of the work's title,
|
||||
preceding the beginning of the body of the text.
|
||||
|
||||
A section ``Entitled XYZ'' means a named subunit of the Document whose
|
||||
title either is precisely XYZ or contains XYZ in parentheses following
|
||||
text that translates XYZ in another language. (Here XYZ stands for a
|
||||
specific section name mentioned below, such as ``Acknowledgements'',
|
||||
``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title''
|
||||
of such a section when you modify the Document means that it remains a
|
||||
section ``Entitled XYZ'' according to this definition.
|
||||
|
||||
The Document may include Warranty Disclaimers next to the notice which
|
||||
states that this License applies to the Document. These Warranty
|
||||
Disclaimers are considered to be included by reference in this
|
||||
License, but only as regards disclaiming warranties: any other
|
||||
implication that these Warranty Disclaimers may have is void and has
|
||||
no effect on the meaning of this License.
|
||||
|
||||
@item
|
||||
VERBATIM COPYING
|
||||
|
||||
You may copy and distribute the Document in any medium, either
|
||||
commercially or noncommercially, provided that this License, the
|
||||
copyright notices, and the license notice saying this License applies
|
||||
to the Document are reproduced in all copies, and that you add no other
|
||||
conditions whatsoever to those of this License. You may not use
|
||||
technical measures to obstruct or control the reading or further
|
||||
copying of the copies you make or distribute. However, you may accept
|
||||
compensation in exchange for copies. If you distribute a large enough
|
||||
number of copies you must also follow the conditions in section 3.
|
||||
|
||||
You may also lend copies, under the same conditions stated above, and
|
||||
you may publicly display copies.
|
||||
|
||||
@item
|
||||
COPYING IN QUANTITY
|
||||
|
||||
If you publish printed copies (or copies in media that commonly have
|
||||
printed covers) of the Document, numbering more than 100, and the
|
||||
Document's license notice requires Cover Texts, you must enclose the
|
||||
copies in covers that carry, clearly and legibly, all these Cover
|
||||
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
|
||||
the back cover. Both covers must also clearly and legibly identify
|
||||
you as the publisher of these copies. The front cover must present
|
||||
the full title with all words of the title equally prominent and
|
||||
visible. You may add other material on the covers in addition.
|
||||
Copying with changes limited to the covers, as long as they preserve
|
||||
the title of the Document and satisfy these conditions, can be treated
|
||||
as verbatim copying in other respects.
|
||||
|
||||
If the required texts for either cover are too voluminous to fit
|
||||
legibly, you should put the first ones listed (as many as fit
|
||||
reasonably) on the actual cover, and continue the rest onto adjacent
|
||||
pages.
|
||||
|
||||
If you publish or distribute Opaque copies of the Document numbering
|
||||
more than 100, you must either include a machine-readable Transparent
|
||||
copy along with each Opaque copy, or state in or with each Opaque copy
|
||||
a computer-network location from which the general network-using
|
||||
public has access to download using public-standard network protocols
|
||||
a complete Transparent copy of the Document, free of added material.
|
||||
If you use the latter option, you must take reasonably prudent steps,
|
||||
when you begin distribution of Opaque copies in quantity, to ensure
|
||||
that this Transparent copy will remain thus accessible at the stated
|
||||
location until at least one year after the last time you distribute an
|
||||
Opaque copy (directly or through your agents or retailers) of that
|
||||
edition to the public.
|
||||
|
||||
It is requested, but not required, that you contact the authors of the
|
||||
Document well before redistributing any large number of copies, to give
|
||||
them a chance to provide you with an updated version of the Document.
|
||||
|
||||
@item
|
||||
MODIFICATIONS
|
||||
|
||||
You may copy and distribute a Modified Version of the Document under
|
||||
the conditions of sections 2 and 3 above, provided that you release
|
||||
the Modified Version under precisely this License, with the Modified
|
||||
Version filling the role of the Document, thus licensing distribution
|
||||
and modification of the Modified Version to whoever possesses a copy
|
||||
of it. In addition, you must do these things in the Modified Version:
|
||||
|
||||
@enumerate A
|
||||
@item
|
||||
Use in the Title Page (and on the covers, if any) a title distinct
|
||||
from that of the Document, and from those of previous versions
|
||||
(which should, if there were any, be listed in the History section
|
||||
of the Document). You may use the same title as a previous version
|
||||
if the original publisher of that version gives permission.
|
||||
|
||||
@item
|
||||
List on the Title Page, as authors, one or more persons or entities
|
||||
responsible for authorship of the modifications in the Modified
|
||||
Version, together with at least five of the principal authors of the
|
||||
Document (all of its principal authors, if it has fewer than five),
|
||||
unless they release you from this requirement.
|
||||
|
||||
@item
|
||||
State on the Title page the name of the publisher of the
|
||||
Modified Version, as the publisher.
|
||||
|
||||
@item
|
||||
Preserve all the copyright notices of the Document.
|
||||
|
||||
@item
|
||||
Add an appropriate copyright notice for your modifications
|
||||
adjacent to the other copyright notices.
|
||||
|
||||
@item
|
||||
Include, immediately after the copyright notices, a license notice
|
||||
giving the public permission to use the Modified Version under the
|
||||
terms of this License, in the form shown in the Addendum below.
|
||||
|
||||
@item
|
||||
Preserve in that license notice the full lists of Invariant Sections
|
||||
and required Cover Texts given in the Document's license notice.
|
||||
|
||||
@item
|
||||
Include an unaltered copy of this License.
|
||||
|
||||
@item
|
||||
Preserve the section Entitled ``History'', Preserve its Title, and add
|
||||
to it an item stating at least the title, year, new authors, and
|
||||
publisher of the Modified Version as given on the Title Page. If
|
||||
there is no section Entitled ``History'' in the Document, create one
|
||||
stating the title, year, authors, and publisher of the Document as
|
||||
given on its Title Page, then add an item describing the Modified
|
||||
Version as stated in the previous sentence.
|
||||
|
||||
@item
|
||||
Preserve the network location, if any, given in the Document for
|
||||
public access to a Transparent copy of the Document, and likewise
|
||||
the network locations given in the Document for previous versions
|
||||
it was based on. These may be placed in the ``History'' section.
|
||||
You may omit a network location for a work that was published at
|
||||
least four years before the Document itself, or if the original
|
||||
publisher of the version it refers to gives permission.
|
||||
|
||||
@item
|
||||
For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
|
||||
the Title of the section, and preserve in the section all the
|
||||
substance and tone of each of the contributor acknowledgements and/or
|
||||
dedications given therein.
|
||||
|
||||
@item
|
||||
Preserve all the Invariant Sections of the Document,
|
||||
unaltered in their text and in their titles. Section numbers
|
||||
or the equivalent are not considered part of the section titles.
|
||||
|
||||
@item
|
||||
Delete any section Entitled ``Endorsements''. Such a section
|
||||
may not be included in the Modified Version.
|
||||
|
||||
@item
|
||||
Do not retitle any existing section to be Entitled ``Endorsements'' or
|
||||
to conflict in title with any Invariant Section.
|
||||
|
||||
@item
|
||||
Preserve any Warranty Disclaimers.
|
||||
@end enumerate
|
||||
|
||||
If the Modified Version includes new front-matter sections or
|
||||
appendices that qualify as Secondary Sections and contain no material
|
||||
copied from the Document, you may at your option designate some or all
|
||||
of these sections as invariant. To do this, add their titles to the
|
||||
list of Invariant Sections in the Modified Version's license notice.
|
||||
These titles must be distinct from any other section titles.
|
||||
|
||||
You may add a section Entitled ``Endorsements'', provided it contains
|
||||
nothing but endorsements of your Modified Version by various
|
||||
parties---for example, statements of peer review or that the text has
|
||||
been approved by an organization as the authoritative definition of a
|
||||
standard.
|
||||
|
||||
You may add a passage of up to five words as a Front-Cover Text, and a
|
||||
passage of up to 25 words as a Back-Cover Text, to the end of the list
|
||||
of Cover Texts in the Modified Version. Only one passage of
|
||||
Front-Cover Text and one of Back-Cover Text may be added by (or
|
||||
through arrangements made by) any one entity. If the Document already
|
||||
includes a cover text for the same cover, previously added by you or
|
||||
by arrangement made by the same entity you are acting on behalf of,
|
||||
you may not add another; but you may replace the old one, on explicit
|
||||
permission from the previous publisher that added the old one.
|
||||
|
||||
The author(s) and publisher(s) of the Document do not by this License
|
||||
give permission to use their names for publicity for or to assert or
|
||||
imply endorsement of any Modified Version.
|
||||
|
||||
@item
|
||||
COMBINING DOCUMENTS
|
||||
|
||||
You may combine the Document with other documents released under this
|
||||
License, under the terms defined in section 4 above for modified
|
||||
versions, provided that you include in the combination all of the
|
||||
Invariant Sections of all of the original documents, unmodified, and
|
||||
list them all as Invariant Sections of your combined work in its
|
||||
license notice, and that you preserve all their Warranty Disclaimers.
|
||||
|
||||
The combined work need only contain one copy of this License, and
|
||||
multiple identical Invariant Sections may be replaced with a single
|
||||
copy. If there are multiple Invariant Sections with the same name but
|
||||
different contents, make the title of each such section unique by
|
||||
adding at the end of it, in parentheses, the name of the original
|
||||
author or publisher of that section if known, or else a unique number.
|
||||
Make the same adjustment to the section titles in the list of
|
||||
Invariant Sections in the license notice of the combined work.
|
||||
|
||||
In the combination, you must combine any sections Entitled ``History''
|
||||
in the various original documents, forming one section Entitled
|
||||
``History''; likewise combine any sections Entitled ``Acknowledgements'',
|
||||
and any sections Entitled ``Dedications''. You must delete all
|
||||
sections Entitled ``Endorsements.''
|
||||
|
||||
@item
|
||||
COLLECTIONS OF DOCUMENTS
|
||||
|
||||
You may make a collection consisting of the Document and other documents
|
||||
released under this License, and replace the individual copies of this
|
||||
License in the various documents with a single copy that is included in
|
||||
the collection, provided that you follow the rules of this License for
|
||||
verbatim copying of each of the documents in all other respects.
|
||||
|
||||
You may extract a single document from such a collection, and distribute
|
||||
it individually under this License, provided you insert a copy of this
|
||||
License into the extracted document, and follow this License in all
|
||||
other respects regarding verbatim copying of that document.
|
||||
|
||||
@item
|
||||
AGGREGATION WITH INDEPENDENT WORKS
|
||||
|
||||
A compilation of the Document or its derivatives with other separate
|
||||
and independent documents or works, in or on a volume of a storage or
|
||||
distribution medium, is called an ``aggregate'' if the copyright
|
||||
resulting from the compilation is not used to limit the legal rights
|
||||
of the compilation's users beyond what the individual works permit.
|
||||
When the Document is included in an aggregate, this License does not
|
||||
apply to the other works in the aggregate which are not themselves
|
||||
derivative works of the Document.
|
||||
|
||||
If the Cover Text requirement of section 3 is applicable to these
|
||||
copies of the Document, then if the Document is less than one half of
|
||||
the entire aggregate, the Document's Cover Texts may be placed on
|
||||
covers that bracket the Document within the aggregate, or the
|
||||
electronic equivalent of covers if the Document is in electronic form.
|
||||
Otherwise they must appear on printed covers that bracket the whole
|
||||
aggregate.
|
||||
|
||||
@item
|
||||
TRANSLATION
|
||||
|
||||
Translation is considered a kind of modification, so you may
|
||||
distribute translations of the Document under the terms of section 4.
|
||||
Replacing Invariant Sections with translations requires special
|
||||
permission from their copyright holders, but you may include
|
||||
translations of some or all Invariant Sections in addition to the
|
||||
original versions of these Invariant Sections. You may include a
|
||||
translation of this License, and all the license notices in the
|
||||
Document, and any Warranty Disclaimers, provided that you also include
|
||||
the original English version of this License and the original versions
|
||||
of those notices and disclaimers. In case of a disagreement between
|
||||
the translation and the original version of this License or a notice
|
||||
or disclaimer, the original version will prevail.
|
||||
|
||||
If a section in the Document is Entitled ``Acknowledgements'',
|
||||
``Dedications'', or ``History'', the requirement (section 4) to Preserve
|
||||
its Title (section 1) will typically require changing the actual
|
||||
title.
|
||||
|
||||
@item
|
||||
TERMINATION
|
||||
|
||||
You may not copy, modify, sublicense, or distribute the Document except
|
||||
as expressly provided for under this License. Any other attempt to
|
||||
copy, modify, sublicense or distribute the Document is void, and will
|
||||
automatically terminate your rights under this License. However,
|
||||
parties who have received copies, or rights, from you under this
|
||||
License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
@item
|
||||
FUTURE REVISIONS OF THIS LICENSE
|
||||
|
||||
The Free Software Foundation may publish new, revised versions
|
||||
of the GNU Free Documentation License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns. See
|
||||
@uref{http://www.gnu.org/copyleft/}.
|
||||
|
||||
Each version of the License is given a distinguishing version number.
|
||||
If the Document specifies that a particular numbered version of this
|
||||
License ``or any later version'' applies to it, you have the option of
|
||||
following the terms and conditions either of that specified version or
|
||||
of any later version that has been published (not as a draft) by the
|
||||
Free Software Foundation. If the Document does not specify a version
|
||||
number of this License, you may choose any version ever published (not
|
||||
as a draft) by the Free Software Foundation.
|
||||
@end enumerate
|
||||
Loading…
x
Reference in New Issue
Block a user