##// END OF EJS Templates
convert: fix the RevisionSpec import in the bzr module...
Saurabh Singh -
r34489:6bda8a9d default
parent child Browse files
Show More
@@ -1,297 +1,298 b''
1 1 # bzr.py - bzr support for the convert extension
2 2 #
3 3 # Copyright 2008, 2009 Marek Kubica <marek@xivilization.net> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 # This module is for handling 'bzr', that was formerly known as Bazaar-NG;
9 9 # it cannot access 'bar' repositories, but they were never used very much
10 10 from __future__ import absolute_import
11 11
12 12 import os
13 13
14 14 from mercurial.i18n import _
15 15 from mercurial import (
16 16 demandimport,
17 17 error
18 18 )
19 19 from . import common
20 20
21 21 # these do not work with demandimport, blacklist
22 22 demandimport.ignore.extend([
23 23 'bzrlib.transactions',
24 24 'bzrlib.urlutils',
25 25 'ElementPath',
26 26 ])
27 27
28 28 try:
29 29 # bazaar imports
30 30 import bzrlib.bzrdir
31 31 import bzrlib.errors
32 32 import bzrlib.revision
33 import bzrlib.revisionspec.RevisionSpec
33 import bzrlib.revisionspec
34 34 bzrdir = bzrlib.bzrdir
35 35 errors = bzrlib.errors
36 36 revision = bzrlib.revision
37 37 revisionspec = bzrlib.revisionspec
38 revisionspec.RevisionSpec
38 39 except ImportError:
39 40 pass
40 41
41 42 supportedkinds = ('file', 'symlink')
42 43
43 44 class bzr_source(common.converter_source):
44 45 """Reads Bazaar repositories by using the Bazaar Python libraries"""
45 46
46 47 def __init__(self, ui, path, revs=None):
47 48 super(bzr_source, self).__init__(ui, path, revs=revs)
48 49
49 50 if not os.path.exists(os.path.join(path, '.bzr')):
50 51 raise common.NoRepo(_('%s does not look like a Bazaar repository')
51 52 % path)
52 53
53 54 try:
54 55 # access bzrlib stuff
55 56 bzrdir
56 57 except NameError:
57 58 raise common.NoRepo(_('Bazaar modules could not be loaded'))
58 59
59 60 path = os.path.abspath(path)
60 61 self._checkrepotype(path)
61 62 try:
62 63 self.sourcerepo = bzrdir.BzrDir.open(path).open_repository()
63 64 except errors.NoRepositoryPresent:
64 65 raise common.NoRepo(_('%s does not look like a Bazaar repository')
65 66 % path)
66 67 self._parentids = {}
67 68
68 69 def _checkrepotype(self, path):
69 70 # Lightweight checkouts detection is informational but probably
70 71 # fragile at API level. It should not terminate the conversion.
71 72 try:
72 73 dir = bzrdir.BzrDir.open_containing(path)[0]
73 74 try:
74 75 tree = dir.open_workingtree(recommend_upgrade=False)
75 76 branch = tree.branch
76 77 except (errors.NoWorkingTree, errors.NotLocalUrl):
77 78 tree = None
78 79 branch = dir.open_branch()
79 80 if (tree is not None and tree.bzrdir.root_transport.base !=
80 81 branch.bzrdir.root_transport.base):
81 82 self.ui.warn(_('warning: lightweight checkouts may cause '
82 83 'conversion failures, try with a regular '
83 84 'branch instead.\n'))
84 85 except Exception:
85 86 self.ui.note(_('bzr source type could not be determined\n'))
86 87
87 88 def before(self):
88 89 """Before the conversion begins, acquire a read lock
89 90 for all the operations that might need it. Fortunately
90 91 read locks don't block other reads or writes to the
91 92 repository, so this shouldn't have any impact on the usage of
92 93 the source repository.
93 94
94 95 The alternative would be locking on every operation that
95 96 needs locks (there are currently two: getting the file and
96 97 getting the parent map) and releasing immediately after,
97 98 but this approach can take even 40% longer."""
98 99 self.sourcerepo.lock_read()
99 100
100 101 def after(self):
101 102 self.sourcerepo.unlock()
102 103
103 104 def _bzrbranches(self):
104 105 return self.sourcerepo.find_branches(using=True)
105 106
106 107 def getheads(self):
107 108 if not self.revs:
108 109 # Set using=True to avoid nested repositories (see issue3254)
109 110 heads = sorted([b.last_revision() for b in self._bzrbranches()])
110 111 else:
111 112 revid = None
112 113 for branch in self._bzrbranches():
113 114 try:
114 115 r = revisionspec.RevisionSpec.from_string(self.revs[0])
115 116 info = r.in_history(branch)
116 117 except errors.BzrError:
117 118 pass
118 119 revid = info.rev_id
119 120 if revid is None:
120 121 raise error.Abort(_('%s is not a valid revision')
121 122 % self.revs[0])
122 123 heads = [revid]
123 124 # Empty repositories return 'null:', which cannot be retrieved
124 125 heads = [h for h in heads if h != 'null:']
125 126 return heads
126 127
127 128 def getfile(self, name, rev):
128 129 revtree = self.sourcerepo.revision_tree(rev)
129 130 fileid = revtree.path2id(name.decode(self.encoding or 'utf-8'))
130 131 kind = None
131 132 if fileid is not None:
132 133 kind = revtree.kind(fileid)
133 134 if kind not in supportedkinds:
134 135 # the file is not available anymore - was deleted
135 136 return None, None
136 137 mode = self._modecache[(name, rev)]
137 138 if kind == 'symlink':
138 139 target = revtree.get_symlink_target(fileid)
139 140 if target is None:
140 141 raise error.Abort(_('%s.%s symlink has no target')
141 142 % (name, rev))
142 143 return target, mode
143 144 else:
144 145 sio = revtree.get_file(fileid)
145 146 return sio.read(), mode
146 147
147 148 def getchanges(self, version, full):
148 149 if full:
149 150 raise error.Abort(_("convert from cvs does not support --full"))
150 151 self._modecache = {}
151 152 self._revtree = self.sourcerepo.revision_tree(version)
152 153 # get the parentids from the cache
153 154 parentids = self._parentids.pop(version)
154 155 # only diff against first parent id
155 156 prevtree = self.sourcerepo.revision_tree(parentids[0])
156 157 files, changes = self._gettreechanges(self._revtree, prevtree)
157 158 return files, changes, set()
158 159
159 160 def getcommit(self, version):
160 161 rev = self.sourcerepo.get_revision(version)
161 162 # populate parent id cache
162 163 if not rev.parent_ids:
163 164 parents = []
164 165 self._parentids[version] = (revision.NULL_REVISION,)
165 166 else:
166 167 parents = self._filterghosts(rev.parent_ids)
167 168 self._parentids[version] = parents
168 169
169 170 branch = self.recode(rev.properties.get('branch-nick', u'default'))
170 171 if branch == 'trunk':
171 172 branch = 'default'
172 173 return common.commit(parents=parents,
173 174 date='%d %d' % (rev.timestamp, -rev.timezone),
174 175 author=self.recode(rev.committer),
175 176 desc=self.recode(rev.message),
176 177 branch=branch,
177 178 rev=version)
178 179
179 180 def gettags(self):
180 181 bytetags = {}
181 182 for branch in self._bzrbranches():
182 183 if not branch.supports_tags():
183 184 return {}
184 185 tagdict = branch.tags.get_tag_dict()
185 186 for name, rev in tagdict.iteritems():
186 187 bytetags[self.recode(name)] = rev
187 188 return bytetags
188 189
189 190 def getchangedfiles(self, rev, i):
190 191 self._modecache = {}
191 192 curtree = self.sourcerepo.revision_tree(rev)
192 193 if i is not None:
193 194 parentid = self._parentids[rev][i]
194 195 else:
195 196 # no parent id, get the empty revision
196 197 parentid = revision.NULL_REVISION
197 198
198 199 prevtree = self.sourcerepo.revision_tree(parentid)
199 200 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]]
200 201 return changes
201 202
202 203 def _gettreechanges(self, current, origin):
203 204 revid = current._revision_id
204 205 changes = []
205 206 renames = {}
206 207 seen = set()
207 208 # Process the entries by reverse lexicographic name order to
208 209 # handle nested renames correctly, most specific first.
209 210 curchanges = sorted(current.iter_changes(origin),
210 211 key=lambda c: c[1][0] or c[1][1],
211 212 reverse=True)
212 213 for (fileid, paths, changed_content, versioned, parent, name,
213 214 kind, executable) in curchanges:
214 215
215 216 if paths[0] == u'' or paths[1] == u'':
216 217 # ignore changes to tree root
217 218 continue
218 219
219 220 # bazaar tracks directories, mercurial does not, so
220 221 # we have to rename the directory contents
221 222 if kind[1] == 'directory':
222 223 if kind[0] not in (None, 'directory'):
223 224 # Replacing 'something' with a directory, record it
224 225 # so it can be removed.
225 226 changes.append((self.recode(paths[0]), revid))
226 227
227 228 if kind[0] == 'directory' and None not in paths:
228 229 renaming = paths[0] != paths[1]
229 230 # neither an add nor an delete - a move
230 231 # rename all directory contents manually
231 232 subdir = origin.root_inventory.path2id(paths[0])
232 233 # get all child-entries of the directory
233 234 for name, entry in origin.root_inventory.iter_entries(
234 235 subdir):
235 236 # hg does not track directory renames
236 237 if entry.kind == 'directory':
237 238 continue
238 239 frompath = self.recode(paths[0] + '/' + name)
239 240 if frompath in seen:
240 241 # Already handled by a more specific change entry
241 242 # This is important when you have:
242 243 # a => b
243 244 # a/c => a/c
244 245 # Here a/c must not be renamed into b/c
245 246 continue
246 247 seen.add(frompath)
247 248 if not renaming:
248 249 continue
249 250 topath = self.recode(paths[1] + '/' + name)
250 251 # register the files as changed
251 252 changes.append((frompath, revid))
252 253 changes.append((topath, revid))
253 254 # add to mode cache
254 255 mode = ((entry.executable and 'x')
255 256 or (entry.kind == 'symlink' and 's')
256 257 or '')
257 258 self._modecache[(topath, revid)] = mode
258 259 # register the change as move
259 260 renames[topath] = frompath
260 261
261 262 # no further changes, go to the next change
262 263 continue
263 264
264 265 # we got unicode paths, need to convert them
265 266 path, topath = paths
266 267 if path is not None:
267 268 path = self.recode(path)
268 269 if topath is not None:
269 270 topath = self.recode(topath)
270 271 seen.add(path or topath)
271 272
272 273 if topath is None:
273 274 # file deleted
274 275 changes.append((path, revid))
275 276 continue
276 277
277 278 # renamed
278 279 if path and path != topath:
279 280 renames[topath] = path
280 281 changes.append((path, revid))
281 282
282 283 # populate the mode cache
283 284 kind, executable = [e[1] for e in (kind, executable)]
284 285 mode = ((executable and 'x') or (kind == 'symlink' and 'l')
285 286 or '')
286 287 self._modecache[(topath, revid)] = mode
287 288 changes.append((topath, revid))
288 289
289 290 return changes, renames
290 291
291 292 def _filterghosts(self, ids):
292 293 """Filters out ghost revisions which hg does not support, see
293 294 <http://bazaar-vcs.org/GhostRevision>
294 295 """
295 296 parentmap = self.sourcerepo.get_parent_map(ids)
296 297 parents = tuple([parent for parent in ids if parent in parentmap])
297 298 return parents
General Comments 0
You need to be logged in to leave comments. Login now