El siguiente script permite tener sincronizado un repositorio mercurial con un subversion. Solo es, como se diría "one-way".
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# $Id$
#
# (c) 2007 - Rolando Espinoza La Fuente <darkrho@gmail.com>
# Distributed under the BSD License
# Use at your own risk!
#
# This script make a mercurial repository from a svn one.
# Keeping revision history with authors and dates.
# Just convert one-way, svn to hg. If you want two-way conversion checkout tailor.
#
#
# Requirements:
# - Mercurial of course ;)
# - pysvn subversion bindings
# Ubuntu users: apt-get install python-svn
#
# Based on:
# <a href="http://www.selenic.com/mercurial/wiki/index.cgi/SubversionToMercurialSync">http://www.selenic.com/mercurial/wiki/index.cgi/SubversionToMe</a>
#
# (use backups)
# Usage: svn2hg.py svnrepo
#
# Tested on Ubuntu Edgy against small repositories (<20Mb)
# TODO: Need more testing
import sys, os
# really don't need cPickle
# TODO: take out cPickle
import cPickle
import pysvn # svn functions
import mercurial.commands # hg functions
class svn2hg:
def __init__(self, args):
if len(args) != 1:
sys.stderr.write("[*] Error: have to provide one argumentn")
sys.exit(-1)
if not os.path.isdir(args[0]):
sys.stderr.write("[*] Error: argument must be a directoryn")
sys.exit(-1)
else:
self.path = os.path.realpath(args[0]) + os.path.sep
self.statefile = self.path + '.svn2hg_state'
def _pysvnrev(self, rev):
return pysvn.Revision(pysvn.opt_revision_kind.number, rev)
def savestate(self):
#TODO: try/catch errors
if self.currev:
try:
cPickle.dump(self.currev, open(self.statefile,'wb+'))
except:
pass
def loadstate(self):
#TODO: try/catch errors
if os.path.exists(self.statefile):
try:
self.currev = cPickle.load(open(self.statefile))
except:
self.currev = None
pass
else:
self.currev = None
def builddate(self, timestamp):
from datetime import datetime
import time
format = '%Y-%m-%d %H:%M'
date = datetime.fromtimestamp(timestamp)
return time.strftime(format, date.timetuple())
def check_hg(self):
hgdir = self.path + '.hg'
hgignore = self.path + '.hgignore'
if not os.path.exists(hgdir):
self.hg.dispatch(['init',self.path])
ignoreme = ".hgignoren.svnn" + os.path.basename(self.statefile) + 'n'
open(hgignore, 'w').writelines(ignoreme)
elif not os.path.isdir(hgdir):
sys.stderr.write("[*] Error: unknown .hg directoryn")
sys.exit(-1)
def check_svn(self):
svndir = self.path + '.svn'
if not os.path.exists(svndir) or not os.path.isdir(svndir):
sys.stderr.write("[*] Error: unknown .svn directoryn")
sys.exit(-1)
def run(self):
self.loadstate()
self.svn = pysvn.Client()
self.hg = mercurial.commands
self.check_hg()
self.check_svn()
# why?
# get local repo info to get the url
self.info = self.svn.info2(self.path, recurse=False)[0][1]
#self.url = self.info['repos_root_URL']
self.url = self.info['URL']
## Get current revisions...
#print '+ Updating svn repos... '
#self.newrev = self.svn.update(self.path)[0]
#self.newrev = self.newrev.number
#print 'donen'
# Getting last revision
print '[+] Getting last revision number from remote repo... '
self.remoteinfo = self.svn.info2(self.url, recurse=False)[0][1]
self.newrev = self.remoteinfo['last_changed_rev'].number
# newer revision?
if not self.currev == self.newrev:
if not self.currev:
self.currev = 0
print '[+] Getting remote changelog from r%s up to r%s)... ' % (self.currev, self.newrev)
svnlog = self.svn.log(self.url, self._pysvnrev(self.newrev), self._pysvnrev(self.currev))
# reverse to process from old to new
svnlog.reverse()
# fix, hg needs to 'be' inside the repo
os.chdir(self.path)
# cset dict
# - author ""
# - changed_paths []
# - date timestamp
# - message ""
# - revision _pysvnrev
# process one by one
for cset in svnlog:
# update to rev
localrev = self.svn.update(self.path, revision=cset['revision'])[0]
if not cset['message']:
# dirty hack to prevent rollback on empty svn commit message
cset['message'] = cset['author']
# commit changes to hg
# mantain the same author, message and date of the changeset
print '[+] Process revision r%s ...' % (localrev.number)
self.hg.dispatch(['commit', '-A', '-m', cset['message'],
'-u', cset['author'],
'-d', self.builddate(cset['date'])])
# save newrev as currev
self.currev = self.newrev
else:
print '[-] Nothing to do'
# save currev to a file for further updates
self.savestate()
if __name__ == '__main__':
main = svn2hg(sys.argv[1:])
sys.exit(main.run())
Palabras clave: convert svn to hg, mercuial to subversion, mercurial, python, script, subversion, svn2hg, tailor
Comentarios