##// END OF EJS Templates
convert: fixed python2.3 incompatibility in bzr source (generator expression)
Dirkjan Ochtman -
r7060:972cce34 default
parent child Browse files
Show More
@@ -1,216 +1,216 b''
1 1 # bzr support for the convert extension
2 2 # This module is for handling 'bzr', that was formerly known as Bazaar-NG;
3 3 # it cannot access 'bar' repositories, but they were never used very much
4 4
5 5 import os
6 6 from mercurial import demandimport
7 7 # these do not work with demandimport, blacklist
8 8 demandimport.ignore.extend([
9 9 'bzrlib.transactions',
10 10 'bzrlib.urlutils',
11 11 ])
12 12
13 13 from mercurial.i18n import _
14 14 from mercurial import util
15 15 from common import NoRepo, commit, converter_source
16 16
17 17 try:
18 18 # bazaar imports
19 19 from bzrlib import branch, revision, errors
20 20 from bzrlib.revisionspec import RevisionSpec
21 21 except ImportError:
22 22 pass
23 23
24 24 class bzr_source(converter_source):
25 25 """Reads Bazaar repositories by using the Bazaar Python libraries"""
26 26
27 27 def __init__(self, ui, path, rev=None):
28 28 super(bzr_source, self).__init__(ui, path, rev=rev)
29 29
30 30 try:
31 31 # access bzrlib stuff
32 32 branch
33 33 except NameError:
34 34 raise NoRepo('Bazaar modules could not be loaded')
35 35
36 36 if not os.path.exists(os.path.join(path, '.bzr')):
37 37 raise NoRepo('%s does not look like a Bazaar repo' % path)
38 38
39 39 path = os.path.abspath(path)
40 40 self.branch = branch.Branch.open(path)
41 41 self.sourcerepo = self.branch.repository
42 42 self._parentids = {}
43 43
44 44 def before(self):
45 45 """Before the conversion begins, acquire a read lock
46 46 for all the operations that might need it. Fortunately
47 47 read locks don't block other reads or writes to the
48 48 repository, so this shouldn't have any impact on the usage of
49 49 the source repository.
50 50
51 51 The alternative would be locking on every operation that
52 52 needs locks (there are currently two: getting the file and
53 53 getting the parent map) and releasing immediately after,
54 54 but this approach can take even 40% longer."""
55 55 self.sourcerepo.lock_read()
56 56
57 57 def after(self):
58 58 self.sourcerepo.unlock()
59 59
60 60 def getheads(self):
61 61 if not self.rev:
62 62 return [self.branch.last_revision()]
63 63 try:
64 64 r = RevisionSpec.from_string(self.rev)
65 65 info = r.in_history(self.branch)
66 66 except errors.BzrError:
67 67 raise util.Abort(_('%s is not a valid revision in current branch')
68 68 % self.rev)
69 69 return [info.rev_id]
70 70
71 71 def getfile(self, name, rev):
72 72 revtree = self.sourcerepo.revision_tree(rev)
73 73 fileid = revtree.path2id(name)
74 74 if fileid is None:
75 75 # the file is not available anymore - was deleted
76 76 raise IOError(_('%s is not available in %s anymore') %
77 77 (name, rev))
78 78 sio = revtree.get_file(fileid)
79 79 return sio.read()
80 80
81 81 def getmode(self, name, rev):
82 82 return self._modecache[(name, rev)]
83 83
84 84 def getchanges(self, version):
85 85 # set up caches: modecache and revtree
86 86 self._modecache = {}
87 87 self._revtree = self.sourcerepo.revision_tree(version)
88 88 # get the parentids from the cache
89 89 parentids = self._parentids.pop(version)
90 90 # only diff against first parent id
91 91 prevtree = self.sourcerepo.revision_tree(parentids[0])
92 92 return self._gettreechanges(self._revtree, prevtree)
93 93
94 94 def getcommit(self, version):
95 95 rev = self.sourcerepo.get_revision(version)
96 96 # populate parent id cache
97 97 if not rev.parent_ids:
98 98 parents = []
99 99 self._parentids[version] = (revision.NULL_REVISION,)
100 100 else:
101 101 parents = self._filterghosts(rev.parent_ids)
102 102 self._parentids[version] = parents
103 103
104 104 return commit(parents=parents,
105 105 # bzr uses 1 second timezone precision
106 106 date='%d %d' % (rev.timestamp, rev.timezone / 3600),
107 107 author=self.recode(rev.committer),
108 108 # bzr returns bytestrings or unicode, depending on the content
109 109 desc=self.recode(rev.message),
110 110 rev=version)
111 111
112 112 def gettags(self):
113 113 if not self.branch.supports_tags():
114 114 return {}
115 115 tagdict = self.branch.tags.get_tag_dict()
116 116 bytetags = {}
117 117 for name, rev in tagdict.iteritems():
118 118 bytetags[self.recode(name)] = rev
119 119 return bytetags
120 120
121 121 def getchangedfiles(self, rev, i):
122 122 self._modecache = {}
123 123 curtree = self.sourcerepo.revision_tree(rev)
124 124 parentids = self._parentids.pop(rev)
125 125 if i is not None:
126 126 parentid = parentids[i]
127 127 else:
128 128 # no parent id, get the empty revision
129 129 parentid = revision.NULL_REVISION
130 130
131 131 prevtree = self.sourcerepo.revision_tree(parentid)
132 132 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]]
133 133 return changes
134 134
135 135 def _gettreechanges(self, current, origin):
136 136 revid = current._revision_id;
137 137 changes = []
138 138 renames = {}
139 139 for (fileid, paths, changed_content, versioned, parent, name,
140 140 kind, executable) in current.iter_changes(origin):
141 141
142 142 if paths[0] == u'' or paths[1] == u'':
143 143 # ignore changes to tree root
144 144 continue
145 145
146 146 # bazaar tracks directories, mercurial does not, so
147 147 # we have to rename the directory contents
148 148 if kind[1] == 'directory':
149 149 if None not in paths and paths[0] != paths[1]:
150 150 # neither an add nor an delete - a move
151 151 # rename all directory contents manually
152 152 subdir = origin.inventory.path2id(paths[0])
153 153 # get all child-entries of the directory
154 154 for name, entry in origin.inventory.iter_entries(subdir):
155 155 # hg does not track directory renames
156 156 if entry.kind == 'directory':
157 157 continue
158 158 frompath = self.recode(paths[0] + '/' + name)
159 159 topath = self.recode(paths[1] + '/' + name)
160 160 # register the files as changed
161 161 changes.append((frompath, revid))
162 162 changes.append((topath, revid))
163 163 # add to mode cache
164 164 mode = ((entry.executable and 'x') or (entry.kind == 'symlink' and 's')
165 165 or '')
166 166 self._modecache[(topath, revid)] = mode
167 167 # register the change as move
168 168 renames[topath] = frompath
169 169
170 170 # no futher changes, go to the next change
171 171 continue
172 172
173 173 # we got unicode paths, need to convert them
174 174 path, topath = [self.recode(part) for part in paths]
175 175
176 176 if topath is None:
177 177 # file deleted
178 178 changes.append((path, revid))
179 179 continue
180 180
181 181 # renamed
182 182 if path and path != topath:
183 183 renames[topath] = path
184 184
185 185 # populate the mode cache
186 186 kind, executable = [e[1] for e in (kind, executable)]
187 187 mode = ((executable and 'x') or (kind == 'symlink' and 's')
188 188 or '')
189 189 self._modecache[(topath, revid)] = mode
190 190 changes.append((topath, revid))
191 191
192 192 return changes, renames
193 193
194 194 def _filterghosts(self, ids):
195 195 """Filters out ghost revisions which hg does not support, see
196 196 <http://bazaar-vcs.org/GhostRevision>
197 197 """
198 198 parentmap = self.sourcerepo.get_parent_map(ids)
199 parents = tuple(parent for parent in ids if parent in parentmap)
199 parents = tuple([parent for parent in ids if parent in parentmap])
200 200 return parents
201 201
202 202 def recode(self, s, encoding=None):
203 203 """This version of recode tries to encode unicode to bytecode,
204 204 and preferably using the UTF-8 codec.
205 205 Other types than Unicode are silently returned, this is by
206 206 intention, e.g. the None-type is not going to be encoded but instead
207 207 just passed through
208 208 """
209 209 if not encoding:
210 210 encoding = self.encoding or 'utf-8'
211 211
212 212 if isinstance(s, unicode):
213 213 return s.encode(encoding)
214 214 else:
215 215 # leave it alone
216 216 return s
General Comments 0
You need to be logged in to leave comments. Login now