##// END OF EJS Templates
py3: use stringutil.forcebytestr() to convert error messages to bytes...
Pulkit Goyal -
r37603:df4fd29c default
parent child Browse files
Show More
@@ -1,395 +1,396 b''
1 # subrepoutil.py - sub-repository operations and substate handling
1 # subrepoutil.py - sub-repository operations and substate handling
2 #
2 #
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import posixpath
12 import posixpath
13 import re
13 import re
14
14
15 from .i18n import _
15 from .i18n import _
16 from . import (
16 from . import (
17 config,
17 config,
18 error,
18 error,
19 filemerge,
19 filemerge,
20 pathutil,
20 pathutil,
21 phases,
21 phases,
22 util,
22 util,
23 )
23 )
24 from .utils import (
24 from .utils import (
25 stringutil,
25 stringutil,
26 )
26 )
27
27
28 nullstate = ('', '', 'empty')
28 nullstate = ('', '', 'empty')
29
29
30 def state(ctx, ui):
30 def state(ctx, ui):
31 """return a state dict, mapping subrepo paths configured in .hgsub
31 """return a state dict, mapping subrepo paths configured in .hgsub
32 to tuple: (source from .hgsub, revision from .hgsubstate, kind
32 to tuple: (source from .hgsub, revision from .hgsubstate, kind
33 (key in types dict))
33 (key in types dict))
34 """
34 """
35 p = config.config()
35 p = config.config()
36 repo = ctx.repo()
36 repo = ctx.repo()
37 def read(f, sections=None, remap=None):
37 def read(f, sections=None, remap=None):
38 if f in ctx:
38 if f in ctx:
39 try:
39 try:
40 data = ctx[f].data()
40 data = ctx[f].data()
41 except IOError as err:
41 except IOError as err:
42 if err.errno != errno.ENOENT:
42 if err.errno != errno.ENOENT:
43 raise
43 raise
44 # handle missing subrepo spec files as removed
44 # handle missing subrepo spec files as removed
45 ui.warn(_("warning: subrepo spec file \'%s\' not found\n") %
45 ui.warn(_("warning: subrepo spec file \'%s\' not found\n") %
46 repo.pathto(f))
46 repo.pathto(f))
47 return
47 return
48 p.parse(f, data, sections, remap, read)
48 p.parse(f, data, sections, remap, read)
49 else:
49 else:
50 raise error.Abort(_("subrepo spec file \'%s\' not found") %
50 raise error.Abort(_("subrepo spec file \'%s\' not found") %
51 repo.pathto(f))
51 repo.pathto(f))
52 if '.hgsub' in ctx:
52 if '.hgsub' in ctx:
53 read('.hgsub')
53 read('.hgsub')
54
54
55 for path, src in ui.configitems('subpaths'):
55 for path, src in ui.configitems('subpaths'):
56 p.set('subpaths', path, src, ui.configsource('subpaths', path))
56 p.set('subpaths', path, src, ui.configsource('subpaths', path))
57
57
58 rev = {}
58 rev = {}
59 if '.hgsubstate' in ctx:
59 if '.hgsubstate' in ctx:
60 try:
60 try:
61 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
61 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
62 l = l.lstrip()
62 l = l.lstrip()
63 if not l:
63 if not l:
64 continue
64 continue
65 try:
65 try:
66 revision, path = l.split(" ", 1)
66 revision, path = l.split(" ", 1)
67 except ValueError:
67 except ValueError:
68 raise error.Abort(_("invalid subrepository revision "
68 raise error.Abort(_("invalid subrepository revision "
69 "specifier in \'%s\' line %d")
69 "specifier in \'%s\' line %d")
70 % (repo.pathto('.hgsubstate'), (i + 1)))
70 % (repo.pathto('.hgsubstate'), (i + 1)))
71 rev[path] = revision
71 rev[path] = revision
72 except IOError as err:
72 except IOError as err:
73 if err.errno != errno.ENOENT:
73 if err.errno != errno.ENOENT:
74 raise
74 raise
75
75
76 def remap(src):
76 def remap(src):
77 for pattern, repl in p.items('subpaths'):
77 for pattern, repl in p.items('subpaths'):
78 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
78 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
79 # does a string decode.
79 # does a string decode.
80 repl = stringutil.escapestr(repl)
80 repl = stringutil.escapestr(repl)
81 # However, we still want to allow back references to go
81 # However, we still want to allow back references to go
82 # through unharmed, so we turn r'\\1' into r'\1'. Again,
82 # through unharmed, so we turn r'\\1' into r'\1'. Again,
83 # extra escapes are needed because re.sub string decodes.
83 # extra escapes are needed because re.sub string decodes.
84 repl = re.sub(br'\\\\([0-9]+)', br'\\\1', repl)
84 repl = re.sub(br'\\\\([0-9]+)', br'\\\1', repl)
85 try:
85 try:
86 src = re.sub(pattern, repl, src, 1)
86 src = re.sub(pattern, repl, src, 1)
87 except re.error as e:
87 except re.error as e:
88 raise error.Abort(_("bad subrepository pattern in %s: %s")
88 raise error.Abort(_("bad subrepository pattern in %s: %s")
89 % (p.source('subpaths', pattern), e))
89 % (p.source('subpaths', pattern),
90 stringutil.forcebytestr(e)))
90 return src
91 return src
91
92
92 state = {}
93 state = {}
93 for path, src in p[''].items():
94 for path, src in p[''].items():
94 kind = 'hg'
95 kind = 'hg'
95 if src.startswith('['):
96 if src.startswith('['):
96 if ']' not in src:
97 if ']' not in src:
97 raise error.Abort(_('missing ] in subrepository source'))
98 raise error.Abort(_('missing ] in subrepository source'))
98 kind, src = src.split(']', 1)
99 kind, src = src.split(']', 1)
99 kind = kind[1:]
100 kind = kind[1:]
100 src = src.lstrip() # strip any extra whitespace after ']'
101 src = src.lstrip() # strip any extra whitespace after ']'
101
102
102 if not util.url(src).isabs():
103 if not util.url(src).isabs():
103 parent = _abssource(repo, abort=False)
104 parent = _abssource(repo, abort=False)
104 if parent:
105 if parent:
105 parent = util.url(parent)
106 parent = util.url(parent)
106 parent.path = posixpath.join(parent.path or '', src)
107 parent.path = posixpath.join(parent.path or '', src)
107 parent.path = posixpath.normpath(parent.path)
108 parent.path = posixpath.normpath(parent.path)
108 joined = str(parent)
109 joined = str(parent)
109 # Remap the full joined path and use it if it changes,
110 # Remap the full joined path and use it if it changes,
110 # else remap the original source.
111 # else remap the original source.
111 remapped = remap(joined)
112 remapped = remap(joined)
112 if remapped == joined:
113 if remapped == joined:
113 src = remap(src)
114 src = remap(src)
114 else:
115 else:
115 src = remapped
116 src = remapped
116
117
117 src = remap(src)
118 src = remap(src)
118 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind)
119 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind)
119
120
120 return state
121 return state
121
122
122 def writestate(repo, state):
123 def writestate(repo, state):
123 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
124 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
124 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)
125 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)
125 if state[s][1] != nullstate[1]]
126 if state[s][1] != nullstate[1]]
126 repo.wwrite('.hgsubstate', ''.join(lines), '')
127 repo.wwrite('.hgsubstate', ''.join(lines), '')
127
128
128 def submerge(repo, wctx, mctx, actx, overwrite, labels=None):
129 def submerge(repo, wctx, mctx, actx, overwrite, labels=None):
129 """delegated from merge.applyupdates: merging of .hgsubstate file
130 """delegated from merge.applyupdates: merging of .hgsubstate file
130 in working context, merging context and ancestor context"""
131 in working context, merging context and ancestor context"""
131 if mctx == actx: # backwards?
132 if mctx == actx: # backwards?
132 actx = wctx.p1()
133 actx = wctx.p1()
133 s1 = wctx.substate
134 s1 = wctx.substate
134 s2 = mctx.substate
135 s2 = mctx.substate
135 sa = actx.substate
136 sa = actx.substate
136 sm = {}
137 sm = {}
137
138
138 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
139 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
139
140
140 def debug(s, msg, r=""):
141 def debug(s, msg, r=""):
141 if r:
142 if r:
142 r = "%s:%s:%s" % r
143 r = "%s:%s:%s" % r
143 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
144 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
144
145
145 promptssrc = filemerge.partextras(labels)
146 promptssrc = filemerge.partextras(labels)
146 for s, l in sorted(s1.iteritems()):
147 for s, l in sorted(s1.iteritems()):
147 prompts = None
148 prompts = None
148 a = sa.get(s, nullstate)
149 a = sa.get(s, nullstate)
149 ld = l # local state with possible dirty flag for compares
150 ld = l # local state with possible dirty flag for compares
150 if wctx.sub(s).dirty():
151 if wctx.sub(s).dirty():
151 ld = (l[0], l[1] + "+")
152 ld = (l[0], l[1] + "+")
152 if wctx == actx: # overwrite
153 if wctx == actx: # overwrite
153 a = ld
154 a = ld
154
155
155 prompts = promptssrc.copy()
156 prompts = promptssrc.copy()
156 prompts['s'] = s
157 prompts['s'] = s
157 if s in s2:
158 if s in s2:
158 r = s2[s]
159 r = s2[s]
159 if ld == r or r == a: # no change or local is newer
160 if ld == r or r == a: # no change or local is newer
160 sm[s] = l
161 sm[s] = l
161 continue
162 continue
162 elif ld == a: # other side changed
163 elif ld == a: # other side changed
163 debug(s, "other changed, get", r)
164 debug(s, "other changed, get", r)
164 wctx.sub(s).get(r, overwrite)
165 wctx.sub(s).get(r, overwrite)
165 sm[s] = r
166 sm[s] = r
166 elif ld[0] != r[0]: # sources differ
167 elif ld[0] != r[0]: # sources differ
167 prompts['lo'] = l[0]
168 prompts['lo'] = l[0]
168 prompts['ro'] = r[0]
169 prompts['ro'] = r[0]
169 if repo.ui.promptchoice(
170 if repo.ui.promptchoice(
170 _(' subrepository sources for %(s)s differ\n'
171 _(' subrepository sources for %(s)s differ\n'
171 'use (l)ocal%(l)s source (%(lo)s)'
172 'use (l)ocal%(l)s source (%(lo)s)'
172 ' or (r)emote%(o)s source (%(ro)s)?'
173 ' or (r)emote%(o)s source (%(ro)s)?'
173 '$$ &Local $$ &Remote') % prompts, 0):
174 '$$ &Local $$ &Remote') % prompts, 0):
174 debug(s, "prompt changed, get", r)
175 debug(s, "prompt changed, get", r)
175 wctx.sub(s).get(r, overwrite)
176 wctx.sub(s).get(r, overwrite)
176 sm[s] = r
177 sm[s] = r
177 elif ld[1] == a[1]: # local side is unchanged
178 elif ld[1] == a[1]: # local side is unchanged
178 debug(s, "other side changed, get", r)
179 debug(s, "other side changed, get", r)
179 wctx.sub(s).get(r, overwrite)
180 wctx.sub(s).get(r, overwrite)
180 sm[s] = r
181 sm[s] = r
181 else:
182 else:
182 debug(s, "both sides changed")
183 debug(s, "both sides changed")
183 srepo = wctx.sub(s)
184 srepo = wctx.sub(s)
184 prompts['sl'] = srepo.shortid(l[1])
185 prompts['sl'] = srepo.shortid(l[1])
185 prompts['sr'] = srepo.shortid(r[1])
186 prompts['sr'] = srepo.shortid(r[1])
186 option = repo.ui.promptchoice(
187 option = repo.ui.promptchoice(
187 _(' subrepository %(s)s diverged (local revision: %(sl)s, '
188 _(' subrepository %(s)s diverged (local revision: %(sl)s, '
188 'remote revision: %(sr)s)\n'
189 'remote revision: %(sr)s)\n'
189 '(M)erge, keep (l)ocal%(l)s or keep (r)emote%(o)s?'
190 '(M)erge, keep (l)ocal%(l)s or keep (r)emote%(o)s?'
190 '$$ &Merge $$ &Local $$ &Remote')
191 '$$ &Merge $$ &Local $$ &Remote')
191 % prompts, 0)
192 % prompts, 0)
192 if option == 0:
193 if option == 0:
193 wctx.sub(s).merge(r)
194 wctx.sub(s).merge(r)
194 sm[s] = l
195 sm[s] = l
195 debug(s, "merge with", r)
196 debug(s, "merge with", r)
196 elif option == 1:
197 elif option == 1:
197 sm[s] = l
198 sm[s] = l
198 debug(s, "keep local subrepo revision", l)
199 debug(s, "keep local subrepo revision", l)
199 else:
200 else:
200 wctx.sub(s).get(r, overwrite)
201 wctx.sub(s).get(r, overwrite)
201 sm[s] = r
202 sm[s] = r
202 debug(s, "get remote subrepo revision", r)
203 debug(s, "get remote subrepo revision", r)
203 elif ld == a: # remote removed, local unchanged
204 elif ld == a: # remote removed, local unchanged
204 debug(s, "remote removed, remove")
205 debug(s, "remote removed, remove")
205 wctx.sub(s).remove()
206 wctx.sub(s).remove()
206 elif a == nullstate: # not present in remote or ancestor
207 elif a == nullstate: # not present in remote or ancestor
207 debug(s, "local added, keep")
208 debug(s, "local added, keep")
208 sm[s] = l
209 sm[s] = l
209 continue
210 continue
210 else:
211 else:
211 if repo.ui.promptchoice(
212 if repo.ui.promptchoice(
212 _(' local%(l)s changed subrepository %(s)s'
213 _(' local%(l)s changed subrepository %(s)s'
213 ' which remote%(o)s removed\n'
214 ' which remote%(o)s removed\n'
214 'use (c)hanged version or (d)elete?'
215 'use (c)hanged version or (d)elete?'
215 '$$ &Changed $$ &Delete') % prompts, 0):
216 '$$ &Changed $$ &Delete') % prompts, 0):
216 debug(s, "prompt remove")
217 debug(s, "prompt remove")
217 wctx.sub(s).remove()
218 wctx.sub(s).remove()
218
219
219 for s, r in sorted(s2.items()):
220 for s, r in sorted(s2.items()):
220 prompts = None
221 prompts = None
221 if s in s1:
222 if s in s1:
222 continue
223 continue
223 elif s not in sa:
224 elif s not in sa:
224 debug(s, "remote added, get", r)
225 debug(s, "remote added, get", r)
225 mctx.sub(s).get(r)
226 mctx.sub(s).get(r)
226 sm[s] = r
227 sm[s] = r
227 elif r != sa[s]:
228 elif r != sa[s]:
228 prompts = promptssrc.copy()
229 prompts = promptssrc.copy()
229 prompts['s'] = s
230 prompts['s'] = s
230 if repo.ui.promptchoice(
231 if repo.ui.promptchoice(
231 _(' remote%(o)s changed subrepository %(s)s'
232 _(' remote%(o)s changed subrepository %(s)s'
232 ' which local%(l)s removed\n'
233 ' which local%(l)s removed\n'
233 'use (c)hanged version or (d)elete?'
234 'use (c)hanged version or (d)elete?'
234 '$$ &Changed $$ &Delete') % prompts, 0) == 0:
235 '$$ &Changed $$ &Delete') % prompts, 0) == 0:
235 debug(s, "prompt recreate", r)
236 debug(s, "prompt recreate", r)
236 mctx.sub(s).get(r)
237 mctx.sub(s).get(r)
237 sm[s] = r
238 sm[s] = r
238
239
239 # record merged .hgsubstate
240 # record merged .hgsubstate
240 writestate(repo, sm)
241 writestate(repo, sm)
241 return sm
242 return sm
242
243
243 def precommit(ui, wctx, status, match, force=False):
244 def precommit(ui, wctx, status, match, force=False):
244 """Calculate .hgsubstate changes that should be applied before committing
245 """Calculate .hgsubstate changes that should be applied before committing
245
246
246 Returns (subs, commitsubs, newstate) where
247 Returns (subs, commitsubs, newstate) where
247 - subs: changed subrepos (including dirty ones)
248 - subs: changed subrepos (including dirty ones)
248 - commitsubs: dirty subrepos which the caller needs to commit recursively
249 - commitsubs: dirty subrepos which the caller needs to commit recursively
249 - newstate: new state dict which the caller must write to .hgsubstate
250 - newstate: new state dict which the caller must write to .hgsubstate
250
251
251 This also updates the given status argument.
252 This also updates the given status argument.
252 """
253 """
253 subs = []
254 subs = []
254 commitsubs = set()
255 commitsubs = set()
255 newstate = wctx.substate.copy()
256 newstate = wctx.substate.copy()
256
257
257 # only manage subrepos and .hgsubstate if .hgsub is present
258 # only manage subrepos and .hgsubstate if .hgsub is present
258 if '.hgsub' in wctx:
259 if '.hgsub' in wctx:
259 # we'll decide whether to track this ourselves, thanks
260 # we'll decide whether to track this ourselves, thanks
260 for c in status.modified, status.added, status.removed:
261 for c in status.modified, status.added, status.removed:
261 if '.hgsubstate' in c:
262 if '.hgsubstate' in c:
262 c.remove('.hgsubstate')
263 c.remove('.hgsubstate')
263
264
264 # compare current state to last committed state
265 # compare current state to last committed state
265 # build new substate based on last committed state
266 # build new substate based on last committed state
266 oldstate = wctx.p1().substate
267 oldstate = wctx.p1().substate
267 for s in sorted(newstate.keys()):
268 for s in sorted(newstate.keys()):
268 if not match(s):
269 if not match(s):
269 # ignore working copy, use old state if present
270 # ignore working copy, use old state if present
270 if s in oldstate:
271 if s in oldstate:
271 newstate[s] = oldstate[s]
272 newstate[s] = oldstate[s]
272 continue
273 continue
273 if not force:
274 if not force:
274 raise error.Abort(
275 raise error.Abort(
275 _("commit with new subrepo %s excluded") % s)
276 _("commit with new subrepo %s excluded") % s)
276 dirtyreason = wctx.sub(s).dirtyreason(True)
277 dirtyreason = wctx.sub(s).dirtyreason(True)
277 if dirtyreason:
278 if dirtyreason:
278 if not ui.configbool('ui', 'commitsubrepos'):
279 if not ui.configbool('ui', 'commitsubrepos'):
279 raise error.Abort(dirtyreason,
280 raise error.Abort(dirtyreason,
280 hint=_("use --subrepos for recursive commit"))
281 hint=_("use --subrepos for recursive commit"))
281 subs.append(s)
282 subs.append(s)
282 commitsubs.add(s)
283 commitsubs.add(s)
283 else:
284 else:
284 bs = wctx.sub(s).basestate()
285 bs = wctx.sub(s).basestate()
285 newstate[s] = (newstate[s][0], bs, newstate[s][2])
286 newstate[s] = (newstate[s][0], bs, newstate[s][2])
286 if oldstate.get(s, (None, None, None))[1] != bs:
287 if oldstate.get(s, (None, None, None))[1] != bs:
287 subs.append(s)
288 subs.append(s)
288
289
289 # check for removed subrepos
290 # check for removed subrepos
290 for p in wctx.parents():
291 for p in wctx.parents():
291 r = [s for s in p.substate if s not in newstate]
292 r = [s for s in p.substate if s not in newstate]
292 subs += [s for s in r if match(s)]
293 subs += [s for s in r if match(s)]
293 if subs:
294 if subs:
294 if (not match('.hgsub') and
295 if (not match('.hgsub') and
295 '.hgsub' in (wctx.modified() + wctx.added())):
296 '.hgsub' in (wctx.modified() + wctx.added())):
296 raise error.Abort(_("can't commit subrepos without .hgsub"))
297 raise error.Abort(_("can't commit subrepos without .hgsub"))
297 status.modified.insert(0, '.hgsubstate')
298 status.modified.insert(0, '.hgsubstate')
298
299
299 elif '.hgsub' in status.removed:
300 elif '.hgsub' in status.removed:
300 # clean up .hgsubstate when .hgsub is removed
301 # clean up .hgsubstate when .hgsub is removed
301 if ('.hgsubstate' in wctx and
302 if ('.hgsubstate' in wctx and
302 '.hgsubstate' not in (status.modified + status.added +
303 '.hgsubstate' not in (status.modified + status.added +
303 status.removed)):
304 status.removed)):
304 status.removed.insert(0, '.hgsubstate')
305 status.removed.insert(0, '.hgsubstate')
305
306
306 return subs, commitsubs, newstate
307 return subs, commitsubs, newstate
307
308
308 def reporelpath(repo):
309 def reporelpath(repo):
309 """return path to this (sub)repo as seen from outermost repo"""
310 """return path to this (sub)repo as seen from outermost repo"""
310 parent = repo
311 parent = repo
311 while util.safehasattr(parent, '_subparent'):
312 while util.safehasattr(parent, '_subparent'):
312 parent = parent._subparent
313 parent = parent._subparent
313 return repo.root[len(pathutil.normasprefix(parent.root)):]
314 return repo.root[len(pathutil.normasprefix(parent.root)):]
314
315
315 def subrelpath(sub):
316 def subrelpath(sub):
316 """return path to this subrepo as seen from outermost repo"""
317 """return path to this subrepo as seen from outermost repo"""
317 return sub._relpath
318 return sub._relpath
318
319
319 def _abssource(repo, push=False, abort=True):
320 def _abssource(repo, push=False, abort=True):
320 """return pull/push path of repo - either based on parent repo .hgsub info
321 """return pull/push path of repo - either based on parent repo .hgsub info
321 or on the top repo config. Abort or return None if no source found."""
322 or on the top repo config. Abort or return None if no source found."""
322 if util.safehasattr(repo, '_subparent'):
323 if util.safehasattr(repo, '_subparent'):
323 source = util.url(repo._subsource)
324 source = util.url(repo._subsource)
324 if source.isabs():
325 if source.isabs():
325 return bytes(source)
326 return bytes(source)
326 source.path = posixpath.normpath(source.path)
327 source.path = posixpath.normpath(source.path)
327 parent = _abssource(repo._subparent, push, abort=False)
328 parent = _abssource(repo._subparent, push, abort=False)
328 if parent:
329 if parent:
329 parent = util.url(util.pconvert(parent))
330 parent = util.url(util.pconvert(parent))
330 parent.path = posixpath.join(parent.path or '', source.path)
331 parent.path = posixpath.join(parent.path or '', source.path)
331 parent.path = posixpath.normpath(parent.path)
332 parent.path = posixpath.normpath(parent.path)
332 return bytes(parent)
333 return bytes(parent)
333 else: # recursion reached top repo
334 else: # recursion reached top repo
334 path = None
335 path = None
335 if util.safehasattr(repo, '_subtoppath'):
336 if util.safehasattr(repo, '_subtoppath'):
336 path = repo._subtoppath
337 path = repo._subtoppath
337 elif push and repo.ui.config('paths', 'default-push'):
338 elif push and repo.ui.config('paths', 'default-push'):
338 path = repo.ui.config('paths', 'default-push')
339 path = repo.ui.config('paths', 'default-push')
339 elif repo.ui.config('paths', 'default'):
340 elif repo.ui.config('paths', 'default'):
340 path = repo.ui.config('paths', 'default')
341 path = repo.ui.config('paths', 'default')
341 elif repo.shared():
342 elif repo.shared():
342 # chop off the .hg component to get the default path form. This has
343 # chop off the .hg component to get the default path form. This has
343 # already run through vfsmod.vfs(..., realpath=True), so it doesn't
344 # already run through vfsmod.vfs(..., realpath=True), so it doesn't
344 # have problems with 'C:'
345 # have problems with 'C:'
345 return os.path.dirname(repo.sharedpath)
346 return os.path.dirname(repo.sharedpath)
346 if path:
347 if path:
347 # issue5770: 'C:\' and 'C:' are not equivalent paths. The former is
348 # issue5770: 'C:\' and 'C:' are not equivalent paths. The former is
348 # as expected: an absolute path to the root of the C: drive. The
349 # as expected: an absolute path to the root of the C: drive. The
349 # latter is a relative path, and works like so:
350 # latter is a relative path, and works like so:
350 #
351 #
351 # C:\>cd C:\some\path
352 # C:\>cd C:\some\path
352 # C:\>D:
353 # C:\>D:
353 # D:\>python -c "import os; print os.path.abspath('C:')"
354 # D:\>python -c "import os; print os.path.abspath('C:')"
354 # C:\some\path
355 # C:\some\path
355 #
356 #
356 # D:\>python -c "import os; print os.path.abspath('C:relative')"
357 # D:\>python -c "import os; print os.path.abspath('C:relative')"
357 # C:\some\path\relative
358 # C:\some\path\relative
358 if util.hasdriveletter(path):
359 if util.hasdriveletter(path):
359 if len(path) == 2 or path[2:3] not in br'\/':
360 if len(path) == 2 or path[2:3] not in br'\/':
360 path = os.path.abspath(path)
361 path = os.path.abspath(path)
361 return path
362 return path
362
363
363 if abort:
364 if abort:
364 raise error.Abort(_("default path for subrepository not found"))
365 raise error.Abort(_("default path for subrepository not found"))
365
366
366 def newcommitphase(ui, ctx):
367 def newcommitphase(ui, ctx):
367 commitphase = phases.newcommitphase(ui)
368 commitphase = phases.newcommitphase(ui)
368 substate = getattr(ctx, "substate", None)
369 substate = getattr(ctx, "substate", None)
369 if not substate:
370 if not substate:
370 return commitphase
371 return commitphase
371 check = ui.config('phases', 'checksubrepos')
372 check = ui.config('phases', 'checksubrepos')
372 if check not in ('ignore', 'follow', 'abort'):
373 if check not in ('ignore', 'follow', 'abort'):
373 raise error.Abort(_('invalid phases.checksubrepos configuration: %s')
374 raise error.Abort(_('invalid phases.checksubrepos configuration: %s')
374 % (check))
375 % (check))
375 if check == 'ignore':
376 if check == 'ignore':
376 return commitphase
377 return commitphase
377 maxphase = phases.public
378 maxphase = phases.public
378 maxsub = None
379 maxsub = None
379 for s in sorted(substate):
380 for s in sorted(substate):
380 sub = ctx.sub(s)
381 sub = ctx.sub(s)
381 subphase = sub.phase(substate[s][1])
382 subphase = sub.phase(substate[s][1])
382 if maxphase < subphase:
383 if maxphase < subphase:
383 maxphase = subphase
384 maxphase = subphase
384 maxsub = s
385 maxsub = s
385 if commitphase < maxphase:
386 if commitphase < maxphase:
386 if check == 'abort':
387 if check == 'abort':
387 raise error.Abort(_("can't commit in %s phase"
388 raise error.Abort(_("can't commit in %s phase"
388 " conflicting %s from subrepository %s") %
389 " conflicting %s from subrepository %s") %
389 (phases.phasenames[commitphase],
390 (phases.phasenames[commitphase],
390 phases.phasenames[maxphase], maxsub))
391 phases.phasenames[maxphase], maxsub))
391 ui.warn(_("warning: changes are committed in"
392 ui.warn(_("warning: changes are committed in"
392 " %s phase from subrepository %s\n") %
393 " %s phase from subrepository %s\n") %
393 (phases.phasenames[maxphase], maxsub))
394 (phases.phasenames[maxphase], maxsub))
394 return maxphase
395 return maxphase
395 return commitphase
396 return commitphase
General Comments 0
You need to be logged in to leave comments. Login now