3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com> |
3 # Copyright 2006, 2007 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, incorporated herein by reference. |
6 # GNU General Public License version 2, incorporated herein by reference. |
7 |
7 |
8 import errno, os |
8 import errno, os, re |
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') |
248 self._repo.ui.status(_('pushing subrepo %s\n') % self._path) |
248 self._repo.ui.status(_('pushing subrepo %s\n') % self._path) |
249 dsturl = _abssource(self._repo, True) |
249 dsturl = _abssource(self._repo, True) |
250 other = hg.repository(self._repo.ui, dsturl) |
250 other = hg.repository(self._repo.ui, dsturl) |
251 self._repo.push(other, force) |
251 self._repo.push(other, force) |
252 |
252 |
|
253 class svnsubrepo(object): |
|
254 def __init__(self, ctx, path, state): |
|
255 self._path = path |
|
256 self._state = state |
|
257 self._ctx = ctx |
|
258 self._ui = ctx._repo.ui |
|
259 |
|
260 def _svncommand(self, commands): |
|
261 cmd = ['svn'] + commands + [self._path] |
|
262 cmd = [util.shellquote(arg) for arg in cmd] |
|
263 cmd = util.quotecommand(' '.join(cmd)) |
|
264 write, read, err = util.popen3(cmd) |
|
265 retdata = read.read() |
|
266 err = err.read().strip() |
|
267 if err: |
|
268 raise util.Abort(err) |
|
269 return retdata |
|
270 |
|
271 def _wcrev(self): |
|
272 info = self._svncommand(['info']) |
|
273 mat = re.search('Revision: ([\d]+)\n', info) |
|
274 if not mat: |
|
275 return 0 |
|
276 return mat.groups()[0] |
|
277 |
|
278 def _url(self): |
|
279 info = self._svncommand(['info']) |
|
280 mat = re.search('URL: ([^\n]+)\n', info) |
|
281 if not mat: |
|
282 return 0 |
|
283 return mat.groups()[0] |
|
284 |
|
285 def _wcclean(self): |
|
286 status = self._svncommand(['status']) |
|
287 status = '\n'.join([s for s in status.splitlines() if s[0] != '?']) |
|
288 if status.strip(): |
|
289 return False |
|
290 return True |
|
291 |
|
292 def dirty(self): |
|
293 if self._wcrev() == self._state[1] and self._wcclean(): |
|
294 return False |
|
295 return True |
|
296 |
|
297 def commit(self, text, user, date): |
|
298 # user and date are out of our hands since svn is centralized |
|
299 if self._wcclean(): |
|
300 return self._wcrev() |
|
301 commitinfo = self._svncommand(['commit', '-m', text]) |
|
302 self._ui.status(commitinfo) |
|
303 newrev = re.search('Committed revision ([\d]+).', commitinfo) |
|
304 if not newrev: |
|
305 raise util.Abort(commitinfo.splitlines()[-1]) |
|
306 newrev = newrev.groups()[0] |
|
307 self._ui.status(self._svncommand(['update', '-r', newrev])) |
|
308 return newrev |
|
309 |
|
310 def remove(self): |
|
311 if self.dirty(): |
|
312 self._repo.ui.warn('Not removing repo %s because' |
|
313 'it has changes.\n' % self._path) |
|
314 return |
|
315 self._repo.ui.note('removing subrepo %s\n' % self._path) |
|
316 shutil.rmtree(self._ctx.repo.join(self._path)) |
|
317 |
|
318 def get(self, state): |
|
319 status = self._svncommand(['checkout', state[0], '--revision', state[1]]) |
|
320 if not re.search('Checked out revision [\d]+.', status): |
|
321 raise util.Abort(status.splitlines()[-1]) |
|
322 self._ui.status(status) |
|
323 |
|
324 def merge(self, state): |
|
325 old = int(self._state[1]) |
|
326 new = int(state[1]) |
|
327 if new > old: |
|
328 self.get(state) |
|
329 |
|
330 def push(self, force): |
|
331 # nothing for svn |
|
332 pass |
|
333 |
253 types = { |
334 types = { |
254 'hg': hgsubrepo, |
335 'hg': hgsubrepo, |
|
336 'svn': svnsubrepo, |
255 } |
337 } |