Mercurial > hgsubversion
view hgsubversion/svncommands.py @ 447:0d3b5acb1d51
tags: handle edits to tags as gracefully as possible
author | Augie Fackler <durin42@gmail.com> |
---|---|
date | Tue, 23 Jun 2009 21:38:27 -0500 |
parents | cbd230043379 |
children | fbc7cf4fd701 |
line wrap: on
line source
import os import cPickle as pickle from mercurial import hg from mercurial import node from mercurial import util as hgutil import svnwrap import svnmeta import util import utility_commands import svnexternals def verify(ui, repo, *args, **opts): '''verify current revision against Subversion repository ''' if not args: url = repo.ui.expandpath('default') else: url = args[0] ctx = repo[opts.get('rev', '.')] if 'close' in ctx.extra(): ui.write('cannot verify closed branch') return 0 srev = ctx.extra().get('convert_revision') if srev is None: raise hgutil.Abort('revision %s not from SVN' % ctx) srev = int(srev.split('@')[1]) ui.write('verifying %s against r%i\n' % (ctx, srev)) url = util.normalize_url(url.rstrip('/')) user, passwd = util.getuserpass(opts) svn = svnwrap.SubversionRepo(url, user, passwd) btypes = {'default': 'trunk'} branchpath = btypes.get(ctx.branch(), 'branches/%s' % ctx.branch()) svnfiles = set() result = 0 for fn, type in svn.list_files(branchpath, srev): if type != 'f': continue svnfiles.add(fn) data, mode = svn.get_file(branchpath + '/' + fn, srev) fctx = ctx[fn] dmatch = fctx.data() == data mmatch = fctx.flags() == mode if not (dmatch and mmatch): ui.write('difference in file %s' % fn) result = 1 hgfiles = set(ctx) hgfiles.discard('.hgtags') hgfiles.discard('.hgsvnexternals') if hgfiles != svnfiles: missing = set(hgfiles).symmetric_difference(svnfiles) ui.write('missing files: %s' % (', '.join(missing))) result = 1 return result def rebuildmeta(ui, repo, hg_repo_path, args, **opts): """rebuild hgsubversion metadata using values stored in revisions """ if len(args) != 1: dest = args[0] url = repo.ui.expandpath(dest or 'default-push', dest or 'default') else: url = args[0] uuid = None url = util.normalize_url(url.rstrip('/')) user, passwd = util.getuserpass(opts) svn = svnwrap.SubversionRepo(url, user, passwd) subdir = svn.subdir svnmetadir = os.path.join(repo.path, 'svn') if not os.path.exists(svnmetadir): os.makedirs(svnmetadir) revmap = open(os.path.join(svnmetadir, 'rev_map'), 'w') revmap.write('1\n') last_rev = -1 branchinfo = {} noderevnums = {} for rev in repo: ctx = repo[rev] convinfo = ctx.extra().get('convert_revision', None) if not convinfo: continue # check that the conversion metadata matches expectations assert convinfo.startswith('svn:') revpath, revision = convinfo[40:].split('@') if subdir and subdir[0] != '/': subdir = '/' + subdir if subdir and subdir[-1] == '/': subdir = subdir[:-1] assert revpath.startswith(subdir), ('That does not look like the ' 'right location in the repo.') # write repository uuid if required if uuid is None: uuid = convinfo[4:40] assert uuid == svn.uuid, 'UUIDs did not match!' uuidfile = open(os.path.join(svnmetadir, 'uuid'), 'w') uuidfile.write(uuid) uuidfile.close() # don't reflect closed branches if ctx.extra().get('close') and not ctx.files(): continue # find commitpath, write to revmap commitpath = revpath[len(subdir)+1:] if commitpath.startswith('branches'): commitpath = commitpath[len('branches/'):] elif commitpath == 'trunk': commitpath = '' elif commitpath.startswith('tags'): if ctx.extra().get('close'): continue commitpath = '../' + commitpath else: assert False, 'Unhandled case in rebuildmeta' revmap.write('%s %s %s\n' % (revision, ctx.hex(), commitpath)) revision = int(revision) noderevnums[ctx.node()] = revision if revision > last_rev: last_rev = revision # deal with branches if ctx.extra().get('close'): continue branch = ctx.branch() if branch == 'default': branch = None if branch not in branchinfo: parent = ctx.parents()[0] if (parent.node() in noderevnums and parent.branch() != ctx.branch()): parentbranch = parent.branch() if parentbranch == 'default': parentbranch = None else: parentbranch = None branchinfo[branch] = (parentbranch, noderevnums.get(parent.node(), 0), revision) for cctx in ctx.children(): if cctx.extra().get('close'): branchinfo.pop(branch, None) break # save off branch info branchinfofile = open(os.path.join(svnmetadir, 'branch_info'), 'w') pickle.dump(branchinfo, branchinfofile) branchinfofile.close() def help(ui, args=None, **opts): """show help for a given subcommands or a help overview """ if args: subcommand = args[0] if subcommand not in table: candidates = [] for c in table: if c.startswith(subcommand): candidates.append(c) if len(candidates) == 1: subcommand = candidates[0] elif len(candidates) > 1: ui.status('Ambiguous command. Could have been:\n%s\n' % ' '.join(candidates)) return doc = table[subcommand].__doc__ if doc is None: doc = "No documentation available for %s." % subcommand ui.status(doc.strip(), '\n') return ui.status(_helpgen()) def update(ui, args, repo, clean=False, **opts): """update to a specified Subversion revision number """ assert len(args) == 1 rev = int(args[0]) meta = svnmeta.SVNMeta(repo) answers = [] for k, v in meta.revmap.iteritems(): if k[0] == rev: answers.append((v, k[1])) if len(answers) == 1: if clean: return hg.clean(repo, answers[0][0]) return hg.update(repo, answers[0][0]) elif len(answers) == 0: ui.status('revision %s did not produce an hg revision\n' % rev) return 1 else: ui.status('ambiguous revision!\n') revs = ['%s on %s' % (node.hex(a[0]), a[1]) for a in answers] + [''] ui.status('\n'.join(revs)) return 1 table = { 'update': update, 'help': help, 'rebuildmeta': rebuildmeta, 'updateexternals': svnexternals.updateexternals, 'verify': verify, } table.update(utility_commands.table) def _helpgen(): ret = ['hg svn ...', '', 'subcommands for Subversion integration', '', 'list of subcommands:', ''] for name, func in sorted(table.items()): short_description = (func.__doc__ or '').splitlines()[0] ret.append(" %-10s %s" % (name, short_description)) return '\n'.join(ret) + '\n'