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'