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