##// END OF EJS Templates
destupdate: have a generic and extensible way to run each step...
Pierre-Yves David -
r26726:8e664961 default
parent child Browse files
Show More
@@ -1,179 +1,186 b''
1 # destutil.py - Mercurial utility function for command destination
1 # destutil.py - Mercurial utility function for command destination
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com> and other
3 # Copyright Matt Mackall <mpm@selenic.com> and other
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from .i18n import _
8 from .i18n import _
9 from . import (
9 from . import (
10 bookmarks,
10 bookmarks,
11 error,
11 error,
12 obsolete,
12 obsolete,
13 )
13 )
14
14
15 def _destupdatevalidate(repo, rev, clean, check):
15 def _destupdatevalidate(repo, rev, clean, check):
16 """validate that the destination comply to various rules
16 """validate that the destination comply to various rules
17
17
18 This exists as its own function to help wrapping from extensions."""
18 This exists as its own function to help wrapping from extensions."""
19 wc = repo[None]
19 wc = repo[None]
20 p1 = wc.p1()
20 p1 = wc.p1()
21 if not clean:
21 if not clean:
22 # Check that the update is linear.
22 # Check that the update is linear.
23 #
23 #
24 # Mercurial do not allow update-merge for non linear pattern
24 # Mercurial do not allow update-merge for non linear pattern
25 # (that would be technically possible but was considered too confusing
25 # (that would be technically possible but was considered too confusing
26 # for user a long time ago)
26 # for user a long time ago)
27 #
27 #
28 # See mercurial.merge.update for details
28 # See mercurial.merge.update for details
29 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
29 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
30 dirty = wc.dirty(missing=True)
30 dirty = wc.dirty(missing=True)
31 foreground = obsolete.foreground(repo, [p1.node()])
31 foreground = obsolete.foreground(repo, [p1.node()])
32 if not repo[rev].node() in foreground:
32 if not repo[rev].node() in foreground:
33 if dirty:
33 if dirty:
34 msg = _("uncommitted changes")
34 msg = _("uncommitted changes")
35 hint = _("commit and merge, or update --clean to"
35 hint = _("commit and merge, or update --clean to"
36 " discard changes")
36 " discard changes")
37 raise error.UpdateAbort(msg, hint=hint)
37 raise error.UpdateAbort(msg, hint=hint)
38 elif not check: # destination is not a descendant.
38 elif not check: # destination is not a descendant.
39 msg = _("not a linear update")
39 msg = _("not a linear update")
40 hint = _("merge or update --check to force update")
40 hint = _("merge or update --check to force update")
41 raise error.UpdateAbort(msg, hint=hint)
41 raise error.UpdateAbort(msg, hint=hint)
42
42
43 def _destupdateobs(repo, clean, check):
43 def _destupdateobs(repo, clean, check):
44 """decide of an update destination from obsolescence markers"""
44 """decide of an update destination from obsolescence markers"""
45 node = None
45 node = None
46 wc = repo[None]
46 wc = repo[None]
47 p1 = wc.p1()
47 p1 = wc.p1()
48 movemark = None
48 movemark = None
49
49
50 if p1.obsolete() and not p1.children():
50 if p1.obsolete() and not p1.children():
51 # allow updating to successors
51 # allow updating to successors
52 successors = obsolete.successorssets(repo, p1.node())
52 successors = obsolete.successorssets(repo, p1.node())
53
53
54 # behavior of certain cases is as follows,
54 # behavior of certain cases is as follows,
55 #
55 #
56 # divergent changesets: update to highest rev, similar to what
56 # divergent changesets: update to highest rev, similar to what
57 # is currently done when there are more than one head
57 # is currently done when there are more than one head
58 # (i.e. 'tip')
58 # (i.e. 'tip')
59 #
59 #
60 # replaced changesets: same as divergent except we know there
60 # replaced changesets: same as divergent except we know there
61 # is no conflict
61 # is no conflict
62 #
62 #
63 # pruned changeset: no update is done; though, we could
63 # pruned changeset: no update is done; though, we could
64 # consider updating to the first non-obsolete parent,
64 # consider updating to the first non-obsolete parent,
65 # similar to what is current done for 'hg prune'
65 # similar to what is current done for 'hg prune'
66
66
67 if successors:
67 if successors:
68 # flatten the list here handles both divergent (len > 1)
68 # flatten the list here handles both divergent (len > 1)
69 # and the usual case (len = 1)
69 # and the usual case (len = 1)
70 successors = [n for sub in successors for n in sub]
70 successors = [n for sub in successors for n in sub]
71
71
72 # get the max revision for the given successors set,
72 # get the max revision for the given successors set,
73 # i.e. the 'tip' of a set
73 # i.e. the 'tip' of a set
74 node = repo.revs('max(%ln)', successors).first()
74 node = repo.revs('max(%ln)', successors).first()
75 if bookmarks.isactivewdirparent(repo):
75 if bookmarks.isactivewdirparent(repo):
76 movemark = repo['.'].node()
76 movemark = repo['.'].node()
77 return node, movemark, None
77 return node, movemark, None
78
78
79 def _destupdatebook(repo, clean, check):
79 def _destupdatebook(repo, clean, check):
80 """decide on an update destination from active bookmark"""
80 """decide on an update destination from active bookmark"""
81 # we also move the active bookmark, if any
81 # we also move the active bookmark, if any
82 activemark = None
82 activemark = None
83 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
83 node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
84 if node is not None:
84 if node is not None:
85 activemark = node
85 activemark = node
86 return node, movemark, activemark
86 return node, movemark, activemark
87
87
88 def _destupdatebranch(repo, clean, check):
88 def _destupdatebranch(repo, clean, check):
89 """decide on an update destination from current branch"""
89 """decide on an update destination from current branch"""
90 wc = repo[None]
90 wc = repo[None]
91 movemark = node = None
91 movemark = node = None
92 try:
92 try:
93 node = repo.branchtip(wc.branch())
93 node = repo.branchtip(wc.branch())
94 if bookmarks.isactivewdirparent(repo):
94 if bookmarks.isactivewdirparent(repo):
95 movemark = repo['.'].node()
95 movemark = repo['.'].node()
96 except error.RepoLookupError:
96 except error.RepoLookupError:
97 if wc.branch() == 'default': # no default branch!
97 if wc.branch() == 'default': # no default branch!
98 node = repo.lookup('tip') # update to tip
98 node = repo.lookup('tip') # update to tip
99 else:
99 else:
100 raise error.Abort(_("branch %s not found") % wc.branch())
100 raise error.Abort(_("branch %s not found") % wc.branch())
101 return node, movemark, None
101 return node, movemark, None
102
102
103 # order in which each step should be evalutated
104 # steps are run until one finds a destination
105 destupdatesteps = ['evolution', 'bookmark', 'branch']
106 # mapping to ease extension overriding steps.
107 destupdatestepmap = {'evolution': _destupdateobs,
108 'bookmark': _destupdatebook,
109 'branch': _destupdatebranch,
110 }
111
103 def destupdate(repo, clean=False, check=False):
112 def destupdate(repo, clean=False, check=False):
104 """destination for bare update operation
113 """destination for bare update operation
105
114
106 return (rev, movemark, activemark)
115 return (rev, movemark, activemark)
107
116
108 - rev: the revision to update to,
117 - rev: the revision to update to,
109 - movemark: node to move the active bookmark from
118 - movemark: node to move the active bookmark from
110 (cf bookmark.calculate update),
119 (cf bookmark.calculate update),
111 - activemark: a bookmark to activate at the end of the update.
120 - activemark: a bookmark to activate at the end of the update.
112 """
121 """
113 node = None
122 node = movemark = activemark = None
114 movemark = activemark = None
115
123
116 node, movemark, activemark = _destupdateobs(repo, clean, check)
124 for step in destupdatesteps:
117 if node is None:
125 node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
118 node, movemark, activemark = _destupdatebook(repo, clean, check)
126 if node is not None:
119 if node is None:
127 break
120 node, movemark, activemark = _destupdatebranch(repo, clean, check)
121 rev = repo[node].rev()
128 rev = repo[node].rev()
122
129
123 _destupdatevalidate(repo, rev, clean, check)
130 _destupdatevalidate(repo, rev, clean, check)
124
131
125 return rev, movemark, activemark
132 return rev, movemark, activemark
126
133
127 def destmerge(repo):
134 def destmerge(repo):
128 if repo._activebookmark:
135 if repo._activebookmark:
129 bmheads = repo.bookmarkheads(repo._activebookmark)
136 bmheads = repo.bookmarkheads(repo._activebookmark)
130 curhead = repo[repo._activebookmark].node()
137 curhead = repo[repo._activebookmark].node()
131 if len(bmheads) == 2:
138 if len(bmheads) == 2:
132 if curhead == bmheads[0]:
139 if curhead == bmheads[0]:
133 node = bmheads[1]
140 node = bmheads[1]
134 else:
141 else:
135 node = bmheads[0]
142 node = bmheads[0]
136 elif len(bmheads) > 2:
143 elif len(bmheads) > 2:
137 raise error.Abort(_("multiple matching bookmarks to merge - "
144 raise error.Abort(_("multiple matching bookmarks to merge - "
138 "please merge with an explicit rev or bookmark"),
145 "please merge with an explicit rev or bookmark"),
139 hint=_("run 'hg heads' to see all heads"))
146 hint=_("run 'hg heads' to see all heads"))
140 elif len(bmheads) <= 1:
147 elif len(bmheads) <= 1:
141 raise error.Abort(_("no matching bookmark to merge - "
148 raise error.Abort(_("no matching bookmark to merge - "
142 "please merge with an explicit rev or bookmark"),
149 "please merge with an explicit rev or bookmark"),
143 hint=_("run 'hg heads' to see all heads"))
150 hint=_("run 'hg heads' to see all heads"))
144 else:
151 else:
145 branch = repo[None].branch()
152 branch = repo[None].branch()
146 bheads = repo.branchheads(branch)
153 bheads = repo.branchheads(branch)
147 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
154 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
148
155
149 if len(nbhs) > 2:
156 if len(nbhs) > 2:
150 raise error.Abort(_("branch '%s' has %d heads - "
157 raise error.Abort(_("branch '%s' has %d heads - "
151 "please merge with an explicit rev")
158 "please merge with an explicit rev")
152 % (branch, len(bheads)),
159 % (branch, len(bheads)),
153 hint=_("run 'hg heads .' to see heads"))
160 hint=_("run 'hg heads .' to see heads"))
154
161
155 parent = repo.dirstate.p1()
162 parent = repo.dirstate.p1()
156 if len(nbhs) <= 1:
163 if len(nbhs) <= 1:
157 if len(bheads) > 1:
164 if len(bheads) > 1:
158 raise error.Abort(_("heads are bookmarked - "
165 raise error.Abort(_("heads are bookmarked - "
159 "please merge with an explicit rev"),
166 "please merge with an explicit rev"),
160 hint=_("run 'hg heads' to see all heads"))
167 hint=_("run 'hg heads' to see all heads"))
161 if len(repo.heads()) > 1:
168 if len(repo.heads()) > 1:
162 raise error.Abort(_("branch '%s' has one head - "
169 raise error.Abort(_("branch '%s' has one head - "
163 "please merge with an explicit rev")
170 "please merge with an explicit rev")
164 % branch,
171 % branch,
165 hint=_("run 'hg heads' to see all heads"))
172 hint=_("run 'hg heads' to see all heads"))
166 msg, hint = _('nothing to merge'), None
173 msg, hint = _('nothing to merge'), None
167 if parent != repo.lookup(branch):
174 if parent != repo.lookup(branch):
168 hint = _("use 'hg update' instead")
175 hint = _("use 'hg update' instead")
169 raise error.Abort(msg, hint=hint)
176 raise error.Abort(msg, hint=hint)
170
177
171 if parent not in bheads:
178 if parent not in bheads:
172 raise error.Abort(_('working directory not at a head revision'),
179 raise error.Abort(_('working directory not at a head revision'),
173 hint=_("use 'hg update' or merge with an "
180 hint=_("use 'hg update' or merge with an "
174 "explicit revision"))
181 "explicit revision"))
175 if parent == nbhs[0]:
182 if parent == nbhs[0]:
176 node = nbhs[-1]
183 node = nbhs[-1]
177 else:
184 else:
178 node = nbhs[0]
185 node = nbhs[0]
179 return repo[node].rev()
186 return repo[node].rev()
General Comments 0
You need to be logged in to leave comments. Login now