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' |