##// END OF EJS Templates
subrepo: wrap long line
Martin Geisler -
r10671:001ffc2b default
parent child Browse files
Show More
@@ -1,369 +1,370 b''
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 = os.path.join(_abssource(ctx._repo), path)
197 addpathconfig('default', defpath)
197 addpathconfig('default', defpath)
198 fp.close()
198 fp.close()
199
199
200 def dirty(self):
200 def dirty(self):
201 r = self._state[1]
201 r = self._state[1]
202 if r == '':
202 if r == '':
203 return True
203 return True
204 w = self._repo[None]
204 w = self._repo[None]
205 if w.p1() != self._repo[r]: # version checked out change
205 if w.p1() != self._repo[r]: # version checked out change
206 return True
206 return True
207 return w.dirty() # working directory changed
207 return w.dirty() # working directory changed
208
208
209 def commit(self, text, user, date):
209 def commit(self, text, user, date):
210 self._repo.ui.debug("committing subrepo %s\n" % self._path)
210 self._repo.ui.debug("committing subrepo %s\n" % self._path)
211 n = self._repo.commit(text, user, date)
211 n = self._repo.commit(text, user, date)
212 if not n:
212 if not n:
213 return self._repo['.'].hex() # different version checked out
213 return self._repo['.'].hex() # different version checked out
214 return node.hex(n)
214 return node.hex(n)
215
215
216 def remove(self):
216 def remove(self):
217 # we can't fully delete the repository as it may contain
217 # we can't fully delete the repository as it may contain
218 # local-only history
218 # local-only history
219 self._repo.ui.note(_('removing subrepo %s\n') % self._path)
219 self._repo.ui.note(_('removing subrepo %s\n') % self._path)
220 hg.clean(self._repo, node.nullid, False)
220 hg.clean(self._repo, node.nullid, False)
221
221
222 def _get(self, state):
222 def _get(self, state):
223 source, revision, kind = state
223 source, revision, kind = state
224 try:
224 try:
225 self._repo.lookup(revision)
225 self._repo.lookup(revision)
226 except error.RepoError:
226 except error.RepoError:
227 self._repo._subsource = source
227 self._repo._subsource = source
228 srcurl = _abssource(self._repo)
228 srcurl = _abssource(self._repo)
229 self._repo.ui.status(_('pulling subrepo %s from %s\n') % (self._path, srcurl))
229 self._repo.ui.status(_('pulling subrepo %s from %s\n')
230 % (self._path, srcurl))
230 other = hg.repository(self._repo.ui, srcurl)
231 other = hg.repository(self._repo.ui, srcurl)
231 self._repo.pull(other)
232 self._repo.pull(other)
232
233
233 def get(self, state):
234 def get(self, state):
234 self._get(state)
235 self._get(state)
235 source, revision, kind = state
236 source, revision, kind = state
236 self._repo.ui.debug("getting subrepo %s\n" % self._path)
237 self._repo.ui.debug("getting subrepo %s\n" % self._path)
237 hg.clean(self._repo, revision, False)
238 hg.clean(self._repo, revision, False)
238
239
239 def merge(self, state):
240 def merge(self, state):
240 self._get(state)
241 self._get(state)
241 cur = self._repo['.']
242 cur = self._repo['.']
242 dst = self._repo[state[1]]
243 dst = self._repo[state[1]]
243 anc = dst.ancestor(cur)
244 anc = dst.ancestor(cur)
244 if anc == cur:
245 if anc == cur:
245 self._repo.ui.debug("updating subrepo %s\n" % self._path)
246 self._repo.ui.debug("updating subrepo %s\n" % self._path)
246 hg.update(self._repo, state[1])
247 hg.update(self._repo, state[1])
247 elif anc == dst:
248 elif anc == dst:
248 self._repo.ui.debug("skipping subrepo %s\n" % self._path)
249 self._repo.ui.debug("skipping subrepo %s\n" % self._path)
249 else:
250 else:
250 self._repo.ui.debug("merging subrepo %s\n" % self._path)
251 self._repo.ui.debug("merging subrepo %s\n" % self._path)
251 hg.merge(self._repo, state[1], remind=False)
252 hg.merge(self._repo, state[1], remind=False)
252
253
253 def push(self, force):
254 def push(self, force):
254 # push subrepos depth-first for coherent ordering
255 # push subrepos depth-first for coherent ordering
255 c = self._repo['']
256 c = self._repo['']
256 subs = c.substate # only repos that are committed
257 subs = c.substate # only repos that are committed
257 for s in sorted(subs):
258 for s in sorted(subs):
258 c.sub(s).push(force)
259 c.sub(s).push(force)
259
260
260 self._repo.ui.status(_('pushing subrepo %s\n') % self._path)
261 self._repo.ui.status(_('pushing subrepo %s\n') % self._path)
261 dsturl = _abssource(self._repo, True)
262 dsturl = _abssource(self._repo, True)
262 other = hg.repository(self._repo.ui, dsturl)
263 other = hg.repository(self._repo.ui, dsturl)
263 self._repo.push(other, force)
264 self._repo.push(other, force)
264
265
265 class svnsubrepo(object):
266 class svnsubrepo(object):
266 def __init__(self, ctx, path, state):
267 def __init__(self, ctx, path, state):
267 self._path = path
268 self._path = path
268 self._state = state
269 self._state = state
269 self._ctx = ctx
270 self._ctx = ctx
270 self._ui = ctx._repo.ui
271 self._ui = ctx._repo.ui
271
272
272 def _svncommand(self, commands):
273 def _svncommand(self, commands):
273 cmd = ['svn'] + commands + [self._path]
274 cmd = ['svn'] + commands + [self._path]
274 cmd = [util.shellquote(arg) for arg in cmd]
275 cmd = [util.shellquote(arg) for arg in cmd]
275 cmd = util.quotecommand(' '.join(cmd))
276 cmd = util.quotecommand(' '.join(cmd))
276 env = dict(os.environ)
277 env = dict(os.environ)
277 # Avoid localized output, preserve current locale for everything else.
278 # Avoid localized output, preserve current locale for everything else.
278 env['LC_MESSAGES'] = 'C'
279 env['LC_MESSAGES'] = 'C'
279 write, read, err = util.popen3(cmd, env=env, newlines=True)
280 write, read, err = util.popen3(cmd, env=env, newlines=True)
280 retdata = read.read()
281 retdata = read.read()
281 err = err.read().strip()
282 err = err.read().strip()
282 if err:
283 if err:
283 raise util.Abort(err)
284 raise util.Abort(err)
284 return retdata
285 return retdata
285
286
286 def _wcrev(self):
287 def _wcrev(self):
287 output = self._svncommand(['info', '--xml'])
288 output = self._svncommand(['info', '--xml'])
288 doc = xml.dom.minidom.parseString(output)
289 doc = xml.dom.minidom.parseString(output)
289 entries = doc.getElementsByTagName('entry')
290 entries = doc.getElementsByTagName('entry')
290 if not entries:
291 if not entries:
291 return 0
292 return 0
292 return int(entries[0].getAttribute('revision') or 0)
293 return int(entries[0].getAttribute('revision') or 0)
293
294
294 def _wcchanged(self):
295 def _wcchanged(self):
295 """Return (changes, extchanges) where changes is True
296 """Return (changes, extchanges) where changes is True
296 if the working directory was changed, and extchanges is
297 if the working directory was changed, and extchanges is
297 True if any of these changes concern an external entry.
298 True if any of these changes concern an external entry.
298 """
299 """
299 output = self._svncommand(['status', '--xml'])
300 output = self._svncommand(['status', '--xml'])
300 externals, changes = [], []
301 externals, changes = [], []
301 doc = xml.dom.minidom.parseString(output)
302 doc = xml.dom.minidom.parseString(output)
302 for e in doc.getElementsByTagName('entry'):
303 for e in doc.getElementsByTagName('entry'):
303 s = e.getElementsByTagName('wc-status')
304 s = e.getElementsByTagName('wc-status')
304 if not s:
305 if not s:
305 continue
306 continue
306 item = s[0].getAttribute('item')
307 item = s[0].getAttribute('item')
307 props = s[0].getAttribute('props')
308 props = s[0].getAttribute('props')
308 path = e.getAttribute('path')
309 path = e.getAttribute('path')
309 if item == 'external':
310 if item == 'external':
310 externals.append(path)
311 externals.append(path)
311 if (item not in ('', 'normal', 'unversioned', 'external')
312 if (item not in ('', 'normal', 'unversioned', 'external')
312 or props not in ('', 'none')):
313 or props not in ('', 'none')):
313 changes.append(path)
314 changes.append(path)
314 for path in changes:
315 for path in changes:
315 for ext in externals:
316 for ext in externals:
316 if path == ext or path.startswith(ext + os.sep):
317 if path == ext or path.startswith(ext + os.sep):
317 return True, True
318 return True, True
318 return bool(changes), False
319 return bool(changes), False
319
320
320 def dirty(self):
321 def dirty(self):
321 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
322 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
322 return False
323 return False
323 return True
324 return True
324
325
325 def commit(self, text, user, date):
326 def commit(self, text, user, date):
326 # user and date are out of our hands since svn is centralized
327 # user and date are out of our hands since svn is centralized
327 changed, extchanged = self._wcchanged()
328 changed, extchanged = self._wcchanged()
328 if not changed:
329 if not changed:
329 return self._wcrev()
330 return self._wcrev()
330 if extchanged:
331 if extchanged:
331 # Do not try to commit externals
332 # Do not try to commit externals
332 raise util.Abort(_('cannot commit svn externals'))
333 raise util.Abort(_('cannot commit svn externals'))
333 commitinfo = self._svncommand(['commit', '-m', text])
334 commitinfo = self._svncommand(['commit', '-m', text])
334 self._ui.status(commitinfo)
335 self._ui.status(commitinfo)
335 newrev = re.search('Committed revision ([\d]+).', commitinfo)
336 newrev = re.search('Committed revision ([\d]+).', commitinfo)
336 if not newrev:
337 if not newrev:
337 raise util.Abort(commitinfo.splitlines()[-1])
338 raise util.Abort(commitinfo.splitlines()[-1])
338 newrev = newrev.groups()[0]
339 newrev = newrev.groups()[0]
339 self._ui.status(self._svncommand(['update', '-r', newrev]))
340 self._ui.status(self._svncommand(['update', '-r', newrev]))
340 return newrev
341 return newrev
341
342
342 def remove(self):
343 def remove(self):
343 if self.dirty():
344 if self.dirty():
344 self._ui.warn(_('not removing repo %s because '
345 self._ui.warn(_('not removing repo %s because '
345 'it has changes.\n' % self._path))
346 'it has changes.\n' % self._path))
346 return
347 return
347 self._ui.note(_('removing subrepo %s\n') % self._path)
348 self._ui.note(_('removing subrepo %s\n') % self._path)
348 shutil.rmtree(self._ctx.repo.join(self._path))
349 shutil.rmtree(self._ctx.repo.join(self._path))
349
350
350 def get(self, state):
351 def get(self, state):
351 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
352 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
352 if not re.search('Checked out revision [\d]+.', status):
353 if not re.search('Checked out revision [\d]+.', status):
353 raise util.Abort(status.splitlines()[-1])
354 raise util.Abort(status.splitlines()[-1])
354 self._ui.status(status)
355 self._ui.status(status)
355
356
356 def merge(self, state):
357 def merge(self, state):
357 old = int(self._state[1])
358 old = int(self._state[1])
358 new = int(state[1])
359 new = int(state[1])
359 if new > old:
360 if new > old:
360 self.get(state)
361 self.get(state)
361
362
362 def push(self, force):
363 def push(self, force):
363 # nothing for svn
364 # nothing for svn
364 pass
365 pass
365
366
366 types = {
367 types = {
367 'hg': hgsubrepo,
368 'hg': hgsubrepo,
368 'svn': svnsubrepo,
369 'svn': svnsubrepo,
369 }
370 }
General Comments 0
You need to be logged in to leave comments. Login now