Mercurial > hg
annotate hgext/convert/bzr.py @ 9021:2ccb527c7b1a
gendoc: fix localization of help topic
When a topic provides a callable method for its text, most likely
this text will be generated from different parts, so it does not
make sense to apply gettext on the whole result, rather the method
should provide translation by itself.
This is the case with the extensions topic, which triggers a double
gettext call, making the ASCII codec fail when it encounters 8 bit
characters, and prevents the documentation from being built.
author | Cédric Duval <cedricduval@free.fr> |
---|---|
date | Sat, 04 Jul 2009 12:12:36 +0200 |
parents | 9154c79c67cc |
children | 25e572394f5c |
rev | line source |
---|---|
8250
1b60efdb8bc5
convert: add copyright and license headers to back-ends
Martin Geisler <mg@lazybytes.net>
parents:
8166
diff
changeset
|
1 # bzr.py - bzr support for the convert extension |
1b60efdb8bc5
convert: add copyright and license headers to back-ends
Martin Geisler <mg@lazybytes.net>
parents:
8166
diff
changeset
|
2 # |
1b60efdb8bc5
convert: add copyright and license headers to back-ends
Martin Geisler <mg@lazybytes.net>
parents:
8166
diff
changeset
|
3 # Copyright 2008, 2009 Marek Kubica <marek@xivilization.net> and others |
1b60efdb8bc5
convert: add copyright and license headers to back-ends
Martin Geisler <mg@lazybytes.net>
parents:
8166
diff
changeset
|
4 # |
1b60efdb8bc5
convert: add copyright and license headers to back-ends
Martin Geisler <mg@lazybytes.net>
parents:
8166
diff
changeset
|
5 # This software may be used and distributed according to the terms of the |
1b60efdb8bc5
convert: add copyright and license headers to back-ends
Martin Geisler <mg@lazybytes.net>
parents:
8166
diff
changeset
|
6 # GNU General Public License version 2, incorporated herein by reference. |
1b60efdb8bc5
convert: add copyright and license headers to back-ends
Martin Geisler <mg@lazybytes.net>
parents:
8166
diff
changeset
|
7 |
7053 | 8 # This module is for handling 'bzr', that was formerly known as Bazaar-NG; |
9 # it cannot access 'bar' repositories, but they were never used very much | |
10 | |
11 import os | |
12 from mercurial import demandimport | |
13 # these do not work with demandimport, blacklist | |
14 demandimport.ignore.extend([ | |
15 'bzrlib.transactions', | |
16 'bzrlib.urlutils', | |
17 ]) | |
18 | |
19 from mercurial.i18n import _ | |
20 from mercurial import util | |
21 from common import NoRepo, commit, converter_source | |
22 | |
23 try: | |
24 # bazaar imports | |
25 from bzrlib import branch, revision, errors | |
26 from bzrlib.revisionspec import RevisionSpec | |
27 except ImportError: | |
28 pass | |
29 | |
8045
e09a2f2ef85d
convert/bzr: fix file rename replaced by a dir case (issue1583)
Patrick Mezard <pmezard@gmail.com>
parents:
8035
diff
changeset
|
30 supportedkinds = ('file', 'symlink') |
e09a2f2ef85d
convert/bzr: fix file rename replaced by a dir case (issue1583)
Patrick Mezard <pmezard@gmail.com>
parents:
8035
diff
changeset
|
31 |
7053 | 32 class bzr_source(converter_source): |
33 """Reads Bazaar repositories by using the Bazaar Python libraries""" | |
34 | |
35 def __init__(self, ui, path, rev=None): | |
36 super(bzr_source, self).__init__(ui, path, rev=rev) | |
37 | |
7973
db3a68fd9387
convert: attempt to check repo type before checking for tool
Matt Mackall <mpm@selenic.com>
parents:
7060
diff
changeset
|
38 if not os.path.exists(os.path.join(path, '.bzr')): |
db3a68fd9387
convert: attempt to check repo type before checking for tool
Matt Mackall <mpm@selenic.com>
parents:
7060
diff
changeset
|
39 raise NoRepo('%s does not look like a Bazaar repo' % path) |
db3a68fd9387
convert: attempt to check repo type before checking for tool
Matt Mackall <mpm@selenic.com>
parents:
7060
diff
changeset
|
40 |
7053 | 41 try: |
42 # access bzrlib stuff | |
43 branch | |
44 except NameError: | |
45 raise NoRepo('Bazaar modules could not be loaded') | |
46 | |
47 path = os.path.abspath(path) | |
8470
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
48 self._checkrepotype(path) |
7053 | 49 self.branch = branch.Branch.open(path) |
50 self.sourcerepo = self.branch.repository | |
51 self._parentids = {} | |
52 | |
8470
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
53 def _checkrepotype(self, path): |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
54 # Lightweight checkouts detection is informational but probably |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
55 # fragile at API level. It should not terminate the conversion. |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
56 try: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
57 from bzrlib import bzrdir |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
58 dir = bzrdir.BzrDir.open_containing(path)[0] |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
59 try: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
60 tree = dir.open_workingtree(recommend_upgrade=False) |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
61 branch = tree.branch |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
62 except (errors.NoWorkingTree, errors.NotLocalUrl), e: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
63 tree = None |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
64 branch = dir.open_branch() |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
65 if (tree is not None and tree.bzrdir.root_transport.base != |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
66 branch.bzrdir.root_transport.base): |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
67 self.ui.warn(_('warning: lightweight checkouts may cause ' |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
68 'conversion failures, try with a regular ' |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
69 'branch instead.\n')) |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
70 except: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
71 self.ui.note(_('bzr source type could not be determined\n')) |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
72 |
7053 | 73 def before(self): |
74 """Before the conversion begins, acquire a read lock | |
75 for all the operations that might need it. Fortunately | |
76 read locks don't block other reads or writes to the | |
77 repository, so this shouldn't have any impact on the usage of | |
78 the source repository. | |
79 | |
80 The alternative would be locking on every operation that | |
81 needs locks (there are currently two: getting the file and | |
82 getting the parent map) and releasing immediately after, | |
83 but this approach can take even 40% longer.""" | |
84 self.sourcerepo.lock_read() | |
85 | |
86 def after(self): | |
87 self.sourcerepo.unlock() | |
88 | |
89 def getheads(self): | |
90 if not self.rev: | |
91 return [self.branch.last_revision()] | |
92 try: | |
93 r = RevisionSpec.from_string(self.rev) | |
94 info = r.in_history(self.branch) | |
95 except errors.BzrError: | |
96 raise util.Abort(_('%s is not a valid revision in current branch') | |
97 % self.rev) | |
98 return [info.rev_id] | |
99 | |
100 def getfile(self, name, rev): | |
101 revtree = self.sourcerepo.revision_tree(rev) | |
8783
6556d4145122
bzr convert: restore paths to source encoding. Closes issue1692.
Brendan Cully <brendan@kublai.com>
parents:
8423
diff
changeset
|
102 fileid = revtree.path2id(name.decode(self.encoding or 'utf-8')) |
8423
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
103 kind = None |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
104 if fileid is not None: |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
105 kind = revtree.kind(fileid) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
106 if kind not in supportedkinds: |
7053 | 107 # the file is not available anymore - was deleted |
108 raise IOError(_('%s is not available in %s anymore') % | |
109 (name, rev)) | |
8423
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
110 if kind == 'symlink': |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
111 target = revtree.get_symlink_target(fileid) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
112 if target is None: |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
113 raise util.Abort(_('%s.%s symlink has no target') |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
114 % (name, rev)) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
115 return target |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
116 else: |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
117 sio = revtree.get_file(fileid) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
118 return sio.read() |
7053 | 119 |
120 def getmode(self, name, rev): | |
121 return self._modecache[(name, rev)] | |
122 | |
123 def getchanges(self, version): | |
124 # set up caches: modecache and revtree | |
125 self._modecache = {} | |
126 self._revtree = self.sourcerepo.revision_tree(version) | |
127 # get the parentids from the cache | |
128 parentids = self._parentids.pop(version) | |
129 # only diff against first parent id | |
130 prevtree = self.sourcerepo.revision_tree(parentids[0]) | |
131 return self._gettreechanges(self._revtree, prevtree) | |
132 | |
133 def getcommit(self, version): | |
134 rev = self.sourcerepo.get_revision(version) | |
135 # populate parent id cache | |
136 if not rev.parent_ids: | |
137 parents = [] | |
138 self._parentids[version] = (revision.NULL_REVISION,) | |
139 else: | |
140 parents = self._filterghosts(rev.parent_ids) | |
141 self._parentids[version] = parents | |
142 | |
143 return commit(parents=parents, | |
8305
7a0fcdd3828f
convert/bzr: handle Bazaar timestamps correctly (issue1652).
Greg Ward <greg-hg@gerg.ca>
parents:
8250
diff
changeset
|
144 date='%d %d' % (rev.timestamp, -rev.timezone), |
7053 | 145 author=self.recode(rev.committer), |
146 # bzr returns bytestrings or unicode, depending on the content | |
147 desc=self.recode(rev.message), | |
148 rev=version) | |
149 | |
150 def gettags(self): | |
151 if not self.branch.supports_tags(): | |
152 return {} | |
153 tagdict = self.branch.tags.get_tag_dict() | |
154 bytetags = {} | |
155 for name, rev in tagdict.iteritems(): | |
156 bytetags[self.recode(name)] = rev | |
157 return bytetags | |
158 | |
159 def getchangedfiles(self, rev, i): | |
160 self._modecache = {} | |
161 curtree = self.sourcerepo.revision_tree(rev) | |
162 if i is not None: | |
8165
78658990c725
convert/bzr: make it work with filemaps (issue1631)
Patrick Mezard <pmezard@gmail.com>
parents:
8148
diff
changeset
|
163 parentid = self._parentids[rev][i] |
7053 | 164 else: |
165 # no parent id, get the empty revision | |
166 parentid = revision.NULL_REVISION | |
167 | |
168 prevtree = self.sourcerepo.revision_tree(parentid) | |
169 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]] | |
170 return changes | |
171 | |
172 def _gettreechanges(self, current, origin): | |
173 revid = current._revision_id; | |
174 changes = [] | |
175 renames = {} | |
176 for (fileid, paths, changed_content, versioned, parent, name, | |
177 kind, executable) in current.iter_changes(origin): | |
178 | |
179 if paths[0] == u'' or paths[1] == u'': | |
180 # ignore changes to tree root | |
181 continue | |
182 | |
183 # bazaar tracks directories, mercurial does not, so | |
184 # we have to rename the directory contents | |
185 if kind[1] == 'directory': | |
8126
13b36eb14324
convert/bzr: handle files replaced by directories (issue1623)
Patrick Mezard <pmezard@gmail.com>
parents:
8045
diff
changeset
|
186 if kind[0] not in (None, 'directory'): |
13b36eb14324
convert/bzr: handle files replaced by directories (issue1623)
Patrick Mezard <pmezard@gmail.com>
parents:
8045
diff
changeset
|
187 # Replacing 'something' with a directory, record it |
13b36eb14324
convert/bzr: handle files replaced by directories (issue1623)
Patrick Mezard <pmezard@gmail.com>
parents:
8045
diff
changeset
|
188 # so it can be removed. |
13b36eb14324
convert/bzr: handle files replaced by directories (issue1623)
Patrick Mezard <pmezard@gmail.com>
parents:
8045
diff
changeset
|
189 changes.append((self.recode(paths[0]), revid)) |
13b36eb14324
convert/bzr: handle files replaced by directories (issue1623)
Patrick Mezard <pmezard@gmail.com>
parents:
8045
diff
changeset
|
190 |
7053 | 191 if None not in paths and paths[0] != paths[1]: |
192 # neither an add nor an delete - a move | |
193 # rename all directory contents manually | |
194 subdir = origin.inventory.path2id(paths[0]) | |
195 # get all child-entries of the directory | |
196 for name, entry in origin.inventory.iter_entries(subdir): | |
197 # hg does not track directory renames | |
198 if entry.kind == 'directory': | |
199 continue | |
200 frompath = self.recode(paths[0] + '/' + name) | |
201 topath = self.recode(paths[1] + '/' + name) | |
202 # register the files as changed | |
203 changes.append((frompath, revid)) | |
204 changes.append((topath, revid)) | |
205 # add to mode cache | |
206 mode = ((entry.executable and 'x') or (entry.kind == 'symlink' and 's') | |
207 or '') | |
208 self._modecache[(topath, revid)] = mode | |
209 # register the change as move | |
210 renames[topath] = frompath | |
211 | |
212 # no futher changes, go to the next change | |
213 continue | |
214 | |
215 # we got unicode paths, need to convert them | |
216 path, topath = [self.recode(part) for part in paths] | |
217 | |
218 if topath is None: | |
219 # file deleted | |
220 changes.append((path, revid)) | |
221 continue | |
222 | |
223 # renamed | |
224 if path and path != topath: | |
225 renames[topath] = path | |
8035
cb77c0fbec39
convert: remove renamed source files (issue1505)
Xavier ALT <dex@phoenix-ind.net>
parents:
7060
diff
changeset
|
226 changes.append((path, revid)) |
7053 | 227 |
228 # populate the mode cache | |
229 kind, executable = [e[1] for e in (kind, executable)] | |
8148
adce97d28389
convert/bzr: fix symlink handling (issue1626)
Patrick Mezard <pmezard@gmail.com>
parents:
8126
diff
changeset
|
230 mode = ((executable and 'x') or (kind == 'symlink' and 'l') |
7053 | 231 or '') |
232 self._modecache[(topath, revid)] = mode | |
233 changes.append((topath, revid)) | |
234 | |
235 return changes, renames | |
236 | |
237 def _filterghosts(self, ids): | |
238 """Filters out ghost revisions which hg does not support, see | |
239 <http://bazaar-vcs.org/GhostRevision> | |
240 """ | |
241 parentmap = self.sourcerepo.get_parent_map(ids) | |
7060
972cce34f345
convert: fixed python2.3 incompatibility in bzr source (generator expression)
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
7053
diff
changeset
|
242 parents = tuple([parent for parent in ids if parent in parentmap]) |
7053 | 243 return parents |
244 | |
245 def recode(self, s, encoding=None): | |
246 """This version of recode tries to encode unicode to bytecode, | |
247 and preferably using the UTF-8 codec. | |
248 Other types than Unicode are silently returned, this is by | |
249 intention, e.g. the None-type is not going to be encoded but instead | |
250 just passed through | |
251 """ | |
252 if not encoding: | |
253 encoding = self.encoding or 'utf-8' | |
254 | |
255 if isinstance(s, unicode): | |
256 return s.encode(encoding) | |
257 else: | |
258 # leave it alone | |
259 return s |