Mercurial > hgsubversion
comparison svncommands.py @ 304:ce676eff002b
First merge, totally untested.
| author | Dan Villiom Podlaski Christiansen <danchr@gmail.com> |
|---|---|
| date | Fri, 01 May 2009 10:28:59 +0200 |
| parents | ba8e91a7c077 |
| children | 1d48d9a34c19 |
comparison
equal
deleted
inserted
replaced
| 303:f423a8780832 | 304:ce676eff002b |
|---|---|
| 1 import os | |
| 2 import cPickle as pickle | |
| 3 | |
| 4 from mercurial import hg | |
| 5 from mercurial import node | |
| 6 from mercurial import util as hgutil | |
| 7 | |
| 8 | |
| 9 import hg_delta_editor | |
| 10 import svnwrap | |
| 11 import util | |
| 12 import utility_commands | |
| 13 import svnexternals | |
| 14 | |
| 15 | |
| 16 def incoming(ui, svn_url, hg_repo_path, skipto_rev=0, stupid=None, | |
| 17 tag_locations='tags', authors=None, filemap=None, **opts): | |
| 18 """show incoming revisions from Subversion | |
| 19 """ | |
| 20 svn_url = util.normalize_url(svn_url) | |
| 21 | |
| 22 initializing_repo = False | |
| 23 user, passwd = util.getuserpass(opts) | |
| 24 svn = svnwrap.SubversionRepo(svn_url, user, passwd) | |
| 25 author_host = "@%s" % svn.uuid | |
| 26 tag_locations = tag_locations.split(',') | |
| 27 hg_editor = hg_delta_editor.HgChangeReceiver(hg_repo_path, | |
| 28 ui_=ui, | |
| 29 subdir=svn.subdir, | |
| 30 author_host=author_host, | |
| 31 tag_locations=tag_locations, | |
| 32 authors=authors, | |
| 33 filemap=filemap) | |
| 34 if os.path.exists(hg_editor.uuid_file): | |
| 35 uuid = open(hg_editor.uuid_file).read() | |
| 36 assert uuid == svn.uuid | |
| 37 start = hg_editor.last_known_revision() | |
| 38 else: | |
| 39 open(hg_editor.uuid_file, 'w').write(svn.uuid) | |
| 40 open(hg_editor.svn_url_file, 'w').write(svn_url) | |
| 41 initializing_repo = True | |
| 42 start = skipto_rev | |
| 43 | |
| 44 if initializing_repo and start > 0: | |
| 45 raise hgutil.Abort('Revision skipping at repository initialization ' | |
| 46 'remains unimplemented.') | |
| 47 | |
| 48 rev_stuff = (('revision', 'revnum'), | |
| 49 ('user', 'author'), | |
| 50 ('date', 'date'), | |
| 51 ('message', 'message') | |
| 52 ) | |
| 53 | |
| 54 ui.status('incoming changes from %s\n' % svn_url) | |
| 55 | |
| 56 for r in svn.revisions(start=start): | |
| 57 ui.status('\n') | |
| 58 for label, attr in rev_stuff: | |
| 59 l1 = label+':' | |
| 60 ui.status('%s%s\n' % (l1.ljust(13), | |
| 61 str(r.__getattribute__(attr)).strip(), )) | |
| 62 | |
| 63 | |
| 64 def rebuildmeta(ui, repo, hg_repo_path, args, **opts): | |
| 65 """rebuild hgsubversion metadata using values stored in revisions | |
| 66 """ | |
| 67 if len(args) != 1: | |
| 68 raise hgutil.Abort('You must pass the svn URI used to create this repo.') | |
| 69 uuid = None | |
| 70 url = args[0].rstrip('/') | |
| 71 user, passwd = util.getuserpass(opts) | |
| 72 svn = svnwrap.SubversionRepo(url, user, passwd) | |
| 73 subdir = svn.subdir | |
| 74 svnmetadir = os.path.join(repo.path, 'svn') | |
| 75 if not os.path.exists(svnmetadir): | |
| 76 os.makedirs(svnmetadir) | |
| 77 | |
| 78 revmap = open(os.path.join(svnmetadir, 'rev_map'), 'w') | |
| 79 revmap.write('1\n') | |
| 80 last_rev = -1 | |
| 81 branchinfo = {} | |
| 82 noderevnums = {} | |
| 83 for rev in repo: | |
| 84 ctx = repo[rev] | |
| 85 convinfo = ctx.extra().get('convert_revision', None) | |
| 86 if convinfo: | |
| 87 assert convinfo.startswith('svn:') | |
| 88 revpath, revision = convinfo[40:].split('@') | |
| 89 if subdir and subdir[0] != '/': | |
| 90 subdir = '/' + subdir | |
| 91 if subdir and subdir[-1] == '/': | |
| 92 subdir = subdir[:-1] | |
| 93 assert revpath.startswith(subdir), ('That does not look like the ' | |
| 94 'right location in the repo.') | |
| 95 if uuid is None: | |
| 96 uuid = convinfo[4:40] | |
| 97 assert uuid == svn.uuid, 'UUIDs did not match!' | |
| 98 urlfile = open(os.path.join(svnmetadir, 'url'), 'w') | |
| 99 urlfile.write(url) | |
| 100 urlfile.close() | |
| 101 uuidfile = open(os.path.join(svnmetadir, 'uuid'), 'w') | |
| 102 uuidfile.write(uuid) | |
| 103 uuidfile.close() | |
| 104 commitpath = revpath[len(subdir)+1:] | |
| 105 if commitpath.startswith('branches'): | |
| 106 commitpath = commitpath[len('branches/'):] | |
| 107 elif commitpath == 'trunk': | |
| 108 commitpath = '' | |
| 109 else: | |
| 110 assert False, 'Unhandled case in rebuildmeta' | |
| 111 revmap.write('%s %s %s\n' % (revision, | |
| 112 node.hex(ctx.node()), | |
| 113 commitpath)) | |
| 114 revision = int(revision) | |
| 115 noderevnums[ctx.node()] = revision | |
| 116 if revision > last_rev: | |
| 117 last_rev = revision | |
| 118 branch = ctx.branch() | |
| 119 if branch == 'default': | |
| 120 branch = None | |
| 121 if branch not in branchinfo: | |
| 122 parent = ctx.parents()[0] | |
| 123 if (parent.node() in noderevnums | |
| 124 and parent.branch() != ctx.branch()): | |
| 125 parentbranch = parent.branch() | |
| 126 if parentbranch == 'default': | |
| 127 parentbranch = None | |
| 128 else: | |
| 129 parentbranch = None | |
| 130 branchinfo[branch] = (parentbranch, | |
| 131 noderevnums.get(parent.node(), 0), | |
| 132 revision) | |
| 133 for c in ctx.children(): | |
| 134 if c.branch() == 'closed-branches': | |
| 135 if branch in branchinfo: | |
| 136 del branchinfo[branch] | |
| 137 branchinfofile = open(os.path.join(svnmetadir, 'branch_info'), 'w') | |
| 138 pickle.dump(branchinfo, branchinfofile) | |
| 139 branchinfofile.close() | |
| 140 | |
| 141 # now handle tags | |
| 142 tagsinfo = {} | |
| 143 realtags = svn.tags | |
| 144 tagsleft = realtags.items() | |
| 145 while tagsleft: | |
| 146 tag, tagparent = tagsleft.pop(0) | |
| 147 source, rev = tagparent | |
| 148 if source.startswith('tags/'): | |
| 149 src = source[len('tags/'):] | |
| 150 if src in tagsinfo: | |
| 151 tagsinfo[tag] = tagsinfo[src] | |
| 152 elif src in realtags: | |
| 153 if (realtags[src][1] <= last_rev | |
| 154 or realtags[src][0].startswith('tags/')): | |
| 155 tagsleft.append(src) | |
| 156 else: | |
| 157 older_tags = svn.tags_at_rev(rev) | |
| 158 newsrc, newrev = older_tags[src] | |
| 159 tagsleft.append((tag, (newsrc, newrev))) | |
| 160 continue | |
| 161 else: | |
| 162 # determine the branch | |
| 163 assert not source.startswith('tags/'), "Tags can't be tags of other tags." | |
| 164 if source.startswith('branches/'): | |
| 165 source = source[len('branches/'):] | |
| 166 elif source == 'trunk': | |
| 167 source = None | |
| 168 else: | |
| 169 source = '../' + source | |
| 170 if rev <= last_rev and (source or 'default') in repo.branchtags(): | |
| 171 tagsinfo[tag] = source, rev | |
| 172 | |
| 173 tagsinfofile = open(os.path.join(svnmetadir, 'tag_info'), 'w') | |
| 174 pickle.dump(tagsinfo, tagsinfofile) | |
| 175 tagsinfofile.close() | |
| 176 | |
| 177 | |
| 178 def help(ui, args=None, **opts): | |
| 179 """show help for a given subcommands or a help overview | |
| 180 """ | |
| 181 if args: | |
| 182 subcommand = args[0] | |
| 183 if subcommand not in table: | |
| 184 candidates = [] | |
| 185 for c in table: | |
| 186 if c.startswith(subcommand): | |
| 187 candidates.append(c) | |
| 188 if len(candidates) == 1: | |
| 189 subcommand = candidates[0] | |
| 190 elif len(candidates) > 1: | |
| 191 ui.status('Ambiguous command. Could have been:\n%s\n' % | |
| 192 ' '.join(candidates)) | |
| 193 return | |
| 194 doc = table[subcommand].__doc__ | |
| 195 if doc is None: | |
| 196 doc = "No documentation available for %s." % subcommand | |
| 197 ui.status(doc.strip(), '\n') | |
| 198 return | |
| 199 ui.status(_helpgen()) | |
| 200 | |
| 201 | |
| 202 def update(ui, args, repo, clean=False, **opts): | |
| 203 """update to a specified Subversion revision number | |
| 204 """ | |
| 205 assert len(args) == 1 | |
| 206 rev = int(args[0]) | |
| 207 path = os.path.join(repo.path, 'svn', 'rev_map') | |
| 208 answers = [] | |
| 209 for k,v in util.parse_revmap(path).iteritems(): | |
| 210 if k[0] == rev: | |
| 211 answers.append((v, k[1])) | |
| 212 if len(answers) == 1: | |
| 213 if clean: | |
| 214 return hg.clean(repo, answers[0][0]) | |
| 215 return hg.update(repo, answers[0][0]) | |
| 216 elif len(answers) == 0: | |
| 217 ui.status('Revision %s did not produce an hg revision.\n' % rev) | |
| 218 return 1 | |
| 219 else: | |
| 220 ui.status('Ambiguous revision!\n') | |
| 221 ui.status('\n'.join(['%s on %s' % (node.hex(a[0]), a[1]) for a in | |
| 222 answers]+[''])) | |
| 223 return 1 | |
| 224 | |
| 225 | |
| 226 nourl = ['rebuildmeta', 'help'] + utility_commands.nourl | |
| 227 table = { | |
| 228 'update': update, | |
| 229 'help': help, | |
| 230 'rebuildmeta': rebuildmeta, | |
| 231 'incoming': incoming, | |
| 232 'updateexternals': svnexternals.updateexternals, | |
| 233 } | |
| 234 | |
| 235 table.update(utility_commands.table) | |
| 236 | |
| 237 | |
| 238 def _helpgen(): | |
| 239 ret = ['hg svn ...', '', | |
| 240 'subcommands for Subversion integration', '', | |
| 241 'list of subcommands:', ''] | |
| 242 for name, func in sorted(table.items()): | |
| 243 short_description = (func.__doc__ or '').splitlines()[0] | |
| 244 ret.append(" %-10s %s" % (name, short_description)) | |
| 245 return '\n'.join(ret) + '\n' |
