##// END OF EJS Templates
subrepo: fix hgrc paths section during subrepo pulling...
Edouard Gomez -
r10697:c90d923f stable
parent child Browse files
Show More
@@ -1,369 +1,372
1 # subrepo.py - sub-repository handling for Mercurial
1 # subrepo.py - sub-repository handling for Mercurial
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 import errno, os, re, xml.dom.minidom, shutil
8 import errno, os, re, xml.dom.minidom, shutil
9 from i18n import _
9 from i18n import _
10 import config, util, node, error
10 import config, util, node, error
11 hg = None
11 hg = None
12
12
13 nullstate = ('', '', 'empty')
13 nullstate = ('', '', 'empty')
14
14
15 def state(ctx):
15 def state(ctx):
16 p = config.config()
16 p = config.config()
17 def read(f, sections=None, remap=None):
17 def read(f, sections=None, remap=None):
18 if f in ctx:
18 if f in ctx:
19 p.parse(f, ctx[f].data(), sections, remap, read)
19 p.parse(f, ctx[f].data(), sections, remap, read)
20 else:
20 else:
21 raise util.Abort(_("subrepo spec file %s not found") % f)
21 raise util.Abort(_("subrepo spec file %s not found") % f)
22
22
23 if '.hgsub' in ctx:
23 if '.hgsub' in ctx:
24 read('.hgsub')
24 read('.hgsub')
25
25
26 rev = {}
26 rev = {}
27 if '.hgsubstate' in ctx:
27 if '.hgsubstate' in ctx:
28 try:
28 try:
29 for l in ctx['.hgsubstate'].data().splitlines():
29 for l in ctx['.hgsubstate'].data().splitlines():
30 revision, path = l.split(" ", 1)
30 revision, path = l.split(" ", 1)
31 rev[path] = revision
31 rev[path] = revision
32 except IOError, err:
32 except IOError, err:
33 if err.errno != errno.ENOENT:
33 if err.errno != errno.ENOENT:
34 raise
34 raise
35
35
36 state = {}
36 state = {}
37 for path, src in p[''].items():
37 for path, src in p[''].items():
38 kind = 'hg'
38 kind = 'hg'
39 if src.startswith('['):
39 if src.startswith('['):
40 if ']' not in src:
40 if ']' not in src:
41 raise util.Abort(_('missing ] in subrepo source'))
41 raise util.Abort(_('missing ] in subrepo source'))
42 kind, src = src.split(']', 1)
42 kind, src = src.split(']', 1)
43 kind = kind[1:]
43 kind = kind[1:]
44 state[path] = (src.strip(), rev.get(path, ''), kind)
44 state[path] = (src.strip(), rev.get(path, ''), kind)
45
45
46 return state
46 return state
47
47
48 def writestate(repo, state):
48 def writestate(repo, state):
49 repo.wwrite('.hgsubstate',
49 repo.wwrite('.hgsubstate',
50 ''.join(['%s %s\n' % (state[s][1], s)
50 ''.join(['%s %s\n' % (state[s][1], s)
51 for s in sorted(state)]), '')
51 for s in sorted(state)]), '')
52
52
53 def submerge(repo, wctx, mctx, actx):
53 def submerge(repo, wctx, mctx, actx):
54 # working context, merging context, ancestor context
54 # working context, merging context, ancestor context
55 if mctx == actx: # backwards?
55 if mctx == actx: # backwards?
56 actx = wctx.p1()
56 actx = wctx.p1()
57 s1 = wctx.substate
57 s1 = wctx.substate
58 s2 = mctx.substate
58 s2 = mctx.substate
59 sa = actx.substate
59 sa = actx.substate
60 sm = {}
60 sm = {}
61
61
62 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
62 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
63
63
64 def debug(s, msg, r=""):
64 def debug(s, msg, r=""):
65 if r:
65 if r:
66 r = "%s:%s:%s" % r
66 r = "%s:%s:%s" % r
67 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
67 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
68
68
69 for s, l in s1.items():
69 for s, l in s1.items():
70 if wctx != actx and wctx.sub(s).dirty():
70 if wctx != actx and wctx.sub(s).dirty():
71 l = (l[0], l[1] + "+")
71 l = (l[0], l[1] + "+")
72 a = sa.get(s, nullstate)
72 a = sa.get(s, nullstate)
73 if s in s2:
73 if s in s2:
74 r = s2[s]
74 r = s2[s]
75 if l == r or r == a: # no change or local is newer
75 if l == r or r == a: # no change or local is newer
76 sm[s] = l
76 sm[s] = l
77 continue
77 continue
78 elif l == a: # other side changed
78 elif l == a: # other side changed
79 debug(s, "other changed, get", r)
79 debug(s, "other changed, get", r)
80 wctx.sub(s).get(r)
80 wctx.sub(s).get(r)
81 sm[s] = r
81 sm[s] = r
82 elif l[0] != r[0]: # sources differ
82 elif l[0] != r[0]: # sources differ
83 if repo.ui.promptchoice(
83 if repo.ui.promptchoice(
84 _(' subrepository sources for %s differ\n'
84 _(' subrepository sources for %s differ\n'
85 'use (l)ocal source (%s) or (r)emote source (%s)?')
85 'use (l)ocal source (%s) or (r)emote source (%s)?')
86 % (s, l[0], r[0]),
86 % (s, l[0], r[0]),
87 (_('&Local'), _('&Remote')), 0):
87 (_('&Local'), _('&Remote')), 0):
88 debug(s, "prompt changed, get", r)
88 debug(s, "prompt changed, get", r)
89 wctx.sub(s).get(r)
89 wctx.sub(s).get(r)
90 sm[s] = r
90 sm[s] = r
91 elif l[1] == a[1]: # local side is unchanged
91 elif l[1] == a[1]: # local side is unchanged
92 debug(s, "other side changed, get", r)
92 debug(s, "other side changed, get", r)
93 wctx.sub(s).get(r)
93 wctx.sub(s).get(r)
94 sm[s] = r
94 sm[s] = r
95 else:
95 else:
96 debug(s, "both sides changed, merge with", r)
96 debug(s, "both sides changed, merge with", r)
97 wctx.sub(s).merge(r)
97 wctx.sub(s).merge(r)
98 sm[s] = l
98 sm[s] = l
99 elif l == a: # remote removed, local unchanged
99 elif l == a: # remote removed, local unchanged
100 debug(s, "remote removed, remove")
100 debug(s, "remote removed, remove")
101 wctx.sub(s).remove()
101 wctx.sub(s).remove()
102 else:
102 else:
103 if repo.ui.promptchoice(
103 if repo.ui.promptchoice(
104 _(' local changed subrepository %s which remote removed\n'
104 _(' local changed subrepository %s which remote removed\n'
105 'use (c)hanged version or (d)elete?') % s,
105 'use (c)hanged version or (d)elete?') % s,
106 (_('&Changed'), _('&Delete')), 0):
106 (_('&Changed'), _('&Delete')), 0):
107 debug(s, "prompt remove")
107 debug(s, "prompt remove")
108 wctx.sub(s).remove()
108 wctx.sub(s).remove()
109
109
110 for s, r in s2.items():
110 for s, r in s2.items():
111 if s in s1:
111 if s in s1:
112 continue
112 continue
113 elif s not in sa:
113 elif s not in sa:
114 debug(s, "remote added, get", r)
114 debug(s, "remote added, get", r)
115 mctx.sub(s).get(r)
115 mctx.sub(s).get(r)
116 sm[s] = r
116 sm[s] = r
117 elif r != sa[s]:
117 elif r != sa[s]:
118 if repo.ui.promptchoice(
118 if repo.ui.promptchoice(
119 _(' remote changed subrepository %s which local removed\n'
119 _(' remote changed subrepository %s which local removed\n'
120 'use (c)hanged version or (d)elete?') % s,
120 'use (c)hanged version or (d)elete?') % s,
121 (_('&Changed'), _('&Delete')), 0) == 0:
121 (_('&Changed'), _('&Delete')), 0) == 0:
122 debug(s, "prompt recreate", r)
122 debug(s, "prompt recreate", r)
123 wctx.sub(s).get(r)
123 wctx.sub(s).get(r)
124 sm[s] = r
124 sm[s] = r
125
125
126 # record merged .hgsubstate
126 # record merged .hgsubstate
127 writestate(repo, sm)
127 writestate(repo, sm)
128
128
129 def _abssource(repo, push=False):
129 def _abssource(repo, push=False):
130 if hasattr(repo, '_subparent'):
130 if hasattr(repo, '_subparent'):
131 source = repo._subsource
131 source = repo._subsource
132 if source.startswith('/') or '://' in source:
132 if source.startswith('/') or '://' in source:
133 return source
133 return source
134 parent = _abssource(repo._subparent, push)
134 parent = _abssource(repo._subparent, push)
135 if '://' in parent:
135 if '://' in parent:
136 if parent[-1] == '/':
136 if parent[-1] == '/':
137 parent = parent[:-1]
137 parent = parent[:-1]
138 return parent + '/' + source
138 return parent + '/' + source
139 return os.path.join(parent, repo._subsource)
139 return os.path.join(parent, repo._subsource)
140 if push and repo.ui.config('paths', 'default-push'):
140 if push and repo.ui.config('paths', 'default-push'):
141 return repo.ui.config('paths', 'default-push', repo.root)
141 return repo.ui.config('paths', 'default-push', repo.root)
142 return repo.ui.config('paths', 'default', repo.root)
142 return repo.ui.config('paths', 'default', repo.root)
143
143
144 def subrepo(ctx, path):
144 def subrepo(ctx, path):
145 # subrepo inherently violates our import layering rules
145 # subrepo inherently violates our import layering rules
146 # because it wants to make repo objects from deep inside the stack
146 # because it wants to make repo objects from deep inside the stack
147 # so we manually delay the circular imports to not break
147 # so we manually delay the circular imports to not break
148 # scripts that don't use our demand-loading
148 # scripts that don't use our demand-loading
149 global hg
149 global hg
150 import hg as h
150 import hg as h
151 hg = h
151 hg = h
152
152
153 util.path_auditor(ctx._repo.root)(path)
153 util.path_auditor(ctx._repo.root)(path)
154 state = ctx.substate.get(path, nullstate)
154 state = ctx.substate.get(path, nullstate)
155 if state[2] not in types:
155 if state[2] not in types:
156 raise util.Abort(_('unknown subrepo type %s') % state[2])
156 raise util.Abort(_('unknown subrepo type %s') % state[2])
157 return types[state[2]](ctx, path, state[:2])
157 return types[state[2]](ctx, path, state[:2])
158
158
159 # subrepo classes need to implement the following methods:
159 # subrepo classes need to implement the following methods:
160 # __init__(self, ctx, path, state)
160 # __init__(self, ctx, path, state)
161 # dirty(self): returns true if the dirstate of the subrepo
161 # dirty(self): returns true if the dirstate of the subrepo
162 # does not match current stored state
162 # does not match current stored state
163 # commit(self, text, user, date): commit the current changes
163 # commit(self, text, user, date): commit the current changes
164 # to the subrepo with the given log message. Use given
164 # to the subrepo with the given log message. Use given
165 # user and date if possible. Return the new state of the subrepo.
165 # user and date if possible. Return the new state of the subrepo.
166 # remove(self): remove the subrepo (should verify the dirstate
166 # remove(self): remove the subrepo (should verify the dirstate
167 # is not dirty first)
167 # is not dirty first)
168 # get(self, state): run whatever commands are needed to put the
168 # get(self, state): run whatever commands are needed to put the
169 # subrepo into this state
169 # subrepo into this state
170 # merge(self, state): merge currently-saved state with the new state.
170 # merge(self, state): merge currently-saved state with the new state.
171 # push(self, force): perform whatever action is analagous to 'hg push'
171 # push(self, force): perform whatever action is analagous to 'hg push'
172 # This may be a no-op on some systems.
172 # This may be a no-op on some systems.
173
173
174 class hgsubrepo(object):
174 class hgsubrepo(object):
175 def __init__(self, ctx, path, state):
175 def __init__(self, ctx, path, state):
176 self._path = path
176 self._path = path
177 self._state = state
177 self._state = state
178 r = ctx._repo
178 r = ctx._repo
179 root = r.wjoin(path)
179 root = r.wjoin(path)
180 create = False
180 create = False
181 if not os.path.exists(os.path.join(root, '.hg')):
181 if not os.path.exists(os.path.join(root, '.hg')):
182 create = True
182 create = True
183 util.makedirs(root)
183 util.makedirs(root)
184 self._repo = hg.repository(r.ui, root, create=create)
184 self._repo = hg.repository(r.ui, root, create=create)
185 self._repo._subparent = r
185 self._repo._subparent = r
186 self._repo._subsource = state[0]
186 self._repo._subsource = state[0]
187
187
188 if create:
188 if create:
189 fp = self._repo.opener("hgrc", "w", text=True)
189 fp = self._repo.opener("hgrc", "w", text=True)
190 fp.write('[paths]\n')
190 fp.write('[paths]\n')
191
191
192 def addpathconfig(key, value):
192 def addpathconfig(key, value):
193 fp.write('%s = %s\n' % (key, value))
193 fp.write('%s = %s\n' % (key, value))
194 self._repo.ui.setconfig('paths', key, value)
194 self._repo.ui.setconfig('paths', key, value)
195
195
196 defpath = os.path.join(_abssource(ctx._repo), path)
196 defpath = _abssource(self._repo)
197 defpushpath = _abssource(self._repo, True)
197 addpathconfig('default', defpath)
198 addpathconfig('default', defpath)
199 if defpath != defpushpath:
200 addpathconfig('default-push', defpushpath)
198 fp.close()
201 fp.close()
199
202
200 def dirty(self):
203 def dirty(self):
201 r = self._state[1]
204 r = self._state[1]
202 if r == '':
205 if r == '':
203 return True
206 return True
204 w = self._repo[None]
207 w = self._repo[None]
205 if w.p1() != self._repo[r]: # version checked out change
208 if w.p1() != self._repo[r]: # version checked out change
206 return True
209 return True
207 return w.dirty() # working directory changed
210 return w.dirty() # working directory changed
208
211
209 def commit(self, text, user, date):
212 def commit(self, text, user, date):
210 self._repo.ui.debug("committing subrepo %s\n" % self._path)
213 self._repo.ui.debug("committing subrepo %s\n" % self._path)
211 n = self._repo.commit(text, user, date)
214 n = self._repo.commit(text, user, date)
212 if not n:
215 if not n:
213 return self._repo['.'].hex() # different version checked out
216 return self._repo['.'].hex() # different version checked out
214 return node.hex(n)
217 return node.hex(n)
215
218
216 def remove(self):
219 def remove(self):
217 # we can't fully delete the repository as it may contain
220 # we can't fully delete the repository as it may contain
218 # local-only history
221 # local-only history
219 self._repo.ui.note(_('removing subrepo %s\n') % self._path)
222 self._repo.ui.note(_('removing subrepo %s\n') % self._path)
220 hg.clean(self._repo, node.nullid, False)
223 hg.clean(self._repo, node.nullid, False)
221
224
222 def _get(self, state):
225 def _get(self, state):
223 source, revision, kind = state
226 source, revision, kind = state
224 try:
227 try:
225 self._repo.lookup(revision)
228 self._repo.lookup(revision)
226 except error.RepoError:
229 except error.RepoError:
227 self._repo._subsource = source
230 self._repo._subsource = source
228 self._repo.ui.status(_('pulling subrepo %s\n') % self._path)
231 self._repo.ui.status(_('pulling subrepo %s\n') % self._path)
229 srcurl = _abssource(self._repo)
232 srcurl = _abssource(self._repo)
230 other = hg.repository(self._repo.ui, srcurl)
233 other = hg.repository(self._repo.ui, srcurl)
231 self._repo.pull(other)
234 self._repo.pull(other)
232
235
233 def get(self, state):
236 def get(self, state):
234 self._get(state)
237 self._get(state)
235 source, revision, kind = state
238 source, revision, kind = state
236 self._repo.ui.debug("getting subrepo %s\n" % self._path)
239 self._repo.ui.debug("getting subrepo %s\n" % self._path)
237 hg.clean(self._repo, revision, False)
240 hg.clean(self._repo, revision, False)
238
241
239 def merge(self, state):
242 def merge(self, state):
240 self._get(state)
243 self._get(state)
241 cur = self._repo['.']
244 cur = self._repo['.']
242 dst = self._repo[state[1]]
245 dst = self._repo[state[1]]
243 anc = dst.ancestor(cur)
246 anc = dst.ancestor(cur)
244 if anc == cur:
247 if anc == cur:
245 self._repo.ui.debug("updating subrepo %s\n" % self._path)
248 self._repo.ui.debug("updating subrepo %s\n" % self._path)
246 hg.update(self._repo, state[1])
249 hg.update(self._repo, state[1])
247 elif anc == dst:
250 elif anc == dst:
248 self._repo.ui.debug("skipping subrepo %s\n" % self._path)
251 self._repo.ui.debug("skipping subrepo %s\n" % self._path)
249 else:
252 else:
250 self._repo.ui.debug("merging subrepo %s\n" % self._path)
253 self._repo.ui.debug("merging subrepo %s\n" % self._path)
251 hg.merge(self._repo, state[1], remind=False)
254 hg.merge(self._repo, state[1], remind=False)
252
255
253 def push(self, force):
256 def push(self, force):
254 # push subrepos depth-first for coherent ordering
257 # push subrepos depth-first for coherent ordering
255 c = self._repo['']
258 c = self._repo['']
256 subs = c.substate # only repos that are committed
259 subs = c.substate # only repos that are committed
257 for s in sorted(subs):
260 for s in sorted(subs):
258 c.sub(s).push(force)
261 c.sub(s).push(force)
259
262
260 self._repo.ui.status(_('pushing subrepo %s\n') % self._path)
263 self._repo.ui.status(_('pushing subrepo %s\n') % self._path)
261 dsturl = _abssource(self._repo, True)
264 dsturl = _abssource(self._repo, True)
262 other = hg.repository(self._repo.ui, dsturl)
265 other = hg.repository(self._repo.ui, dsturl)
263 self._repo.push(other, force)
266 self._repo.push(other, force)
264
267
265 class svnsubrepo(object):
268 class svnsubrepo(object):
266 def __init__(self, ctx, path, state):
269 def __init__(self, ctx, path, state):
267 self._path = path
270 self._path = path
268 self._state = state
271 self._state = state
269 self._ctx = ctx
272 self._ctx = ctx
270 self._ui = ctx._repo.ui
273 self._ui = ctx._repo.ui
271
274
272 def _svncommand(self, commands):
275 def _svncommand(self, commands):
273 cmd = ['svn'] + commands + [self._path]
276 cmd = ['svn'] + commands + [self._path]
274 cmd = [util.shellquote(arg) for arg in cmd]
277 cmd = [util.shellquote(arg) for arg in cmd]
275 cmd = util.quotecommand(' '.join(cmd))
278 cmd = util.quotecommand(' '.join(cmd))
276 env = dict(os.environ)
279 env = dict(os.environ)
277 # Avoid localized output, preserve current locale for everything else.
280 # Avoid localized output, preserve current locale for everything else.
278 env['LC_MESSAGES'] = 'C'
281 env['LC_MESSAGES'] = 'C'
279 write, read, err = util.popen3(cmd, env=env, newlines=True)
282 write, read, err = util.popen3(cmd, env=env, newlines=True)
280 retdata = read.read()
283 retdata = read.read()
281 err = err.read().strip()
284 err = err.read().strip()
282 if err:
285 if err:
283 raise util.Abort(err)
286 raise util.Abort(err)
284 return retdata
287 return retdata
285
288
286 def _wcrev(self):
289 def _wcrev(self):
287 output = self._svncommand(['info', '--xml'])
290 output = self._svncommand(['info', '--xml'])
288 doc = xml.dom.minidom.parseString(output)
291 doc = xml.dom.minidom.parseString(output)
289 entries = doc.getElementsByTagName('entry')
292 entries = doc.getElementsByTagName('entry')
290 if not entries:
293 if not entries:
291 return 0
294 return 0
292 return int(entries[0].getAttribute('revision') or 0)
295 return int(entries[0].getAttribute('revision') or 0)
293
296
294 def _wcchanged(self):
297 def _wcchanged(self):
295 """Return (changes, extchanges) where changes is True
298 """Return (changes, extchanges) where changes is True
296 if the working directory was changed, and extchanges is
299 if the working directory was changed, and extchanges is
297 True if any of these changes concern an external entry.
300 True if any of these changes concern an external entry.
298 """
301 """
299 output = self._svncommand(['status', '--xml'])
302 output = self._svncommand(['status', '--xml'])
300 externals, changes = [], []
303 externals, changes = [], []
301 doc = xml.dom.minidom.parseString(output)
304 doc = xml.dom.minidom.parseString(output)
302 for e in doc.getElementsByTagName('entry'):
305 for e in doc.getElementsByTagName('entry'):
303 s = e.getElementsByTagName('wc-status')
306 s = e.getElementsByTagName('wc-status')
304 if not s:
307 if not s:
305 continue
308 continue
306 item = s[0].getAttribute('item')
309 item = s[0].getAttribute('item')
307 props = s[0].getAttribute('props')
310 props = s[0].getAttribute('props')
308 path = e.getAttribute('path')
311 path = e.getAttribute('path')
309 if item == 'external':
312 if item == 'external':
310 externals.append(path)
313 externals.append(path)
311 if (item not in ('', 'normal', 'unversioned', 'external')
314 if (item not in ('', 'normal', 'unversioned', 'external')
312 or props not in ('', 'none')):
315 or props not in ('', 'none')):
313 changes.append(path)
316 changes.append(path)
314 for path in changes:
317 for path in changes:
315 for ext in externals:
318 for ext in externals:
316 if path == ext or path.startswith(ext + os.sep):
319 if path == ext or path.startswith(ext + os.sep):
317 return True, True
320 return True, True
318 return bool(changes), False
321 return bool(changes), False
319
322
320 def dirty(self):
323 def dirty(self):
321 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
324 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
322 return False
325 return False
323 return True
326 return True
324
327
325 def commit(self, text, user, date):
328 def commit(self, text, user, date):
326 # user and date are out of our hands since svn is centralized
329 # user and date are out of our hands since svn is centralized
327 changed, extchanged = self._wcchanged()
330 changed, extchanged = self._wcchanged()
328 if not changed:
331 if not changed:
329 return self._wcrev()
332 return self._wcrev()
330 if extchanged:
333 if extchanged:
331 # Do not try to commit externals
334 # Do not try to commit externals
332 raise util.Abort(_('cannot commit svn externals'))
335 raise util.Abort(_('cannot commit svn externals'))
333 commitinfo = self._svncommand(['commit', '-m', text])
336 commitinfo = self._svncommand(['commit', '-m', text])
334 self._ui.status(commitinfo)
337 self._ui.status(commitinfo)
335 newrev = re.search('Committed revision ([\d]+).', commitinfo)
338 newrev = re.search('Committed revision ([\d]+).', commitinfo)
336 if not newrev:
339 if not newrev:
337 raise util.Abort(commitinfo.splitlines()[-1])
340 raise util.Abort(commitinfo.splitlines()[-1])
338 newrev = newrev.groups()[0]
341 newrev = newrev.groups()[0]
339 self._ui.status(self._svncommand(['update', '-r', newrev]))
342 self._ui.status(self._svncommand(['update', '-r', newrev]))
340 return newrev
343 return newrev
341
344
342 def remove(self):
345 def remove(self):
343 if self.dirty():
346 if self.dirty():
344 self._ui.warn(_('not removing repo %s because '
347 self._ui.warn(_('not removing repo %s because '
345 'it has changes.\n' % self._path))
348 'it has changes.\n' % self._path))
346 return
349 return
347 self._ui.note(_('removing subrepo %s\n') % self._path)
350 self._ui.note(_('removing subrepo %s\n') % self._path)
348 shutil.rmtree(self._ctx.repo.join(self._path))
351 shutil.rmtree(self._ctx.repo.join(self._path))
349
352
350 def get(self, state):
353 def get(self, state):
351 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
354 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
352 if not re.search('Checked out revision [\d]+.', status):
355 if not re.search('Checked out revision [\d]+.', status):
353 raise util.Abort(status.splitlines()[-1])
356 raise util.Abort(status.splitlines()[-1])
354 self._ui.status(status)
357 self._ui.status(status)
355
358
356 def merge(self, state):
359 def merge(self, state):
357 old = int(self._state[1])
360 old = int(self._state[1])
358 new = int(state[1])
361 new = int(state[1])
359 if new > old:
362 if new > old:
360 self.get(state)
363 self.get(state)
361
364
362 def push(self, force):
365 def push(self, force):
363 # nothing for svn
366 # nothing for svn
364 pass
367 pass
365
368
366 types = {
369 types = {
367 'hg': hgsubrepo,
370 'hg': hgsubrepo,
368 'svn': svnsubrepo,
371 'svn': svnsubrepo,
369 }
372 }
@@ -1,268 +1,268
1 % first revision, no sub
1 % first revision, no sub
2 adding a
2 adding a
3 % add first sub
3 % add first sub
4 adding a
4 adding a
5 committing subrepository s
5 committing subrepository s
6 % add sub sub
6 % add sub sub
7 committing subrepository s
7 committing subrepository s
8 committing subrepository ss
8 committing subrepository ss
9 % bump sub rev
9 % bump sub rev
10 committing subrepository s
10 committing subrepository s
11 % leave sub dirty
11 % leave sub dirty
12 committing subrepository s
12 committing subrepository s
13 changeset: 3:1c833a7a9e3a
13 changeset: 3:1c833a7a9e3a
14 tag: tip
14 tag: tip
15 user: test
15 user: test
16 date: Thu Jan 01 00:00:00 1970 +0000
16 date: Thu Jan 01 00:00:00 1970 +0000
17 summary: 4
17 summary: 4
18
18
19 % check caching
19 % check caching
20 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
20 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
21 % restore
21 % restore
22 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 path s
23 path s
24 source s
24 source s
25 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
25 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
26 % new branch for merge tests
26 % new branch for merge tests
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 adding t/t
28 adding t/t
29 % 5
29 % 5
30 committing subrepository t
30 committing subrepository t
31 created new head
31 created new head
32 % 6
32 % 6
33 committing subrepository t
33 committing subrepository t
34 path s
34 path s
35 source s
35 source s
36 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
36 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
37 path t
37 path t
38 source t
38 source t
39 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
39 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
40 % 7
40 % 7
41 committing subrepository t
41 committing subrepository t
42 % 8
42 % 8
43 % merge tests
43 % merge tests
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 (branch merge, don't forget to commit)
46 (branch merge, don't forget to commit)
47 path s
47 path s
48 source s
48 source s
49 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
49 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
50 path t
50 path t
51 source t
51 source t
52 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
52 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
53 created new head
53 created new head
54 searching for copies back to rev 2
54 searching for copies back to rev 2
55 resolving manifests
55 resolving manifests
56 overwrite None partial False
56 overwrite None partial False
57 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
57 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
58 .hgsubstate: versions differ -> m
58 .hgsubstate: versions differ -> m
59 update: .hgsubstate 1/1 files (100.00%)
59 update: .hgsubstate 1/1 files (100.00%)
60 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
60 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
61 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
61 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
62 getting subrepo t
62 getting subrepo t
63 resolving manifests
63 resolving manifests
64 overwrite True partial False
64 overwrite True partial False
65 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
65 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
66 t: remote is newer -> g
66 t: remote is newer -> g
67 update: t 1/1 files (100.00%)
67 update: t 1/1 files (100.00%)
68 getting t
68 getting t
69 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 (branch merge, don't forget to commit)
70 (branch merge, don't forget to commit)
71 path s
71 path s
72 source s
72 source s
73 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
73 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
74 path t
74 path t
75 source t
75 source t
76 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
76 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
77 committing subrepository t
77 committing subrepository t
78 searching for copies back to rev 2
78 searching for copies back to rev 2
79 resolving manifests
79 resolving manifests
80 overwrite None partial False
80 overwrite None partial False
81 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
81 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
82 .hgsubstate: versions differ -> m
82 .hgsubstate: versions differ -> m
83 update: .hgsubstate 1/1 files (100.00%)
83 update: .hgsubstate 1/1 files (100.00%)
84 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
84 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
85 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
85 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
86 merging subrepo t
86 merging subrepo t
87 searching for copies back to rev 2
87 searching for copies back to rev 2
88 resolving manifests
88 resolving manifests
89 overwrite None partial False
89 overwrite None partial False
90 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
90 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
91 t: versions differ -> m
91 t: versions differ -> m
92 preserving t for resolve of t
92 preserving t for resolve of t
93 update: t 1/1 files (100.00%)
93 update: t 1/1 files (100.00%)
94 picked tool 'internal:merge' for t (binary False symlink False)
94 picked tool 'internal:merge' for t (binary False symlink False)
95 merging t
95 merging t
96 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
96 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
97 warning: conflicts during merge.
97 warning: conflicts during merge.
98 merging t failed!
98 merging t failed!
99 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
99 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
100 use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
100 use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
101 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 (branch merge, don't forget to commit)
102 (branch merge, don't forget to commit)
103 % should conflict
103 % should conflict
104 <<<<<<< local
104 <<<<<<< local
105 conflict
105 conflict
106 =======
106 =======
107 t3
107 t3
108 >>>>>>> other
108 >>>>>>> other
109 % clone
109 % clone
110 updating to branch default
110 updating to branch default
111 pulling subrepo s
111 pulling subrepo s
112 requesting all changes
112 requesting all changes
113 adding changesets
113 adding changesets
114 adding manifests
114 adding manifests
115 adding file changes
115 adding file changes
116 added 4 changesets with 5 changes to 3 files
116 added 4 changesets with 5 changes to 3 files
117 pulling subrepo ss
117 pulling subrepo ss
118 requesting all changes
118 requesting all changes
119 adding changesets
119 adding changesets
120 adding manifests
120 adding manifests
121 adding file changes
121 adding file changes
122 added 1 changesets with 1 changes to 1 files
122 added 1 changesets with 1 changes to 1 files
123 pulling subrepo t
123 pulling subrepo t
124 requesting all changes
124 requesting all changes
125 adding changesets
125 adding changesets
126 adding manifests
126 adding manifests
127 adding file changes
127 adding file changes
128 added 4 changesets with 4 changes to 1 files (+1 heads)
128 added 4 changesets with 4 changes to 1 files (+1 heads)
129 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
129 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
130 path s
130 path s
131 source s
131 source s
132 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
132 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
133 path t
133 path t
134 source t
134 source t
135 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
135 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
136 % push
136 % push
137 committing subrepository t
137 committing subrepository t
138 pushing ...sub/t
138 pushing ...sub/t
139 pushing ...subrepo ss
139 pushing ...subrepo ss
140 searching for changes
140 searching for changes
141 no changes found
141 no changes found
142 pushing ...subrepo s
142 pushing ...subrepo s
143 searching for changes
143 searching for changes
144 no changes found
144 no changes found
145 pushing ...subrepo t
145 pushing ...subrepo t
146 searching for changes
146 searching for changes
147 adding changesets
147 adding changesets
148 adding manifests
148 adding manifests
149 adding file changes
149 adding file changes
150 added 1 changesets with 1 changes to 1 files
150 added 1 changesets with 1 changes to 1 files
151 searching for changes
151 searching for changes
152 adding changesets
152 adding changesets
153 adding manifests
153 adding manifests
154 adding file changes
154 adding file changes
155 added 1 changesets with 1 changes to 1 files
155 added 1 changesets with 1 changes to 1 files
156 % push -f
156 % push -f
157 committing subrepository s
157 committing subrepository s
158 abort: push creates new remote heads on branch 'default'!
158 abort: push creates new remote heads on branch 'default'!
159 pushing ...sub/t
159 pushing ...sub/t
160 pushing ...subrepo ss
160 pushing ...subrepo ss
161 searching for changes
161 searching for changes
162 no changes found
162 no changes found
163 pushing ...subrepo s
163 pushing ...subrepo s
164 searching for changes
164 searching for changes
165 (did you forget to merge? use push -f to force)
165 (did you forget to merge? use push -f to force)
166 pushing ...subrepo t
166 pushing ...subrepo t
167 searching for changes
167 searching for changes
168 no changes found
168 no changes found
169 searching for changes
169 searching for changes
170 adding changesets
170 adding changesets
171 adding manifests
171 adding manifests
172 adding file changes
172 adding file changes
173 added 1 changesets with 1 changes to 1 files
173 added 1 changesets with 1 changes to 1 files
174 pushing ...sub/t
174 pushing ...sub/t
175 pushing ...subrepo ss
175 pushing ...subrepo ss
176 searching for changes
176 searching for changes
177 no changes found
177 no changes found
178 pushing ...subrepo s
178 pushing ...subrepo s
179 searching for changes
179 searching for changes
180 adding changesets
180 adding changesets
181 adding manifests
181 adding manifests
182 adding file changes
182 adding file changes
183 added 1 changesets with 1 changes to 1 files (+1 heads)
183 added 1 changesets with 1 changes to 1 files (+1 heads)
184 pushing ...subrepo t
184 pushing ...subrepo t
185 searching for changes
185 searching for changes
186 no changes found
186 no changes found
187 searching for changes
187 searching for changes
188 no changes found
188 no changes found
189 % update
189 % update
190 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 committing subrepository t
191 committing subrepository t
192 % pull
192 % pull
193 pulling ...sub/t
193 pulling ...sub/t
194 searching for changes
194 searching for changes
195 adding changesets
195 adding changesets
196 adding manifests
196 adding manifests
197 adding file changes
197 adding file changes
198 added 1 changesets with 1 changes to 1 files
198 added 1 changesets with 1 changes to 1 files
199 (run 'hg update' to get a working copy)
199 (run 'hg update' to get a working copy)
200 pulling subrepo t
200 pulling subrepo t
201 searching for changes
201 searching for changes
202 adding changesets
202 adding changesets
203 adding manifests
203 adding manifests
204 adding file changes
204 adding file changes
205 added 1 changesets with 1 changes to 1 files
205 added 1 changesets with 1 changes to 1 files
206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 blah
207 blah
208 % bogus subrepo path aborts
208 % bogus subrepo path aborts
209 abort: missing ] in subrepo source
209 abort: missing ] in subrepo source
210 % issue 1986
210 % issue 1986
211 adding a
211 adding a
212 marked working directory as branch br
212 marked working directory as branch br
213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
214 adding b
214 adding b
215 created new head
215 created new head
216 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
216 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
217 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
218 (branch merge, don't forget to commit)
218 (branch merge, don't forget to commit)
219 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
219 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 adding c
220 adding c
221 created new head
221 created new head
222 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
222 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
223 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
223 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 (branch merge, don't forget to commit)
224 (branch merge, don't forget to commit)
225 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
225 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
226 adding .hgsub
226 adding .hgsub
227 committing subrepository s
227 committing subrepository s
228 marked working directory as branch br
228 marked working directory as branch br
229 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
230 adding b
230 adding b
231 committing subrepository s
231 committing subrepository s
232 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
232 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
233 adding c
233 adding c
234 created new head
234 created new head
235 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
235 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
236 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
237 (branch merge, don't forget to commit)
237 (branch merge, don't forget to commit)
238 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
238 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
239 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
240 adding d
240 adding d
241 committing subrepository s
241 committing subrepository s
242 created new head
242 created new head
243 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
243 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
244 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 adding e
245 adding e
246 committing subrepository s
246 committing subrepository s
247 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
247 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
248 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
248 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
249 (branch merge, don't forget to commit)
249 (branch merge, don't forget to commit)
250 % test subrepo delete from .hgsubstate
250 % test subrepo delete from .hgsubstate
251 adding testdelete/nested/foo
251 adding testdelete/nested/foo
252 adding testdelete/nested2/foo
252 adding testdelete/nested2/foo
253 adding testdelete/.hgsub
253 adding testdelete/.hgsub
254 committing subrepository nested2
254 committing subrepository nested2
255 committing subrepository nested
255 committing subrepository nested
256 nested
256 nested
257 % test repository cloning
257 % test repository cloning
258 adding nested_absolute/foo
258 adding nested_absolute/foo
259 adding nested_relative/foo2
259 adding nested_relative/foo2
260 adding main/.hgsub
260 adding main/.hgsub
261 committing subrepository nested_relative
261 committing subrepository nested_relative
262 committing subrepository nested_absolute
262 committing subrepository nested_absolute
263 updating to branch default
263 updating to branch default
264 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
265 [paths]
265 [paths]
266 default = $HGTMP/test-subrepo/sub/mercurial/main/nested_absolute
266 default = $HGTMP/test-subrepo/sub/mercurial/nested_absolute
267 [paths]
267 [paths]
268 default = $HGTMP/test-subrepo/sub/mercurial/main/nested_relative
268 default = $HGTMP/test-subrepo/sub/mercurial/main/../nested_relative
General Comments 0
You need to be logged in to leave comments. Login now