updating elisp-vcs
This commit is contained in:
parent
d05cf8cddb
commit
4addd60521
@ -8,7 +8,7 @@ AUTOCONF = autoconf
|
||||
TAR = tar
|
||||
RM = @RM@
|
||||
prefix = /usr/local
|
||||
datarootdir= ${prefix}/share
|
||||
datarootdir= /c/kt/.emacs.d
|
||||
info_dir = ${datarootdir}/info
|
||||
srcdir = .
|
||||
lispdir= /c/kt/.emacs.d/lisp/dvc
|
||||
|
||||
@ -9,13 +9,13 @@ prefix = /usr/local
|
||||
RM = @RM@
|
||||
ETAGS = etags
|
||||
MKDIR_P = /bin/mkdir -p
|
||||
INSTALL = /bin/install -c
|
||||
INSTALL = /c/Tools/gnuwin32/bin/ginstall -c
|
||||
INSTALL_DATA = ${INSTALL} -m 644
|
||||
|
||||
top_srcdir = ..
|
||||
srcdir = .
|
||||
|
||||
datarootdir= ${prefix}/share
|
||||
datarootdir= /c/kt/.emacs.d
|
||||
lispdir = /c/kt/.emacs.d/lisp/dvc
|
||||
|
||||
EMACS_PROG = emacs
|
||||
|
||||
@ -827,7 +827,7 @@ workspace version)."
|
||||
(diff-buffer (dvc-prepare-changes-buffer
|
||||
base
|
||||
modified
|
||||
'file-diff file 'bzr))
|
||||
'file-diff file dvc))
|
||||
(base-buffer
|
||||
(dvc-revision-get-file-in-buffer file base))
|
||||
(modified-buffer
|
||||
|
||||
@ -203,9 +203,7 @@ conflicts, and/or ediff current files."
|
||||
(dvc-fileinfo-add-log-entry prefix))
|
||||
|
||||
((deleted rename-source rename-target)
|
||||
;; typically nothing to do; just need commit
|
||||
(ding)
|
||||
(dvc-fileinfo-next))
|
||||
(dvc-status-ediff))
|
||||
|
||||
(missing
|
||||
;; File is in database, but not in workspace
|
||||
|
||||
@ -257,6 +257,21 @@
|
||||
|
||||
(defvar xmtn-automate--*sessions* '())
|
||||
|
||||
(defun xmtn-automate-cache-session (root)
|
||||
"Create a mtn automate session for workspace ROOT, store it in
|
||||
session cache, return it (for later kill)."
|
||||
(let* ((default-directory (file-name-as-directory root))
|
||||
(key (file-truename default-directory))
|
||||
(session (xmtn-automate--make-session root key)))
|
||||
(setq xmtn-automate--*sessions*
|
||||
(acons key session xmtn-automate--*sessions*))
|
||||
session))
|
||||
|
||||
(defun xmtn-automate-get-cached-session (key)
|
||||
"Return a session from the cache, or nil."
|
||||
;; separate function so we can debug it
|
||||
(cdr (assoc key xmtn-automate--*sessions*)))
|
||||
|
||||
(defmacro* xmtn-automate-with-session ((session-var-or-null root-form &key)
|
||||
&body body)
|
||||
"Call BODY, after ensuring an automate session for ROOT-FORM is active."
|
||||
@ -276,7 +291,7 @@
|
||||
(thunk (gensym)))
|
||||
`(let* ((,root (file-name-as-directory ,root-form))
|
||||
(,key (file-truename ,root))
|
||||
(,session (cdr (assoc ,key xmtn-automate--*sessions*)))
|
||||
(,session (xmtn-automate-get-cached-session ,key))
|
||||
(,thunk (lambda ()
|
||||
(let ((,session-var ,session))
|
||||
,@body))))
|
||||
@ -286,6 +301,10 @@
|
||||
(progn
|
||||
(setq ,session (xmtn-automate--make-session ,root ,key))
|
||||
(let ((xmtn-automate--*sessions*
|
||||
;; note the let-binding here; these sessions are _not_
|
||||
;; available for later commands. use
|
||||
;; xmtn-automate-cache-session to get a persistent
|
||||
;; session.
|
||||
(acons ,key ,session xmtn-automate--*sessions*)))
|
||||
(funcall ,thunk)))
|
||||
(when ,session (xmtn-automate--close-session ,session)))))))
|
||||
@ -446,6 +465,7 @@ Signals an error if output contains zero lines or more than one line."
|
||||
nil)
|
||||
|
||||
(defun xmtn-automate--make-session (root key)
|
||||
(dvc-trace "new session %s" key)
|
||||
(let* ((name (format "xmtn automate session for %s" key)))
|
||||
(let ((session (xmtn-automate--%make-raw-session)))
|
||||
(xmtn-automate--initialize-session session :root root :name name)
|
||||
@ -479,8 +499,7 @@ Signals an error if output contains zero lines or more than one line."
|
||||
;; Process died for some reason - most likely 'mtn not found in
|
||||
;; path'. Don't warn if buffer hasn't been deleted; that
|
||||
;; obscures the real error message
|
||||
;; FIXME: if that is the reason, this assert fails. Disable assertions for now, fix later
|
||||
(xmtn--assert-optional (null (xmtn-automate--session-buffer session))))
|
||||
nil)
|
||||
((ecase (process-status process)
|
||||
(run nil)
|
||||
(exit t)
|
||||
@ -576,7 +595,7 @@ Signals an error if output contains zero lines or more than one line."
|
||||
(exit nil)
|
||||
(signal nil))
|
||||
(accept-process-output process))
|
||||
;;(dvc-trace "Process in root %s terminated" root)
|
||||
(dvc-trace "Process in root %s terminated" root)
|
||||
))
|
||||
(xmtn-automate--initialize-session
|
||||
session
|
||||
|
||||
@ -59,11 +59,22 @@ 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 '.', '..'."
|
||||
(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)))
|
||||
filename))
|
||||
subdirs))
|
||||
(delq nil subdirs)))
|
||||
|
||||
(defvar xmtn--*enable-assertions* nil
|
||||
"Effective at macroexpansion time.")
|
||||
|
||||
;; (setq xmtn--*enable-assertions* t)
|
||||
|
||||
(defmacro xmtn--assert-for-effect (form &rest more-assert-args)
|
||||
(if xmtn--*enable-assertions*
|
||||
`(assert ,form ,@more-assert-args)
|
||||
|
||||
@ -66,8 +66,10 @@
|
||||
|
||||
(defmacro xmtn--set-process-query-on-exit-flag (process value)
|
||||
(if (fboundp 'set-process-query-on-exit-flag)
|
||||
;; emacs 22.2 and greater
|
||||
`(set-process-query-on-exit-flag ,process ,value)
|
||||
`(progn
|
||||
;; emacs 22.1
|
||||
(process-kill-without-query ,process ,value)
|
||||
,value)))
|
||||
|
||||
|
||||
@ -250,8 +250,8 @@ header."
|
||||
(setq xmtn-conflicts-resolved-internal-count (+ 1 xmtn-conflicts-resolved-internal-count))
|
||||
(setf (xmtn-conflicts-conflict-left_resolution conflict) (list 'resolved_internal)))
|
||||
|
||||
((string= "resolved_user_left" symbol)
|
||||
(setf (xmtn-conflicts-conflict-left_resolution conflict) (list 'resolved_left_user (cadar value))))
|
||||
((string= "resolved_user" symbol)
|
||||
(setf (xmtn-conflicts-conflict-left_resolution conflict) (list 'resolved_user (cadar value))))
|
||||
|
||||
(t
|
||||
(error "found %s" symbol)))))))
|
||||
@ -495,7 +495,8 @@ header."
|
||||
"Write EWOC-BUFFER header info in basic-io format to current buffer."
|
||||
(xmtn-basic-io-write-id "left" (with-current-buffer ewoc-buffer xmtn-conflicts-left-revision))
|
||||
(xmtn-basic-io-write-id "right" (with-current-buffer ewoc-buffer xmtn-conflicts-right-revision))
|
||||
(xmtn-basic-io-write-id "ancestor" (with-current-buffer ewoc-buffer xmtn-conflicts-ancestor-revision))
|
||||
(if xmtn-conflicts-ancestor-revision
|
||||
(xmtn-basic-io-write-id "ancestor" (with-current-buffer ewoc-buffer xmtn-conflicts-ancestor-revision)))
|
||||
)
|
||||
|
||||
(defun xmtn-conflicts-write-content (conflict)
|
||||
@ -522,7 +523,7 @@ header."
|
||||
(insert "resolved_keep_left \n"))
|
||||
|
||||
(resolved_user
|
||||
(xmtn-basic-io-write-str "resolved_user_left" (cadr (xmtn-conflicts-conflict-left_resolution conflict))))
|
||||
(xmtn-basic-io-write-str "resolved_user" (cadr (xmtn-conflicts-conflict-left_resolution conflict))))
|
||||
))))
|
||||
|
||||
(defun xmtn-conflicts-write-duplicate_name (conflict)
|
||||
@ -852,19 +853,25 @@ header."
|
||||
(setf (xmtn-conflicts-conflict-right_resolution conflict) (list 'resolved_drop))
|
||||
(ewoc-invalidate xmtn-conflicts-ewoc elem)))
|
||||
|
||||
(defun xmtn-conflicts-resolve-user (side)
|
||||
"Resolve the current conflict by user_SIDE."
|
||||
(defun xmtn-conflicts-resolve-user (resolve-side default-side)
|
||||
"Resolve the current conflict by user_RESOLVE-SIDE. Default to file from DEFAULT-SIDE."
|
||||
(interactive)
|
||||
;; Right is the target workspace in a propagate, and also the current
|
||||
;; workspace in a merge. So default to right_name.
|
||||
(let* ((elem (ewoc-locate xmtn-conflicts-ewoc))
|
||||
(conflict (ewoc-data elem))
|
||||
(result-file (read-file-name "resolution file: " "./" nil t
|
||||
(xmtn-conflicts-conflict-right_name conflict))))
|
||||
(ecase side
|
||||
('left
|
||||
(result-file
|
||||
(expand-file-name
|
||||
(read-file-name "resolution file: "
|
||||
(ecase default-side
|
||||
(left (file-name-as-directory xmtn-conflicts-left-work))
|
||||
(right (file-name-as-directory xmtn-conflicts-right-work)))
|
||||
nil t
|
||||
(ecase default-side
|
||||
(left (xmtn-conflicts-conflict-left_name conflict))
|
||||
(right (xmtn-conflicts-conflict-right_name conflict)))))))
|
||||
(ecase resolve-side
|
||||
(left
|
||||
(setf (xmtn-conflicts-conflict-left_resolution conflict) (list 'resolved_user result-file)))
|
||||
('right
|
||||
(right
|
||||
(setf (xmtn-conflicts-conflict-right_resolution conflict) (list 'resolved_user result-file)))
|
||||
)
|
||||
(ewoc-invalidate xmtn-conflicts-ewoc elem)))
|
||||
@ -987,32 +994,42 @@ 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 [?9] '(menu-item "9) drop"
|
||||
(define-key map [?b] '(menu-item "b) drop"
|
||||
xmtn-conflicts-resolve-drop_right
|
||||
:visible (xmtn-conflicts-resolve-drop_rightp)))
|
||||
(define-key map [?8] '(menu-item "8) rename"
|
||||
(define-key map [?a] '(menu-item "a) rename"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-rename 'right))
|
||||
:visible (xmtn-conflicts-resolve-rename_rightp)))
|
||||
(define-key map [?7] '(menu-item "7) file"
|
||||
(define-key map [?9] '(menu-item "9) right file"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-user 'right))
|
||||
(xmtn-conflicts-resolve-user 'right 'right))
|
||||
:visible (xmtn-conflicts-resolve-user_rightp)))
|
||||
(define-key map [?6] '(menu-item "6) keep"
|
||||
(define-key map [?8] '(menu-item "8) left file"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-user 'right 'left))
|
||||
:visible (xmtn-conflicts-resolve-user_rightp)))
|
||||
(define-key map [?7] '(menu-item "7) keep"
|
||||
xmtn-conflicts-resolve-keep_right
|
||||
:visible (xmtn-conflicts-resolve-keep_rightp)))
|
||||
(define-key map [?5] '(menu-item "5) ediff"
|
||||
(define-key map [?6] '(menu-item "6) ediff"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-ediff 'right))
|
||||
:visible (xmtn-conflicts-resolve-user_rightp)))
|
||||
|
||||
(define-key map [?4] '(menu-item "4) file"
|
||||
(define-key map [?5] '(menu-item "5) right file"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-user 'left))
|
||||
(xmtn-conflicts-resolve-user 'left 'right))
|
||||
:visible (xmtn-conflicts-resolve-user_leftp)))
|
||||
(define-key map [?4] '(menu-item "4) left file"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(xmtn-conflicts-resolve-user 'left 'left))
|
||||
:visible (xmtn-conflicts-resolve-user_leftp)))
|
||||
(define-key map [?3] '(menu-item "3) drop"
|
||||
xmtn-conflicts-resolve-drop_left
|
||||
@ -1058,17 +1075,17 @@ non-nil, show log-edit buffer in other frame."
|
||||
(insert ": ")
|
||||
))
|
||||
|
||||
(defun xmtn-conflicts-do-propagate ()
|
||||
(defun xmtn-conflicts-do-propagate (&optional cached-branch)
|
||||
"Perform propagate on revisions in current conflict buffer."
|
||||
(interactive)
|
||||
(save-some-buffers t); log buffer
|
||||
(xmtn-propagate-from xmtn-conflicts-left-branch))
|
||||
(xmtn-propagate-from xmtn-conflicts-left-branch cached-branch))
|
||||
|
||||
(defun xmtn-conflicts-do-merge ()
|
||||
"Perform merge on revisions in current conflict buffer."
|
||||
(interactive)
|
||||
(save-some-buffers t); log buffer
|
||||
(xmtn-dvc-merge))
|
||||
(xmtn-dvc-merge-1 default-directory nil))
|
||||
|
||||
(defun xmtn-conflicts-ediff-resolution-ws ()
|
||||
"Ediff current resolution file against workspace."
|
||||
@ -1105,6 +1122,7 @@ non-nil, show log-edit buffer in other frame."
|
||||
"`xmtn-conflicts' menu"
|
||||
`("Mtn-conflicts"
|
||||
["Clear resolution" xmtn-conflicts-clear-resolution t]
|
||||
["Ediff resolution to ws" xmtn-conflicts-ediff-resolution-ws t]
|
||||
["Propagate" xmtn-conflicts-do-propagate t]
|
||||
["Merge" xmtn-conflicts-do-merge t]
|
||||
["Update" dvc-update t]
|
||||
@ -1137,13 +1155,15 @@ non-nil, show log-edit buffer in other frame."
|
||||
|
||||
(defconst xmtn-conflicts-opts-file "_MTN/dvc-conflicts-opts")
|
||||
|
||||
(defun xmtn-conflicts-save-opts (left-work right-work)
|
||||
(defun xmtn-conflicts-save-opts (left-work right-work &optional left-branch right-branch)
|
||||
"Store LEFT-WORK, RIGHT-WORK in `xmtn-conflicts-opts-file', for
|
||||
retrieval by `xmtn-conflicts-load-opts'."
|
||||
(let ((xmtn-conflicts-left-work left-work)
|
||||
(xmtn-conflicts-right-work right-work)
|
||||
(xmtn-conflicts-left-branch (xmtn--tree-default-branch left-work))
|
||||
(xmtn-conflicts-right-branch (xmtn--tree-default-branch right-work)))
|
||||
(xmtn-conflicts-left-branch (or left-branch
|
||||
(xmtn--tree-default-branch left-work)))
|
||||
(xmtn-conflicts-right-branch (or right-branch
|
||||
(xmtn--tree-default-branch right-work))))
|
||||
|
||||
(dvc-save-state (list 'xmtn-conflicts-left-work
|
||||
'xmtn-conflicts-left-branch
|
||||
@ -1174,19 +1194,17 @@ to right. Stores conflict file in RIGHT-WORK/_MTN."
|
||||
'xmtn
|
||||
(list "conflicts" "store" left-rev right-rev)
|
||||
:finished (lambda (output error status arguments)
|
||||
(xmtn-dvc-log-clean)
|
||||
(xmtn-conflicts-review default-directory))
|
||||
|
||||
:error (lambda (output error status arguments)
|
||||
(xmtn-dvc-log-clean)
|
||||
(pop-to-buffer error))
|
||||
)))
|
||||
|
||||
(defun xmtn-check-workspace-for-propagate (work)
|
||||
(defun xmtn-check-workspace-for-propagate (work cached-branch)
|
||||
"Check that workspace WORK is ready for propagate.
|
||||
It must be merged, and should be at the head revision, and have no local changes."
|
||||
(let* ((default-directory work)
|
||||
(heads (xmtn--heads default-directory nil))
|
||||
(heads (xmtn--heads default-directory cached-branch))
|
||||
(base (xmtn--get-base-revision-hash-id-or-null default-directory)))
|
||||
|
||||
(message "checking %s for multiple heads, base not head" work)
|
||||
@ -1250,17 +1268,20 @@ workspace."
|
||||
(setq left-work (dvc-read-project-tree-maybe "Propagate from (workspace directory): " left-work))
|
||||
(setq right-work (dvc-read-project-tree-maybe "to (workspace directory): " right-work))
|
||||
|
||||
(xmtn-check-workspace-for-propagate left-work)
|
||||
(xmtn-check-workspace-for-propagate right-work)
|
||||
(let ((left-branch (xmtn--tree-default-branch left-work))
|
||||
(right-branch (xmtn--tree-default-branch right-work)))
|
||||
|
||||
(xmtn-check-propagate-needed left-work right-work)
|
||||
(xmtn-check-workspace-for-propagate left-work left-branch)
|
||||
(xmtn-check-workspace-for-propagate right-work right-branch)
|
||||
|
||||
(message "computing conflicts")
|
||||
(xmtn-check-propagate-needed left-work right-work)
|
||||
|
||||
(xmtn-conflicts-1 left-work
|
||||
(car (xmtn--heads left-work nil))
|
||||
(message "computing conflicts")
|
||||
|
||||
(xmtn-conflicts-1 left-work
|
||||
(car (xmtn--heads left-work left-branch))
|
||||
right-work
|
||||
(car (xmtn--heads right-work nil))))
|
||||
(car (xmtn--heads right-work right-branch)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-conflicts-merge ()
|
||||
@ -1304,6 +1325,8 @@ workspace."
|
||||
|
||||
(if (file-exists-p "_MTN/resolutions")
|
||||
(dired-delete-file "_MTN/resolutions" 'always))
|
||||
|
||||
(message "conflicts cleaned")
|
||||
))
|
||||
|
||||
(provide 'xmtn-conflicts)
|
||||
|
||||
@ -285,12 +285,6 @@ the file before saving."
|
||||
(if (file-exists-p log-edit-file)
|
||||
(concat "--message-file=" log-edit-file))))
|
||||
|
||||
(defun xmtn-dvc-log-clean ()
|
||||
"Delete xmtn log file."
|
||||
(let ((log-edit-file "_MTN/log"))
|
||||
(if (file-exists-p log-edit-file)
|
||||
(delete-file log-edit-file))))
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-dvc-log-edit-done ()
|
||||
(let* ((root default-directory)
|
||||
@ -351,11 +345,9 @@ the file before saving."
|
||||
"--depth=0"
|
||||
"--" normalized-files))))
|
||||
:error (lambda (output error status arguments)
|
||||
(xmtn-dvc-log-clean)
|
||||
(dvc-default-error-function output error
|
||||
status arguments))
|
||||
:killed (lambda (output error status arguments)
|
||||
(xmtn-dvc-log-clean)
|
||||
(dvc-default-killed-function output error
|
||||
status arguments))
|
||||
:finished (lambda (output error status arguments)
|
||||
@ -363,13 +355,18 @@ the file before saving."
|
||||
;; Monotone creates an empty log file when the
|
||||
;; commit was successful. Let's not interfere with
|
||||
;; that. (Calling `dvc-log-close' would.)
|
||||
(xmtn-dvc-log-clean)
|
||||
|
||||
;; we'd like to delete log-edit-buffer here, but
|
||||
;; we can't do that from a process sentinel
|
||||
|
||||
(dvc-diff-clear-buffers 'xmtn
|
||||
default-directory
|
||||
"* Just committed! Please refresh buffer"
|
||||
(xmtn--status-header
|
||||
default-directory
|
||||
(xmtn--get-base-revision-hash-id-or-null default-directory)))))
|
||||
(xmtn--get-base-revision-hash-id-or-null default-directory)))
|
||||
))
|
||||
|
||||
;; Show message _after_ spawning command to override DVC's
|
||||
;; debugging message.
|
||||
(message "%s... " progress-message))
|
||||
@ -1224,22 +1221,25 @@ finished."
|
||||
(check-type revision-hash-id xmtn--hash-id)
|
||||
(xmtn--command-output-lines-future root `("disapprove" ,revision-hash-id)))
|
||||
|
||||
(defun xmtn--do-update (root target-revision-hash-id)
|
||||
(defun xmtn--do-update (root target-revision-hash-id post-update-p)
|
||||
(check-type root string)
|
||||
(check-type target-revision-hash-id xmtn--hash-id)
|
||||
(lexical-let ((progress-message (format "Updating tree %s to revision %s"
|
||||
root target-revision-hash-id)))
|
||||
root target-revision-hash-id))
|
||||
(post-update-p post-update-p))
|
||||
(let ((command `("update" "--move-conflicting-paths" ,(concat "--revision=" target-revision-hash-id)))
|
||||
(post-process
|
||||
(lambda ()
|
||||
(message "%s... done" progress-message)
|
||||
(dvc-revert-some-buffers default-directory)
|
||||
(dvc-diff-clear-buffers 'xmtn
|
||||
default-directory
|
||||
"* Just updated; please refresh buffer"
|
||||
(xmtn--status-header
|
||||
default-directory
|
||||
(xmtn--get-base-revision-hash-id-or-null default-directory)))))
|
||||
(if post-update-p
|
||||
(progn
|
||||
(dvc-revert-some-buffers default-directory)
|
||||
(dvc-diff-clear-buffers 'xmtn
|
||||
default-directory
|
||||
"* Just updated; please refresh buffer"
|
||||
(xmtn--status-header
|
||||
default-directory
|
||||
(xmtn--get-base-revision-hash-id-or-null default-directory)))))))
|
||||
)
|
||||
|
||||
(message "%s..." progress-message)
|
||||
@ -1248,28 +1248,32 @@ finished."
|
||||
(funcall post-process))
|
||||
nil))
|
||||
|
||||
(defun xmtn--update (root target-revision-hash-id)
|
||||
(defun xmtn--update (root target-revision-hash-id check-id-p no-ding)
|
||||
;; mtn will just give an innocuous message if already updated, which
|
||||
;; the user won't see. So check that here - it's fast.
|
||||
(when (equal (xmtn--get-base-revision-hash-id root) target-revision-hash-id)
|
||||
(error "Tree %s is already based on target revision %s"
|
||||
root target-revision-hash-id))
|
||||
(dvc-save-some-buffers root)
|
||||
(xmtn--do-update root target-revision-hash-id))
|
||||
;; Don't throw an error; upper level might be doing other directories as well.
|
||||
(if (and check-id-p
|
||||
(equal (xmtn--get-base-revision-hash-id root) target-revision-hash-id))
|
||||
(progn
|
||||
(unless no-ding (ding))
|
||||
(message "Tree %s is already based on target revision %s"
|
||||
root target-revision-hash-id))
|
||||
(dvc-save-some-buffers root)
|
||||
(xmtn--do-update root target-revision-hash-id check-id-p)))
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-dvc-update (&optional revision-id)
|
||||
(defun xmtn-dvc-update (&optional revision-id no-ding)
|
||||
(let ((root (dvc-tree-root)))
|
||||
(xmtn-automate-with-session (nil root)
|
||||
(if revision-id
|
||||
(xmtn--update root (xmtn--revision-hash-id revision-id))
|
||||
(xmtn--update root (xmtn--revision-hash-id revision-id) t no-ding)
|
||||
|
||||
(let* ((branch (xmtn--tree-default-branch root))
|
||||
(heads (xmtn--heads root branch)))
|
||||
(case (length heads)
|
||||
(0 (assert nil))
|
||||
(1
|
||||
(xmtn--update root (first heads)))
|
||||
(xmtn--update root (first heads) t no-ding))
|
||||
|
||||
(t
|
||||
;; User can choose one head from a revlist, or merge them.
|
||||
@ -1279,12 +1283,13 @@ finished."
|
||||
branch (length heads))))))))
|
||||
nil)
|
||||
|
||||
(defun xmtn-propagate-from (other)
|
||||
(defun xmtn-propagate-from (other &optional cached-branch)
|
||||
"Propagate from OTHER branch to local tree branch."
|
||||
(interactive "MPropagate from branch: ")
|
||||
(let*
|
||||
((root (dvc-tree-root))
|
||||
(local-branch (xmtn--tree-default-branch root))
|
||||
(local-branch (or cached-branch
|
||||
(xmtn--tree-default-branch root)))
|
||||
(resolve-conflicts
|
||||
(if (file-exists-p (concat root "/_MTN/conflicts"))
|
||||
(progn
|
||||
@ -1318,31 +1323,35 @@ finished."
|
||||
(xmtn--refresh-status-header display-buffer)
|
||||
(message "%s... done" msg)))))))
|
||||
|
||||
(defun xmtn-dvc-merge-1 (root refresh-status)
|
||||
(lexical-let ((refresh-status refresh-status))
|
||||
(xmtn-automate-with-session
|
||||
(nil root)
|
||||
(xmtn--run-command-async
|
||||
root
|
||||
(list
|
||||
"merge"
|
||||
(if (file-exists-p (concat root "/_MTN/conflicts"))
|
||||
"--resolve-conflicts-file=_MTN/conflicts")
|
||||
(xmtn-dvc-log-message))
|
||||
:finished (lambda (output error status arguments)
|
||||
(if refresh-status
|
||||
(xmtn--refresh-status-header (current-buffer))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-dvc-merge (&optional other)
|
||||
(if other
|
||||
(xmtn-propagate-from other)
|
||||
;; else merge heads
|
||||
(let* ((root (dvc-tree-root))
|
||||
(resolve-conflicts
|
||||
(if (file-exists-p (concat root "/_MTN/conflicts"))
|
||||
(progn
|
||||
"--resolve-conflicts-file=_MTN/conflicts"))))
|
||||
(lexical-let
|
||||
((display-buffer (current-buffer)))
|
||||
(xmtn-automate-with-session
|
||||
(nil root)
|
||||
(let* ((branch (xmtn--tree-default-branch root))
|
||||
(heads (xmtn--heads root branch)))
|
||||
(case (length heads)
|
||||
(0 (assert nil))
|
||||
(1
|
||||
(message "already merged"))
|
||||
(t
|
||||
(xmtn--run-command-that-might-invoke-merger
|
||||
root
|
||||
(list "merge" resolve-conflicts (xmtn-dvc-log-message))
|
||||
(lambda () (xmtn--refresh-status-header display-buffer))))))))))
|
||||
(branch (xmtn--tree-default-branch root))
|
||||
(heads (xmtn--heads root branch)))
|
||||
(case (length heads)
|
||||
(0 (assert nil))
|
||||
(1
|
||||
(message "already merged"))
|
||||
(t
|
||||
(xmtn-dvc-merge-1 root t)))))
|
||||
nil)
|
||||
|
||||
;;;###autoload
|
||||
|
||||
@ -152,9 +152,27 @@ See file commentary for details."
|
||||
,base-revision-hash-id
|
||||
,(1- num))))))
|
||||
|
||||
(defun xmtn--get-parent-revision-hash-id (root hash-id local-branch)
|
||||
(check-type hash-id xmtn--hash-id)
|
||||
(let ((parents (xmtn-automate-simple-command-output-lines root `("parents"
|
||||
,hash-id))))
|
||||
(case (length parents)
|
||||
(0 (error "Revision has no parents: %s" hash-id))
|
||||
(1 (let ((parent (first parents)))
|
||||
(assert (typep parent 'xmtn--hash-id))
|
||||
parent))
|
||||
(t
|
||||
;; If this revision is the result of a propagate, there are two parents, one of which is on the local branch
|
||||
(let ((first-parent-branch (xmtn--branch-of root (first parents))))
|
||||
(if (equal local-branch first-parent-branch)
|
||||
(first parents)
|
||||
(second parents)))
|
||||
))))
|
||||
|
||||
(defun xmtn--resolve--previous-revision (root backend-id num)
|
||||
(check-type num (integer 0 *))
|
||||
(let ((resolved-id (xmtn--resolve-backend-id root backend-id)))
|
||||
(let ((local-branch (xmtn--tree-default-branch root))
|
||||
(resolved-id (xmtn--resolve-backend-id root backend-id)))
|
||||
(if (zerop num)
|
||||
resolved-id
|
||||
(ecase (first resolved-id)
|
||||
@ -170,7 +188,7 @@ See file commentary for details."
|
||||
(check-type hash-id xmtn--hash-id)
|
||||
(loop repeat num
|
||||
;; If two parents of this rev, use parent on same branch as rev.
|
||||
do (setq hash-id (xmtn--get-parent-revision-hash-id root hash-id t)))
|
||||
do (setq hash-id (xmtn--get-parent-revision-hash-id root hash-id local-branch)))
|
||||
`(revision ,hash-id)))))))
|
||||
|
||||
(defun xmtn--error-unless-revision-exists (root hash-id)
|
||||
@ -216,31 +234,6 @@ must be a workspace."
|
||||
)))))
|
||||
result))
|
||||
|
||||
(defun xmtn--get-parent-revision-hash-id (root hash-id &optional multi-parent-use-local-branch)
|
||||
(check-type hash-id xmtn--hash-id)
|
||||
(let ((parents (xmtn-automate-simple-command-output-lines root `("parents"
|
||||
,hash-id))))
|
||||
(case (length parents)
|
||||
(0 (error "Revision has no parents: %s" hash-id))
|
||||
(1 (let ((parent (first parents)))
|
||||
(assert (typep parent 'xmtn--hash-id))
|
||||
parent))
|
||||
(t
|
||||
(if multi-parent-use-local-branch
|
||||
;; If this revision is the result of a propagate, there are two parents, one of which is on the local branch
|
||||
(let ((local-branch (xmtn--tree-default-branch root))
|
||||
(first-parent-branch (xmtn--branch-of root (first parents))))
|
||||
(if (equal local-branch first-parent-branch)
|
||||
(first parents)
|
||||
(second parents)))
|
||||
;; Otherwise, just error. Depending on the context, we should
|
||||
;; prompt which parent is desired, or operate on all of them.
|
||||
;; This function is too low-level to decide what to do, though.
|
||||
;; Need to wait for use cases.
|
||||
(error "Revision has more than one parent (%s): %s"
|
||||
(length parents)
|
||||
hash-id))))))
|
||||
|
||||
(defun xmtn--get-base-revision-hash-id-or-null (root)
|
||||
(let ((hash-id (xmtn-automate-simple-command-output-line
|
||||
root `("get_base_revision_id"))))
|
||||
|
||||
@ -26,19 +26,35 @@
|
||||
|
||||
(eval-when-compile
|
||||
;; these have functions we use
|
||||
(require 'xmtn-base)
|
||||
(require 'xmtn-conflicts))
|
||||
|
||||
(defvar xmtn-propagate-from-root ""
|
||||
"Buffer-local variable holding `from' root directory.")
|
||||
(make-variable-buffer-local 'xmtn-propagate-from-root)
|
||||
(put 'xmtn-propagate-from-root 'permanent-local t)
|
||||
|
||||
(defvar xmtn-propagate-to-root ""
|
||||
"Buffer-local variable holding `to' root directory.")
|
||||
(make-variable-buffer-local 'xmtn-propagate-to-root)
|
||||
(put 'xmtn-propagate-to-root 'permanent-local t)
|
||||
|
||||
(defvar xmtn-propagate-ewoc nil
|
||||
"Buffer-local ewoc for displaying propagations.
|
||||
All xmtn-propagate functions operate on this ewoc.
|
||||
The elements must all be of class xmtn-propagate-data.")
|
||||
(make-variable-buffer-local 'xmtn-propagate-ewoc)
|
||||
(put 'xmtn-propagate-ewoc 'permanent-local t)
|
||||
|
||||
(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
|
||||
to-name ;
|
||||
from-branch ; branch name (assumed never changes)
|
||||
to-branch ;
|
||||
from-session ; mtn automate session
|
||||
to-session ;
|
||||
need-refresh ; nil | t; if an async process was started that invalidates state data
|
||||
from-head-rev ; nil | mtn rev string; current head revision; nil if multiple heads
|
||||
to-head-rev ;
|
||||
@ -47,9 +63,9 @@
|
||||
from-heads ; 'at-head | 'need-update | 'need-merge)
|
||||
to-heads ;
|
||||
(from-local-changes
|
||||
'need-scan) ; 'need-scan | 'need-status | 'ok
|
||||
'need-scan) ; 'need-scan | 'need-commit | 'ok
|
||||
(to-local-changes
|
||||
'need-scan) ; once these are changed from 'need-scan, no action changes it .
|
||||
'need-scan) ;
|
||||
(conflicts
|
||||
'need-scan) ; 'need-scan | 'need-resolve | 'need-review-resolve-internal | 'ok
|
||||
)
|
||||
@ -60,6 +76,14 @@
|
||||
(defun xmtn-propagate-to-work (data)
|
||||
(concat xmtn-propagate-to-root (xmtn-propagate-data-to-work data)))
|
||||
|
||||
(defun xmtn-propagate-from-name ()
|
||||
"Display name for current `from' workspace."
|
||||
(xmtn-propagate-data-from-name (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
|
||||
(defun xmtn-propagate-to-name ()
|
||||
"Display name for current `to' workspace."
|
||||
(xmtn-propagate-data-to-name (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
|
||||
(defun xmtn-propagate-need-refresh (elem data)
|
||||
(setf (xmtn-propagate-data-need-refresh data) t)
|
||||
(ewoc-invalidate xmtn-propagate-ewoc elem))
|
||||
@ -77,112 +101,127 @@
|
||||
(if (xmtn-propagate-data-need-refresh data)
|
||||
(insert (dvc-face-add " need refresh\n" 'dvc-conflict))
|
||||
|
||||
(ecase (xmtn-propagate-data-from-local-changes data)
|
||||
(need-scan (insert " local changes unknown " (xmtn-propagate-data-from-name data) "\n"))
|
||||
(need-commit
|
||||
(insert (dvc-face-add (concat " need commit " (xmtn-propagate-data-from-name data) "\n")
|
||||
'dvc-header)))
|
||||
(ok nil))
|
||||
|
||||
(ecase (xmtn-propagate-data-to-local-changes data)
|
||||
(need-scan (insert " local changes unknown " (xmtn-propagate-data-to-name data) "\n"))
|
||||
(need-commit
|
||||
(insert (dvc-face-add (concat " need commit " (xmtn-propagate-data-to-name data) "\n")
|
||||
'dvc-header)))
|
||||
(ok nil))
|
||||
|
||||
(ecase (xmtn-propagate-data-from-heads data)
|
||||
(at-head nil)
|
||||
(need-update
|
||||
(insert (dvc-face-add (concat " need update " (xmtn-propagate-data-from-name data) "\n")
|
||||
'dvc-conflict)))
|
||||
(need-merge
|
||||
(insert (dvc-face-add (concat " need merge " (xmtn-propagate-data-from-name data) "\n")
|
||||
'dvc-conflict))))
|
||||
|
||||
(ecase (xmtn-propagate-data-to-heads data)
|
||||
(at-head nil)
|
||||
(need-update
|
||||
(insert (dvc-face-add (concat " need update " (xmtn-propagate-data-to-name data) "\n")
|
||||
'dvc-conflict)))
|
||||
(need-merge
|
||||
(insert (dvc-face-add (concat " need merge " (xmtn-propagate-data-to-name data) "\n")
|
||||
'dvc-conflict))))
|
||||
|
||||
(if (xmtn-propagate-data-propagate-needed data)
|
||||
(progn
|
||||
(ecase (xmtn-propagate-data-from-local-changes data)
|
||||
(need-scan (insert " from local changes unknown\n"))
|
||||
(need-status (insert (dvc-face-add " need dvc-status from\n" 'dvc-header)))
|
||||
(ok nil))
|
||||
|
||||
(ecase (xmtn-propagate-data-to-local-changes data)
|
||||
(need-scan (insert " to local changes unknown\n"))
|
||||
(need-status (insert (dvc-face-add " need dvc-status to\n" 'dvc-header)))
|
||||
(ok nil))
|
||||
(if (and (eq 'at-head (xmtn-propagate-data-from-heads data))
|
||||
(eq 'at-head (xmtn-propagate-data-to-heads data)))
|
||||
(ecase (xmtn-propagate-data-conflicts data)
|
||||
(need-scan
|
||||
(insert "conflicts need scan\n"))
|
||||
(need-resolve
|
||||
(insert (dvc-face-add " need resolve conflicts\n" 'dvc-conflict)))
|
||||
(need-review-resolve-internal
|
||||
(insert (dvc-face-add " need review resolve internal\n" 'dvc-header))
|
||||
(insert (dvc-face-add " need propagate\n" 'dvc-conflict)))
|
||||
(ok
|
||||
(insert (dvc-face-add " need propagate\n" 'dvc-conflict)))))
|
||||
|
||||
(ecase (xmtn-propagate-data-from-heads data)
|
||||
(at-head nil)
|
||||
(need-update (insert (dvc-face-add " need dvc-missing from\n" 'dvc-conflict)))
|
||||
(need-merge (insert (dvc-face-add " need xmtn-heads from\n" 'dvc-conflict))))
|
||||
(if (eq 'at-head (xmtn-propagate-data-to-heads data))
|
||||
(insert " need clean\n"))
|
||||
))
|
||||
;; ewoc ought to do this, but it doesn't
|
||||
(redisplay))
|
||||
|
||||
(ecase (xmtn-propagate-data-to-heads data)
|
||||
(at-head nil)
|
||||
(need-update (insert (dvc-face-add " need dvc-missing to\n" 'dvc-conflict)))
|
||||
(need-merge (insert (dvc-face-add " need xmtn-heads to\n" 'dvc-conflict))))
|
||||
|
||||
|
||||
(if (and (eq 'at-head (xmtn-propagate-data-from-heads data))
|
||||
(eq 'at-head (xmtn-propagate-data-to-heads data)))
|
||||
(ecase (xmtn-propagate-data-conflicts data)
|
||||
(need-scan
|
||||
(insert "conflicts need scan\n"))
|
||||
(need-resolve
|
||||
(insert (dvc-face-add " need resolve conflicts\n" 'dvc-conflict)))
|
||||
(need-review-resolve-internal
|
||||
(insert (dvc-face-add " need review resolve internal\n" 'dvc-header))
|
||||
(insert (dvc-face-add " need propagate\n" 'dvc-conflict)))
|
||||
(ok
|
||||
(insert (dvc-face-add " need propagate\n" 'dvc-conflict)))))
|
||||
)
|
||||
|
||||
;; propagate not needed
|
||||
(ecase (xmtn-propagate-data-from-local-changes data)
|
||||
(need-scan (insert " from local changes unknown\n"))
|
||||
(need-status (insert (dvc-face-add " need dvc-status from\n" 'dvc-header)))
|
||||
(ok nil))
|
||||
|
||||
(ecase (xmtn-propagate-data-to-local-changes data)
|
||||
(need-scan (insert " to local changes unknown\n"))
|
||||
(need-status (insert (dvc-face-add " need dvc-status to\n" 'dvc-header)))
|
||||
(ok nil))
|
||||
|
||||
(ecase (xmtn-propagate-data-to-heads data)
|
||||
(at-head nil)
|
||||
(need-update (insert (dvc-face-add " need dvc-update to\n" 'dvc-conflict)))
|
||||
(need-merge (insert (dvc-face-add " programmer error!\n" 'dvc-conflict))))
|
||||
)))
|
||||
|
||||
(defvar xmtn-propagate-ewoc nil
|
||||
"Buffer-local ewoc for displaying propagations.
|
||||
All xmtn-propagate functions operate on this ewoc.
|
||||
The elements must all be of class xmtn-propagate-data.")
|
||||
(make-variable-buffer-local 'xmtn-propagate-ewoc)
|
||||
(defun xmtn-kill-conflicts-buffer (data)
|
||||
(if (buffer-live-p (xmtn-propagate-data-conflicts-buffer data))
|
||||
(let ((buffer (xmtn-propagate-data-conflicts-buffer data)))
|
||||
(with-current-buffer buffer (save-buffer))
|
||||
(kill-buffer buffer))))
|
||||
|
||||
(defun xmtn-propagate-clean ()
|
||||
"Clean current workspace, delete from ewoc"
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(with-current-buffer (xmtn-propagate-data-conflicts-buffer data)
|
||||
(xmtn-conflicts-clean (xmtn-propagate-from-work data)))
|
||||
|
||||
;; only one conflicts file and buffer
|
||||
(xmtn-conflicts-clean (xmtn-propagate-to-work data))
|
||||
(xmtn-kill-conflicts-buffer data)
|
||||
|
||||
(let ((inhibit-read-only t))
|
||||
(ewoc-delete xmtn-propagate-ewoc elem))))
|
||||
|
||||
(defun xmtn-propagate-cleanp ()
|
||||
"Non-nil if clean is appropriate for current workspace."
|
||||
(let ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
;; don't check need-refresh here; allow deleting after just doing
|
||||
;; final required action in another buffer. Or we've just started,
|
||||
;; but the user knows it's ok.
|
||||
(and (member (xmtn-propagate-data-from-local-changes data) '(need-scan ok))
|
||||
(member (xmtn-propagate-data-to-local-changes data) '(need-scan ok))
|
||||
(not (xmtn-propagate-data-propagate-needed data))
|
||||
(eq 'at-head (xmtn-propagate-data-to-heads data)))))
|
||||
(member (xmtn-propagate-data-to-heads data) '(need-scan at-head)))))
|
||||
|
||||
(defun xmtn-propagate-do-refresh-one ()
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-propagate-refresh-one data)
|
||||
(xmtn-propagate-refresh-one data (or current-prefix-arg
|
||||
(not (xmtn-propagate-data-need-refresh data))))
|
||||
(ewoc-invalidate xmtn-propagate-ewoc elem)))
|
||||
|
||||
(defun xmtn-propagate-refreshp ()
|
||||
"Non-nil if refresh is appropriate for current workspace."
|
||||
(let ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(xmtn-propagate-data-need-refresh data)))
|
||||
(or (xmtn-propagate-data-need-refresh data)
|
||||
(eq 'need-scan (xmtn-propagate-data-from-local-changes data))
|
||||
(eq 'need-scan (xmtn-propagate-data-to-local-changes data)))))
|
||||
|
||||
(defun xmtn-propagate-update ()
|
||||
(defun xmtn-propagate-update-to ()
|
||||
"Update current workspace."
|
||||
(interactive)
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(with-current-buffer (xmtn-propagate-data-conflicts-buffer data)
|
||||
(xmtn-dvc-update))
|
||||
(xmtn-propagate-refresh-one data)
|
||||
(xmtn--update (xmtn-propagate-to-work data)
|
||||
(xmtn-propagate-data-to-head-rev data)
|
||||
nil t)
|
||||
(xmtn-propagate-refresh-one data nil)
|
||||
(ewoc-invalidate xmtn-propagate-ewoc elem)))
|
||||
|
||||
(defun xmtn-propagate-updatep ()
|
||||
"Non-nil if update is appropriate for current workspace."
|
||||
(let ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(not (xmtn-propagate-data-propagate-needed data))
|
||||
(eq 'need-update (xmtn-propagate-data-to-heads data)))))
|
||||
(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-propagate ()
|
||||
"Propagate current workspace."
|
||||
@ -192,8 +231,8 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(with-current-buffer (xmtn-propagate-data-conflicts-buffer data)
|
||||
(let ((xmtn-confirm-operation nil))
|
||||
(xmtn-conflicts-do-propagate)))
|
||||
(xmtn-propagate-refresh-one data)
|
||||
(xmtn-conflicts-do-propagate (xmtn-propagate-data-to-branch data))))
|
||||
(xmtn-propagate-refresh-one data nil)
|
||||
(ewoc-invalidate xmtn-propagate-ewoc elem)))
|
||||
|
||||
(defun xmtn-propagate-propagatep ()
|
||||
@ -212,6 +251,7 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(let* ((elem (ewoc-locate xmtn-propagate-ewoc))
|
||||
(data (ewoc-data elem)))
|
||||
(xmtn-propagate-need-refresh elem data)
|
||||
(setf (xmtn-propagate-data-conflicts data) 'ok)
|
||||
(pop-to-buffer (xmtn-propagate-data-conflicts-buffer data))))
|
||||
|
||||
(defun xmtn-propagate-resolve-conflictsp ()
|
||||
@ -230,6 +270,12 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(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-kill-conflicts-buffer data)
|
||||
|
||||
(setf (xmtn-propagate-data-to-local-changes data) 'ok)
|
||||
(xmtn-status (xmtn-propagate-to-work data))))
|
||||
|
||||
@ -246,7 +292,7 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(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-status)))))
|
||||
'(need-scan need-commit)))))
|
||||
|
||||
(defun xmtn-propagate-status-from ()
|
||||
"Run xmtn-status on current `from' workspace."
|
||||
@ -270,7 +316,7 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(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-status)))))
|
||||
'(need-scan need-commit)))))
|
||||
|
||||
(defun xmtn-propagate-missing-to ()
|
||||
"Run xmtn-missing on current `to' workspace."
|
||||
@ -284,7 +330,6 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
"Non-nil if xmtn-missing is appropriate for current `to' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(xmtn-propagate-data-propagate-needed data)
|
||||
(eq 'need-update (xmtn-propagate-data-to-heads data)))))
|
||||
|
||||
(defun xmtn-propagate-missing-from ()
|
||||
@ -299,7 +344,6 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
"Non-nil if xmtn-missing is appropriate for current `from' workspace."
|
||||
(let* ((data (ewoc-data (ewoc-locate xmtn-propagate-ewoc))))
|
||||
(and (not (xmtn-propagate-data-need-refresh data))
|
||||
(xmtn-propagate-data-propagate-needed data)
|
||||
(eq 'need-update (xmtn-propagate-data-from-heads data)))))
|
||||
|
||||
(defun xmtn-propagate-heads-to ()
|
||||
@ -315,7 +359,6 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
"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))
|
||||
(xmtn-propagate-data-propagate-needed data)
|
||||
(eq 'need-merge (xmtn-propagate-data-to-heads data)))))
|
||||
|
||||
(defun xmtn-propagate-heads-from ()
|
||||
@ -331,7 +374,6 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
"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))
|
||||
(xmtn-propagate-data-propagate-needed data)
|
||||
(eq 'need-merge (xmtn-propagate-data-from-heads data)))))
|
||||
|
||||
(defvar xmtn-propagate-actions-map
|
||||
@ -342,37 +384,40 @@ 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 [?a] '(menu-item "a) update"
|
||||
xmtn-propagate-update
|
||||
:visible (xmtn-propagate-updatep)))
|
||||
(define-key map [?9] '(menu-item "9) propagate"
|
||||
(define-key map [?b] '(menu-item "b) propagate"
|
||||
xmtn-propagate-propagate
|
||||
:visible (xmtn-propagate-propagatep)))
|
||||
(define-key map [?8] '(menu-item "8) resolve conflicts"
|
||||
(define-key map [?a] '(menu-item "a) resolve conflicts"
|
||||
xmtn-propagate-resolve-conflicts
|
||||
:visible (xmtn-propagate-resolve-conflictsp)))
|
||||
(define-key map [?7] '(menu-item "7) ignore local changes to"
|
||||
(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 [?6] '(menu-item "6) ignore local changes from"
|
||||
(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 [?5] '(menu-item "5) status to"
|
||||
xmtn-propagate-status-to
|
||||
:visible (xmtn-propagate-status-top)))
|
||||
(define-key map [?4] '(menu-item "4) status from"
|
||||
xmtn-propagate-status-from
|
||||
:visible (xmtn-propagate-status-fromp)))
|
||||
(define-key map [?3] '(menu-item "3) dvc-missing to"
|
||||
(define-key map [?7] '(menu-item (concat "7) dvc-missing " (xmtn-propagate-to-name))
|
||||
xmtn-propagate-missing-to
|
||||
:visible (xmtn-propagate-missing-top)))
|
||||
(define-key map [?2] '(menu-item "2) dvc-missing from"
|
||||
(define-key map [?6] '(menu-item (concat "6) dvc-missing " (xmtn-propagate-from-name))
|
||||
xmtn-propagate-missing-from
|
||||
:visible (xmtn-propagate-missing-fromp)))
|
||||
(define-key map [?1] '(menu-item "1) xmtn-heads to"
|
||||
(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))
|
||||
xmtn-propagate-status-to
|
||||
:visible (xmtn-propagate-status-top)))
|
||||
(define-key map [?2] '(menu-item (concat "2) commit " (xmtn-propagate-from-name))
|
||||
xmtn-propagate-status-from
|
||||
:visible (xmtn-propagate-status-fromp)))
|
||||
(define-key map [?1] '(menu-item (concat "1) xmtn-heads " (xmtn-propagate-to-name))
|
||||
xmtn-propagate-heads-to
|
||||
:visible (xmtn-propagate-heads-top)))
|
||||
(define-key map [?0] '(menu-item "0) xmtn-heads from"
|
||||
(define-key map [?0] '(menu-item (concat "0) xmtn-heads " (xmtn-propagate-from-name))
|
||||
xmtn-propagate-heads-from
|
||||
:visible (xmtn-propagate-heads-fromp)))
|
||||
map)
|
||||
@ -395,7 +440,6 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
"Major mode to propagate multiple workspaces."
|
||||
(setq dvc-buffer-current-active-dvc 'xmtn)
|
||||
(setq buffer-read-only nil)
|
||||
(setq xmtn-propagate-ewoc (ewoc-create 'xmtn-propagate-printer))
|
||||
|
||||
;; don't do normal clean up stuff
|
||||
(set (make-local-variable 'before-save-hook) nil)
|
||||
@ -404,12 +448,15 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(dvc-install-buffer-menu)
|
||||
(setq buffer-read-only t)
|
||||
(buffer-disable-undo)
|
||||
(set-buffer-modified-p nil))
|
||||
(set-buffer-modified-p nil)
|
||||
(xmtn-propagate-refresh)
|
||||
(xmtn-propagate-next nil t))
|
||||
|
||||
(defun xmtn-propagate-local-changes (work)
|
||||
"Value for xmtn-propagate-data-local-changes for WORK."
|
||||
(message "checking %s for local changes" work)
|
||||
(let ((default-directory work))
|
||||
(let ((default-directory work)
|
||||
result)
|
||||
|
||||
(dvc-run-dvc-sync
|
||||
'xmtn
|
||||
@ -424,11 +471,28 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(set-buffer output)
|
||||
(goto-char (point-min))
|
||||
(if (search-forward "patch" (point-max) t)
|
||||
'need-status
|
||||
'ok))
|
||||
(setq result 'need-commit)
|
||||
(setq result 'ok)))
|
||||
|
||||
:error (lambda (output error status arguments)
|
||||
(pop-to-buffer error))))
|
||||
(pop-to-buffer error)))
|
||||
|
||||
(if (eq result 'ok)
|
||||
;; check for unknown
|
||||
(dvc-run-dvc-sync
|
||||
'xmtn
|
||||
(list "ls" "unknown")
|
||||
:finished (lambda (output error status arguments)
|
||||
(message "") ; clear minibuffer
|
||||
(set-buffer output)
|
||||
(if (not (= (point-min) (point-max)))
|
||||
(setq result 'need-commit)
|
||||
(setq result 'ok)))
|
||||
|
||||
:error (lambda (output error status arguments)
|
||||
(pop-to-buffer error))))
|
||||
|
||||
result)
|
||||
)
|
||||
|
||||
(defun xmtn-propagate-needed (data)
|
||||
@ -438,50 +502,58 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(from-head-rev (xmtn-propagate-data-from-head-rev data))
|
||||
(to-head-rev (xmtn-propagate-data-to-head-rev data)))
|
||||
|
||||
;; If from has no descendants, then:
|
||||
;; 1) to branched off earlier, and propagate is needed
|
||||
;; 2) propagate was just done but required no changes; no propagate needed
|
||||
;;
|
||||
(if (string= from-head-rev to-head-rev)
|
||||
;; case 2
|
||||
(if (or (not from-head-rev)
|
||||
(not to-head-rev))
|
||||
;; multiple heads; can't propagate
|
||||
(setq result nil)
|
||||
(let ((descendents (xmtn-automate-simple-command-output-lines from-work (list "descendents" from-head-rev)))
|
||||
done)
|
||||
(if (not descendents)
|
||||
;; case 1
|
||||
(setq result t)
|
||||
(while (and descendents (not done))
|
||||
(if (string= to-head-rev (car descendents))
|
||||
(progn
|
||||
(setq result nil)
|
||||
(setq done t)))
|
||||
(setq descendents (cdr descendents))))))
|
||||
|
||||
;; 1) to branched off earlier, and propagate is needed
|
||||
;; 2) propagate was just done but required no changes; no propagate needed
|
||||
;;
|
||||
(if (string= from-head-rev to-head-rev)
|
||||
;; case 2
|
||||
(setq result nil)
|
||||
(let ((descendents (xmtn-automate-simple-command-output-lines from-work (list "descendents" from-head-rev)))
|
||||
done)
|
||||
(if (not descendents)
|
||||
;; case 1
|
||||
(setq result t)
|
||||
(while (and descendents (not done))
|
||||
(if (string= to-head-rev (car descendents))
|
||||
(progn
|
||||
(setq result nil)
|
||||
(setq done t)))
|
||||
(setq descendents (cdr descendents)))))))
|
||||
result
|
||||
))
|
||||
|
||||
(defun xmtn-propagate-conflicts-buffer (from-work from-head-rev to-work to-head-rev)
|
||||
(defun xmtn-propagate-conflicts-buffer (data)
|
||||
"Return a conflicts buffer for FROM-WORK, TO-WORK (absolute paths)."
|
||||
(let ((conflicts-buffer (dvc-get-buffer 'xmtn 'conflicts to-work)))
|
||||
(let ((from-work (xmtn-propagate-from-work data))
|
||||
(from-head-rev (xmtn-propagate-data-from-head-rev data))
|
||||
(to-work (xmtn-propagate-to-work data))
|
||||
(to-head-rev (xmtn-propagate-data-to-head-rev data)))
|
||||
|
||||
(or conflicts-buffer
|
||||
(or (dvc-get-buffer 'xmtn 'conflicts to-work)
|
||||
(let ((default-directory to-work))
|
||||
(if (not (file-exists-p "_MTN/conflicts"))
|
||||
(progn
|
||||
;; create conflicts file
|
||||
(xmtn-conflicts-save-opts from-work to-work)
|
||||
(xmtn-conflicts-save-opts
|
||||
from-work
|
||||
to-work
|
||||
(xmtn-propagate-data-from-branch data)
|
||||
(xmtn-propagate-data-to-branch data))
|
||||
(dvc-run-dvc-sync
|
||||
'xmtn
|
||||
(list "conflicts" "store" from-head-rev to-head-rev)
|
||||
:finished (lambda (output error status arguments)
|
||||
(xmtn-dvc-log-clean)
|
||||
|
||||
:error (lambda (output error status arguments)
|
||||
(xmtn-dvc-log-clean)
|
||||
(pop-to-buffer error))))))
|
||||
:error (lambda (output error status arguments)
|
||||
(pop-to-buffer error)))))
|
||||
;; create conflicts buffer
|
||||
(save-excursion
|
||||
(let ((dvc-switch-to-buffer-first nil))
|
||||
(xmtn-conflicts-review default-directory)
|
||||
(xmtn-conflicts-review to-work)
|
||||
(current-buffer)))))))
|
||||
|
||||
(defun xmtn-propagate-conflicts (data)
|
||||
@ -497,17 +569,12 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(xmtn-conflicts-update-counts))
|
||||
|
||||
;; recreate conflicts
|
||||
(if (buffer-live-p (xmtn-propagate-data-conflicts-buffer data))
|
||||
(kill-buffer (xmtn-propagate-data-conflicts-buffer data)))
|
||||
(xmtn-kill-conflicts-buffer data)
|
||||
|
||||
(xmtn-conflicts-clean (xmtn-propagate-to-work data))
|
||||
|
||||
(setf (xmtn-propagate-data-conflicts-buffer data)
|
||||
(xmtn-propagate-conflicts-buffer
|
||||
(xmtn-propagate-from-work data)
|
||||
(xmtn-propagate-data-from-head-rev data)
|
||||
(xmtn-propagate-to-work data)
|
||||
(xmtn-propagate-data-to-head-rev data)))
|
||||
(xmtn-propagate-conflicts-buffer data))
|
||||
)
|
||||
|
||||
(with-current-buffer (xmtn-propagate-data-conflicts-buffer data)
|
||||
@ -517,12 +584,19 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
'ok)
|
||||
'need-resolve))))
|
||||
|
||||
(defun xmtn-propagate-refresh-one (data)
|
||||
(defun xmtn-propagate-refresh-one (data refresh-local-changes)
|
||||
"Refresh DATA."
|
||||
(let ((from-work (xmtn-propagate-from-work data))
|
||||
(to-work (xmtn-propagate-to-work data)))
|
||||
|
||||
(let ((heads (xmtn--heads from-work nil))
|
||||
(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)
|
||||
(1
|
||||
@ -534,7 +608,7 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(setf (xmtn-propagate-data-from-head-rev data) nil)
|
||||
(setf (xmtn-propagate-data-from-heads data) 'need-merge))))
|
||||
|
||||
(let ((heads (xmtn--heads to-work nil))
|
||||
(let ((heads (xmtn--heads to-work (xmtn-propagate-data-to-branch data)))
|
||||
(to-base-rev (xmtn--get-base-revision-hash-id-or-null to-work)))
|
||||
(case (length heads)
|
||||
(1
|
||||
@ -549,23 +623,25 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
(setf (xmtn-propagate-data-propagate-needed data)
|
||||
(xmtn-propagate-needed data))
|
||||
|
||||
(if (xmtn-propagate-data-propagate-needed data)
|
||||
(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-status)
|
||||
((need-scan need-commit)
|
||||
(setf (xmtn-propagate-data-from-local-changes data) (xmtn-propagate-local-changes from-work)))
|
||||
(ok nil))
|
||||
|
||||
(ecase (xmtn-propagate-data-to-local-changes data)
|
||||
((need-scan need-status)
|
||||
((need-scan need-commit)
|
||||
(setf (xmtn-propagate-data-to-local-changes data) (xmtn-propagate-local-changes to-work)))
|
||||
(ok nil))
|
||||
(ok nil))))
|
||||
|
||||
(setf (xmtn-propagate-data-conflicts data)
|
||||
(xmtn-propagate-conflicts data)))
|
||||
(if (xmtn-propagate-data-propagate-needed data)
|
||||
;; can't compute conflicts if propagate not needed
|
||||
(setf (xmtn-propagate-data-conflicts data)
|
||||
(xmtn-propagate-conflicts data))
|
||||
|
||||
;; propagate not needed
|
||||
(setf (xmtn-propagate-data-conflicts data) 'need-scan))
|
||||
|
||||
(setf (xmtn-propagate-data-need-refresh data) nil))
|
||||
@ -574,35 +650,53 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
t)
|
||||
|
||||
(defun xmtn-propagate-refresh ()
|
||||
"Refresh status of each ewoc element."
|
||||
"Refresh status of each ewoc element. With prefix arg, reset local changes status to `unknown'."
|
||||
(interactive)
|
||||
(ewoc-map 'xmtn-propagate-refresh-one xmtn-propagate-ewoc)
|
||||
(ewoc-map 'xmtn-propagate-refresh-one xmtn-propagate-ewoc current-prefix-arg)
|
||||
;; leaves point at (point-min)
|
||||
(xmtn-propagate-next t)
|
||||
(message "done"))
|
||||
|
||||
(defun xmtn--filter-non-dir (dir)
|
||||
"Return list of all directories in DIR, excluding '.', '..'."
|
||||
(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)))
|
||||
filename))
|
||||
subdirs))
|
||||
(delq nil subdirs)))
|
||||
(defun xmtn-propagate-make-data (from-workspace to-workspace from-name to-name)
|
||||
"FROM-WORKSPACE, TO-WORKSPACE are relative names"
|
||||
(let* ((from-work (concat xmtn-propagate-from-root from-workspace))
|
||||
;; cached sessions not working (yet)
|
||||
;;(from-session (xmtn-automate-cache-session from-work))
|
||||
(to-work (concat xmtn-propagate-to-root to-workspace))
|
||||
;;(to-session (xmtn-automate-cache-session to-work))
|
||||
)
|
||||
|
||||
(ewoc-enter-last
|
||||
xmtn-propagate-ewoc
|
||||
(make-xmtn-propagate-data
|
||||
:from-work from-workspace
|
||||
:to-work to-workspace
|
||||
:from-name from-name
|
||||
:to-name to-name
|
||||
:from-branch (xmtn--tree-default-branch from-work)
|
||||
:to-branch (xmtn--tree-default-branch to-work)
|
||||
:from-session nil ;; from-session
|
||||
:to-session nil ;; to-session
|
||||
:need-refresh t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun xmtn-propagate-multiple (from-dir to-dir)
|
||||
"Show all actions needed to propagate all projects under FROM-DIR to TO-DIR."
|
||||
(defun xmtn-propagate-multiple (from-dir to-dir &optional workspaces)
|
||||
"Show all actions needed to propagate projects under FROM-DIR
|
||||
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): ")
|
||||
(let ((from-workspaces (xmtn--filter-non-dir from-dir))
|
||||
(to-workspaces (xmtn--filter-non-dir to-dir)))
|
||||
(setq from-dir (substitute-in-file-name from-dir))
|
||||
(setq to-dir (substitute-in-file-name to-dir))
|
||||
(let ((from-workspaces (or workspaces
|
||||
(xmtn--filter-non-dir from-dir)))
|
||||
(to-workspaces (or workspaces
|
||||
(xmtn--filter-non-dir to-dir))))
|
||||
|
||||
(pop-to-buffer (get-buffer-create "*xmtn-propagate*"))
|
||||
(xmtn-propagate-mode)
|
||||
(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
|
||||
xmtn-propagate-ewoc
|
||||
@ -613,40 +707,41 @@ The elements must all be of class xmtn-propagate-data.")
|
||||
"")
|
||||
(dolist (workspace from-workspaces)
|
||||
(if (member workspace to-workspaces)
|
||||
(ewoc-enter-last xmtn-propagate-ewoc
|
||||
(make-xmtn-propagate-data
|
||||
:to-work workspace
|
||||
:from-work workspace
|
||||
:need-refresh t))))
|
||||
|
||||
(xmtn-propagate-refresh)
|
||||
(xmtn-propagate-next)))
|
||||
(xmtn-propagate-make-data
|
||||
workspace
|
||||
workspace
|
||||
(file-name-nondirectory (directory-file-name xmtn-propagate-from-root))
|
||||
(file-name-nondirectory (directory-file-name xmtn-propagate-to-root)))))
|
||||
(redisplay)
|
||||
(xmtn-propagate-mode)))
|
||||
|
||||
;;;###autoload
|
||||
(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): ")
|
||||
(pop-to-buffer (get-buffer-create "*xmtn-propagate*"))
|
||||
(xmtn-propagate-mode)
|
||||
(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) "../")))
|
||||
|
||||
(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)
|
||||
)
|
||||
"")
|
||||
(ewoc-enter-last xmtn-propagate-ewoc
|
||||
(make-xmtn-propagate-data
|
||||
:from-work (file-name-nondirectory from-work)
|
||||
:to-work (file-name-nondirectory to-work)
|
||||
:need-refresh t))
|
||||
|
||||
(xmtn-propagate-refresh)
|
||||
(xmtn-propagate-next))
|
||||
(setq from-work (substitute-in-file-name from-work))
|
||||
(setq to-work (substitute-in-file-name to-work))
|
||||
(let ((default-directory to-work)
|
||||
(from-session (xmtn-automate-cache-session from-work))
|
||||
(to-session (xmtn-automate-cache-session to-work)))
|
||||
(pop-to-buffer (get-buffer-create "*xmtn-propagate*"))
|
||||
(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)))
|
||||
|
||||
(provide 'xmtn-propagate)
|
||||
|
||||
|
||||
@ -349,30 +349,47 @@ arg; root. Result is of the form:
|
||||
"If point is on a revision that has two parents, show conflicts
|
||||
from the merge."
|
||||
;; IMPROVEME: We just use the xmtn conflicts machinery for now. It
|
||||
;; would be better if we had a read-only version of it. And a way to
|
||||
;; compare to the actual result.
|
||||
;; would be better if we had a read-only version of it.
|
||||
(interactive)
|
||||
(let ((changelog (car (xmtn--revlist-entry-changelogs (dvc-revlist-entry-patch-struct (dvc-revlist-current-patch)))))
|
||||
left-start left-end left-rev right-start right-end right-rev)
|
||||
start end left-branch left-rev right-branch right-rev)
|
||||
;; string-match does _not_ set up match-strings properly, so we do this instead
|
||||
(cond
|
||||
((string= (substring changelog 0 9) "propagate")
|
||||
(setq left-start (+ 6 (string-match "(head" changelog)))
|
||||
(setq left-end (string-match ")" changelog left-start))
|
||||
(setq right-start (+ 6 (string-match "(head .*)" changelog left-start)))
|
||||
(setq right-end (string-match ")" changelog right-start)))
|
||||
(setq start (+ 1 (string-match "'" changelog)))
|
||||
(setq end (string-match "'" changelog start))
|
||||
(setq left-branch (substring changelog start end))
|
||||
|
||||
(setq start (+ 6 (string-match "(head" changelog end)))
|
||||
(setq end (string-match ")" changelog start))
|
||||
(setq left-rev (substring changelog start end))
|
||||
|
||||
(setq start (+ 1 (string-match "'" changelog end)))
|
||||
(setq end (string-match "'" changelog start))
|
||||
(setq right-branch (substring changelog start end))
|
||||
|
||||
(setq start (+ 6 (string-match "(head .*)" changelog end)))
|
||||
(setq end (string-match ")" changelog start))
|
||||
(setq right-rev (substring changelog start end)))
|
||||
|
||||
|
||||
((string= (substring changelog 0 5) "merge")
|
||||
(setq left-start (+ 4 (string-match "of" changelog)))
|
||||
(setq left-end (string-match "'" changelog left-start))
|
||||
(setq right-start (+ 5 (string-match "and" changelog left-start)))
|
||||
(setq right-end (string-match "'" changelog right-start)))
|
||||
(setq start (+ 4 (string-match "of" changelog)))
|
||||
(setq end (string-match "'" changelog start))
|
||||
(setq left-rev (substring changelog start (1- end)))
|
||||
|
||||
(setq start (+ 5 (string-match "and" changelog start)))
|
||||
(setq end (string-match "'" changelog start))
|
||||
(setq right-rev (substring changelog start (1- end))))
|
||||
|
||||
(t
|
||||
(error "not on a two parent revision")))
|
||||
|
||||
(setq left-rev (substring changelog left-start (1- left-end)))
|
||||
(setq right-rev (substring changelog right-start (1- right-end)))
|
||||
(xmtn-conflicts-save-opts
|
||||
(read-file-name "left work: ")
|
||||
(read-file-name "right work: ")
|
||||
left-branch
|
||||
right-branch)
|
||||
|
||||
(dvc-run-dvc-async
|
||||
'xmtn
|
||||
@ -380,11 +397,11 @@ from the merge."
|
||||
:finished (lambda (output error status arguments)
|
||||
(let ((conflicts-buffer (dvc-get-buffer-create 'xmtn 'conflicts default-directory)))
|
||||
(pop-to-buffer conflicts-buffer)
|
||||
(xmtn-conflicts-load-opts)
|
||||
(set (make-local-variable 'after-insert-file-functions) '(xmtn-conflicts-after-insert-file))
|
||||
(insert-file-contents "_MTN/conflicts" t)))
|
||||
|
||||
:error (lambda (output error status arguments)
|
||||
(xmtn-dvc-log-clean)
|
||||
(pop-to-buffer error)))))
|
||||
|
||||
;;;###autoload
|
||||
@ -599,7 +616,7 @@ To be invoked from an xmtn revlist buffer."
|
||||
(let* ((root (dvc-tree-root))
|
||||
(entry (dvc-revlist-current-patch-struct))
|
||||
(target-hash-id (xmtn--revlist-entry-revision-hash-id entry)))
|
||||
(xmtn--update root target-hash-id)))
|
||||
(xmtn--update root target-hash-id nil nil)))
|
||||
|
||||
;; Being able to conveniently disapprove whole batches of revisions
|
||||
;; is going to be a lot of fun.
|
||||
|
||||
@ -8,13 +8,13 @@ PACKAGE_VERSION = 0
|
||||
# location of required programms
|
||||
RM = @RM@
|
||||
MKDIR_P = /bin/mkdir -p
|
||||
INSTALL = /bin/install -c
|
||||
INSTALL = /c/Tools/gnuwin32/bin/ginstall -c
|
||||
INSTALL_DATA = ${INSTALL} -m 644
|
||||
MAKEINFO = makeinfo
|
||||
TEXI2DVI = texi2dvi
|
||||
|
||||
# Other settings
|
||||
datarootdir = ${prefix}/share
|
||||
datarootdir = /c/kt/.emacs.d
|
||||
prefix = /usr/local
|
||||
info_dir = ${datarootdir}/info
|
||||
|
||||
@ -33,7 +33,7 @@ Makefile: $(srcdir)/Makefile.in ../config.status
|
||||
ii = install-info
|
||||
|
||||
install: uninstall info
|
||||
$(MKDIR_P) -m 0755 $(info_dir)
|
||||
echo $(MKDIR_P) -m 0755 $(info_dir)
|
||||
@for i in dvc.info* ; do \
|
||||
echo Installing $$i ; \
|
||||
$(INSTALL_DATA) $$i $(info_dir) ; \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user