##// END OF EJS Templates
subrepo: fix 2.5ism in url parsing
Matt Mackall -
r11117:dd543e8d default
parent child Browse files
Show More
@@ -1,388 +1,388 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, urlparse, posixpath
8 import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
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 relpath(sub):
129 def relpath(sub):
130 if not hasattr(sub, '_repo'):
130 if not hasattr(sub, '_repo'):
131 return sub._path
131 return sub._path
132 parent = sub._repo
132 parent = sub._repo
133 while hasattr(parent, '_subparent'):
133 while hasattr(parent, '_subparent'):
134 parent = parent._subparent
134 parent = parent._subparent
135 return sub._repo.root[len(parent.root)+1:]
135 return sub._repo.root[len(parent.root)+1:]
136
136
137 def _abssource(repo, push=False):
137 def _abssource(repo, push=False):
138 if hasattr(repo, '_subparent'):
138 if hasattr(repo, '_subparent'):
139 source = repo._subsource
139 source = repo._subsource
140 if source.startswith('/') or '://' in source:
140 if source.startswith('/') or '://' in source:
141 return source
141 return source
142 parent = _abssource(repo._subparent, push)
142 parent = _abssource(repo._subparent, push)
143 if '://' in parent:
143 if '://' in parent:
144 if parent[-1] == '/':
144 if parent[-1] == '/':
145 parent = parent[:-1]
145 parent = parent[:-1]
146 r = urlparse.urlparse(parent + '/' + source)
146 r = urlparse.urlparse(parent + '/' + source)
147 r = urlparse.urlunparse((r[0], r[1],
147 r = urlparse.urlunparse((r[0], r[1],
148 posixpath.normpath(r.path),
148 posixpath.normpath(r[2]),
149 r[3], r[4], r[5]))
149 r[3], r[4], r[5]))
150 return r
150 return r
151 return posixpath.normpath(os.path.join(parent, repo._subsource))
151 return posixpath.normpath(os.path.join(parent, repo._subsource))
152 if push and repo.ui.config('paths', 'default-push'):
152 if push and repo.ui.config('paths', 'default-push'):
153 return repo.ui.config('paths', 'default-push', repo.root)
153 return repo.ui.config('paths', 'default-push', repo.root)
154 return repo.ui.config('paths', 'default', repo.root)
154 return repo.ui.config('paths', 'default', repo.root)
155
155
156 def subrepo(ctx, path):
156 def subrepo(ctx, path):
157 # subrepo inherently violates our import layering rules
157 # subrepo inherently violates our import layering rules
158 # because it wants to make repo objects from deep inside the stack
158 # because it wants to make repo objects from deep inside the stack
159 # so we manually delay the circular imports to not break
159 # so we manually delay the circular imports to not break
160 # scripts that don't use our demand-loading
160 # scripts that don't use our demand-loading
161 global hg
161 global hg
162 import hg as h
162 import hg as h
163 hg = h
163 hg = h
164
164
165 util.path_auditor(ctx._repo.root)(path)
165 util.path_auditor(ctx._repo.root)(path)
166 state = ctx.substate.get(path, nullstate)
166 state = ctx.substate.get(path, nullstate)
167 if state[2] not in types:
167 if state[2] not in types:
168 raise util.Abort(_('unknown subrepo type %s') % state[2])
168 raise util.Abort(_('unknown subrepo type %s') % state[2])
169 return types[state[2]](ctx, path, state[:2])
169 return types[state[2]](ctx, path, state[:2])
170
170
171 # subrepo classes need to implement the following methods:
171 # subrepo classes need to implement the following methods:
172 # __init__(self, ctx, path, state)
172 # __init__(self, ctx, path, state)
173 # dirty(self): returns true if the dirstate of the subrepo
173 # dirty(self): returns true if the dirstate of the subrepo
174 # does not match current stored state
174 # does not match current stored state
175 # commit(self, text, user, date): commit the current changes
175 # commit(self, text, user, date): commit the current changes
176 # to the subrepo with the given log message. Use given
176 # to the subrepo with the given log message. Use given
177 # user and date if possible. Return the new state of the subrepo.
177 # user and date if possible. Return the new state of the subrepo.
178 # remove(self): remove the subrepo (should verify the dirstate
178 # remove(self): remove the subrepo (should verify the dirstate
179 # is not dirty first)
179 # is not dirty first)
180 # get(self, state): run whatever commands are needed to put the
180 # get(self, state): run whatever commands are needed to put the
181 # subrepo into this state
181 # subrepo into this state
182 # merge(self, state): merge currently-saved state with the new state.
182 # merge(self, state): merge currently-saved state with the new state.
183 # push(self, force): perform whatever action is analagous to 'hg push'
183 # push(self, force): perform whatever action is analagous to 'hg push'
184 # This may be a no-op on some systems.
184 # This may be a no-op on some systems.
185
185
186 class hgsubrepo(object):
186 class hgsubrepo(object):
187 def __init__(self, ctx, path, state):
187 def __init__(self, ctx, path, state):
188 self._path = path
188 self._path = path
189 self._state = state
189 self._state = state
190 r = ctx._repo
190 r = ctx._repo
191 root = r.wjoin(path)
191 root = r.wjoin(path)
192 create = False
192 create = False
193 if not os.path.exists(os.path.join(root, '.hg')):
193 if not os.path.exists(os.path.join(root, '.hg')):
194 create = True
194 create = True
195 util.makedirs(root)
195 util.makedirs(root)
196 self._repo = hg.repository(r.ui, root, create=create)
196 self._repo = hg.repository(r.ui, root, create=create)
197 self._repo._subparent = r
197 self._repo._subparent = r
198 self._repo._subsource = state[0]
198 self._repo._subsource = state[0]
199
199
200 if create:
200 if create:
201 fp = self._repo.opener("hgrc", "w", text=True)
201 fp = self._repo.opener("hgrc", "w", text=True)
202 fp.write('[paths]\n')
202 fp.write('[paths]\n')
203
203
204 def addpathconfig(key, value):
204 def addpathconfig(key, value):
205 fp.write('%s = %s\n' % (key, value))
205 fp.write('%s = %s\n' % (key, value))
206 self._repo.ui.setconfig('paths', key, value)
206 self._repo.ui.setconfig('paths', key, value)
207
207
208 defpath = _abssource(self._repo)
208 defpath = _abssource(self._repo)
209 defpushpath = _abssource(self._repo, True)
209 defpushpath = _abssource(self._repo, True)
210 addpathconfig('default', defpath)
210 addpathconfig('default', defpath)
211 if defpath != defpushpath:
211 if defpath != defpushpath:
212 addpathconfig('default-push', defpushpath)
212 addpathconfig('default-push', defpushpath)
213 fp.close()
213 fp.close()
214
214
215 def dirty(self):
215 def dirty(self):
216 r = self._state[1]
216 r = self._state[1]
217 if r == '':
217 if r == '':
218 return True
218 return True
219 w = self._repo[None]
219 w = self._repo[None]
220 if w.p1() != self._repo[r]: # version checked out change
220 if w.p1() != self._repo[r]: # version checked out change
221 return True
221 return True
222 return w.dirty() # working directory changed
222 return w.dirty() # working directory changed
223
223
224 def commit(self, text, user, date):
224 def commit(self, text, user, date):
225 self._repo.ui.debug("committing subrepo %s\n" % relpath(self))
225 self._repo.ui.debug("committing subrepo %s\n" % relpath(self))
226 n = self._repo.commit(text, user, date)
226 n = self._repo.commit(text, user, date)
227 if not n:
227 if not n:
228 return self._repo['.'].hex() # different version checked out
228 return self._repo['.'].hex() # different version checked out
229 return node.hex(n)
229 return node.hex(n)
230
230
231 def remove(self):
231 def remove(self):
232 # we can't fully delete the repository as it may contain
232 # we can't fully delete the repository as it may contain
233 # local-only history
233 # local-only history
234 self._repo.ui.note(_('removing subrepo %s\n') % relpath(self))
234 self._repo.ui.note(_('removing subrepo %s\n') % relpath(self))
235 hg.clean(self._repo, node.nullid, False)
235 hg.clean(self._repo, node.nullid, False)
236
236
237 def _get(self, state):
237 def _get(self, state):
238 source, revision, kind = state
238 source, revision, kind = state
239 try:
239 try:
240 self._repo.lookup(revision)
240 self._repo.lookup(revision)
241 except error.RepoError:
241 except error.RepoError:
242 self._repo._subsource = source
242 self._repo._subsource = source
243 srcurl = _abssource(self._repo)
243 srcurl = _abssource(self._repo)
244 self._repo.ui.status(_('pulling subrepo %s from %s\n')
244 self._repo.ui.status(_('pulling subrepo %s from %s\n')
245 % (relpath(self), srcurl))
245 % (relpath(self), srcurl))
246 other = hg.repository(self._repo.ui, srcurl)
246 other = hg.repository(self._repo.ui, srcurl)
247 self._repo.pull(other)
247 self._repo.pull(other)
248
248
249 def get(self, state):
249 def get(self, state):
250 self._get(state)
250 self._get(state)
251 source, revision, kind = state
251 source, revision, kind = state
252 self._repo.ui.debug("getting subrepo %s\n" % self._path)
252 self._repo.ui.debug("getting subrepo %s\n" % self._path)
253 hg.clean(self._repo, revision, False)
253 hg.clean(self._repo, revision, False)
254
254
255 def merge(self, state):
255 def merge(self, state):
256 self._get(state)
256 self._get(state)
257 cur = self._repo['.']
257 cur = self._repo['.']
258 dst = self._repo[state[1]]
258 dst = self._repo[state[1]]
259 anc = dst.ancestor(cur)
259 anc = dst.ancestor(cur)
260 if anc == cur:
260 if anc == cur:
261 self._repo.ui.debug("updating subrepo %s\n" % relpath(self))
261 self._repo.ui.debug("updating subrepo %s\n" % relpath(self))
262 hg.update(self._repo, state[1])
262 hg.update(self._repo, state[1])
263 elif anc == dst:
263 elif anc == dst:
264 self._repo.ui.debug("skipping subrepo %s\n" % relpath(self))
264 self._repo.ui.debug("skipping subrepo %s\n" % relpath(self))
265 else:
265 else:
266 self._repo.ui.debug("merging subrepo %s\n" % relpath(self))
266 self._repo.ui.debug("merging subrepo %s\n" % relpath(self))
267 hg.merge(self._repo, state[1], remind=False)
267 hg.merge(self._repo, state[1], remind=False)
268
268
269 def push(self, force):
269 def push(self, force):
270 # push subrepos depth-first for coherent ordering
270 # push subrepos depth-first for coherent ordering
271 c = self._repo['']
271 c = self._repo['']
272 subs = c.substate # only repos that are committed
272 subs = c.substate # only repos that are committed
273 for s in sorted(subs):
273 for s in sorted(subs):
274 if not c.sub(s).push(force):
274 if not c.sub(s).push(force):
275 return False
275 return False
276
276
277 dsturl = _abssource(self._repo, True)
277 dsturl = _abssource(self._repo, True)
278 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
278 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
279 (relpath(self), dsturl))
279 (relpath(self), dsturl))
280 other = hg.repository(self._repo.ui, dsturl)
280 other = hg.repository(self._repo.ui, dsturl)
281 return self._repo.push(other, force)
281 return self._repo.push(other, force)
282
282
283 class svnsubrepo(object):
283 class svnsubrepo(object):
284 def __init__(self, ctx, path, state):
284 def __init__(self, ctx, path, state):
285 self._path = path
285 self._path = path
286 self._state = state
286 self._state = state
287 self._ctx = ctx
287 self._ctx = ctx
288 self._ui = ctx._repo.ui
288 self._ui = ctx._repo.ui
289
289
290 def _svncommand(self, commands):
290 def _svncommand(self, commands):
291 path = os.path.join(self._ctx._repo.origroot, self._path)
291 path = os.path.join(self._ctx._repo.origroot, self._path)
292 cmd = ['svn'] + commands + [path]
292 cmd = ['svn'] + commands + [path]
293 cmd = [util.shellquote(arg) for arg in cmd]
293 cmd = [util.shellquote(arg) for arg in cmd]
294 cmd = util.quotecommand(' '.join(cmd))
294 cmd = util.quotecommand(' '.join(cmd))
295 env = dict(os.environ)
295 env = dict(os.environ)
296 # Avoid localized output, preserve current locale for everything else.
296 # Avoid localized output, preserve current locale for everything else.
297 env['LC_MESSAGES'] = 'C'
297 env['LC_MESSAGES'] = 'C'
298 write, read, err = util.popen3(cmd, env=env, newlines=True)
298 write, read, err = util.popen3(cmd, env=env, newlines=True)
299 retdata = read.read()
299 retdata = read.read()
300 err = err.read().strip()
300 err = err.read().strip()
301 if err:
301 if err:
302 raise util.Abort(err)
302 raise util.Abort(err)
303 return retdata
303 return retdata
304
304
305 def _wcrev(self):
305 def _wcrev(self):
306 output = self._svncommand(['info', '--xml'])
306 output = self._svncommand(['info', '--xml'])
307 doc = xml.dom.minidom.parseString(output)
307 doc = xml.dom.minidom.parseString(output)
308 entries = doc.getElementsByTagName('entry')
308 entries = doc.getElementsByTagName('entry')
309 if not entries:
309 if not entries:
310 return 0
310 return 0
311 return int(entries[0].getAttribute('revision') or 0)
311 return int(entries[0].getAttribute('revision') or 0)
312
312
313 def _wcchanged(self):
313 def _wcchanged(self):
314 """Return (changes, extchanges) where changes is True
314 """Return (changes, extchanges) where changes is True
315 if the working directory was changed, and extchanges is
315 if the working directory was changed, and extchanges is
316 True if any of these changes concern an external entry.
316 True if any of these changes concern an external entry.
317 """
317 """
318 output = self._svncommand(['status', '--xml'])
318 output = self._svncommand(['status', '--xml'])
319 externals, changes = [], []
319 externals, changes = [], []
320 doc = xml.dom.minidom.parseString(output)
320 doc = xml.dom.minidom.parseString(output)
321 for e in doc.getElementsByTagName('entry'):
321 for e in doc.getElementsByTagName('entry'):
322 s = e.getElementsByTagName('wc-status')
322 s = e.getElementsByTagName('wc-status')
323 if not s:
323 if not s:
324 continue
324 continue
325 item = s[0].getAttribute('item')
325 item = s[0].getAttribute('item')
326 props = s[0].getAttribute('props')
326 props = s[0].getAttribute('props')
327 path = e.getAttribute('path')
327 path = e.getAttribute('path')
328 if item == 'external':
328 if item == 'external':
329 externals.append(path)
329 externals.append(path)
330 if (item not in ('', 'normal', 'unversioned', 'external')
330 if (item not in ('', 'normal', 'unversioned', 'external')
331 or props not in ('', 'none')):
331 or props not in ('', 'none')):
332 changes.append(path)
332 changes.append(path)
333 for path in changes:
333 for path in changes:
334 for ext in externals:
334 for ext in externals:
335 if path == ext or path.startswith(ext + os.sep):
335 if path == ext or path.startswith(ext + os.sep):
336 return True, True
336 return True, True
337 return bool(changes), False
337 return bool(changes), False
338
338
339 def dirty(self):
339 def dirty(self):
340 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
340 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
341 return False
341 return False
342 return True
342 return True
343
343
344 def commit(self, text, user, date):
344 def commit(self, text, user, date):
345 # user and date are out of our hands since svn is centralized
345 # user and date are out of our hands since svn is centralized
346 changed, extchanged = self._wcchanged()
346 changed, extchanged = self._wcchanged()
347 if not changed:
347 if not changed:
348 return self._wcrev()
348 return self._wcrev()
349 if extchanged:
349 if extchanged:
350 # Do not try to commit externals
350 # Do not try to commit externals
351 raise util.Abort(_('cannot commit svn externals'))
351 raise util.Abort(_('cannot commit svn externals'))
352 commitinfo = self._svncommand(['commit', '-m', text])
352 commitinfo = self._svncommand(['commit', '-m', text])
353 self._ui.status(commitinfo)
353 self._ui.status(commitinfo)
354 newrev = re.search('Committed revision ([\d]+).', commitinfo)
354 newrev = re.search('Committed revision ([\d]+).', commitinfo)
355 if not newrev:
355 if not newrev:
356 raise util.Abort(commitinfo.splitlines()[-1])
356 raise util.Abort(commitinfo.splitlines()[-1])
357 newrev = newrev.groups()[0]
357 newrev = newrev.groups()[0]
358 self._ui.status(self._svncommand(['update', '-r', newrev]))
358 self._ui.status(self._svncommand(['update', '-r', newrev]))
359 return newrev
359 return newrev
360
360
361 def remove(self):
361 def remove(self):
362 if self.dirty():
362 if self.dirty():
363 self._ui.warn(_('not removing repo %s because '
363 self._ui.warn(_('not removing repo %s because '
364 'it has changes.\n' % self._path))
364 'it has changes.\n' % self._path))
365 return
365 return
366 self._ui.note(_('removing subrepo %s\n') % self._path)
366 self._ui.note(_('removing subrepo %s\n') % self._path)
367 shutil.rmtree(self._ctx.repo.join(self._path))
367 shutil.rmtree(self._ctx.repo.join(self._path))
368
368
369 def get(self, state):
369 def get(self, state):
370 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
370 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
371 if not re.search('Checked out revision [\d]+.', status):
371 if not re.search('Checked out revision [\d]+.', status):
372 raise util.Abort(status.splitlines()[-1])
372 raise util.Abort(status.splitlines()[-1])
373 self._ui.status(status)
373 self._ui.status(status)
374
374
375 def merge(self, state):
375 def merge(self, state):
376 old = int(self._state[1])
376 old = int(self._state[1])
377 new = int(state[1])
377 new = int(state[1])
378 if new > old:
378 if new > old:
379 self.get(state)
379 self.get(state)
380
380
381 def push(self, force):
381 def push(self, force):
382 # nothing for svn
382 # nothing for svn
383 pass
383 pass
384
384
385 types = {
385 types = {
386 'hg': hgsubrepo,
386 'hg': hgsubrepo,
387 'svn': svnsubrepo,
387 'svn': svnsubrepo,
388 }
388 }
General Comments 0
You need to be logged in to leave comments. Login now