Mercurial > hg
annotate hgext/convert/bzr.py @ 10938:02d6149a480b stable
convert: write "repository" instead of "repo"
We should strive to avoid slang in our messages to the users.
author | Martin Geisler <mg@lazybytes.net> |
---|---|
date | Sun, 18 Apr 2010 15:47:49 +0200 |
parents | 9134725caf1d |
children | 9f6731b03906 |
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 |
10263 | 6 # GNU General Public License version 2 or any later version. |
8250
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', | |
10560
9134725caf1d
Add ElementPath to the list of package ignored by demand import
Pierre-Yves David <pierre-yves.david@logilab.fr>
parents:
10394
diff
changeset
|
17 'ElementPath', |
7053 | 18 ]) |
19 | |
20 from mercurial.i18n import _ | |
21 from mercurial import util | |
22 from common import NoRepo, commit, converter_source | |
23 | |
24 try: | |
25 # bazaar imports | |
26 from bzrlib import branch, revision, errors | |
27 from bzrlib.revisionspec import RevisionSpec | |
28 except ImportError: | |
29 pass | |
30 | |
8045
e09a2f2ef85d
convert/bzr: fix file rename replaced by a dir case (issue1583)
Patrick Mezard <pmezard@gmail.com>
parents:
8035
diff
changeset
|
31 supportedkinds = ('file', 'symlink') |
e09a2f2ef85d
convert/bzr: fix file rename replaced by a dir case (issue1583)
Patrick Mezard <pmezard@gmail.com>
parents:
8035
diff
changeset
|
32 |
7053 | 33 class bzr_source(converter_source): |
34 """Reads Bazaar repositories by using the Bazaar Python libraries""" | |
35 | |
36 def __init__(self, ui, path, rev=None): | |
37 super(bzr_source, self).__init__(ui, path, rev=rev) | |
38 | |
7973
db3a68fd9387
convert: attempt to check repo type before checking for tool
Matt Mackall <mpm@selenic.com>
parents:
7060
diff
changeset
|
39 if not os.path.exists(os.path.join(path, '.bzr')): |
10938
02d6149a480b
convert: write "repository" instead of "repo"
Martin Geisler <mg@lazybytes.net>
parents:
10560
diff
changeset
|
40 raise NoRepo('%s does not look like a Bazaar repository' % path) |
7973
db3a68fd9387
convert: attempt to check repo type before checking for tool
Matt Mackall <mpm@selenic.com>
parents:
7060
diff
changeset
|
41 |
7053 | 42 try: |
43 # access bzrlib stuff | |
44 branch | |
45 except NameError: | |
46 raise NoRepo('Bazaar modules could not be loaded') | |
47 | |
48 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
|
49 self._checkrepotype(path) |
7053 | 50 self.branch = branch.Branch.open(path) |
51 self.sourcerepo = self.branch.repository | |
52 self._parentids = {} | |
53 | |
8470
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
54 def _checkrepotype(self, path): |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
55 # 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
|
56 # 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
|
57 try: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
58 from bzrlib import bzrdir |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
59 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
|
60 try: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
61 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
|
62 branch = tree.branch |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
63 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
|
64 tree = None |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
65 branch = dir.open_branch() |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
66 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
|
67 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
|
68 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
|
69 '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
|
70 'branch instead.\n')) |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
71 except: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
72 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
|
73 |
7053 | 74 def before(self): |
75 """Before the conversion begins, acquire a read lock | |
76 for all the operations that might need it. Fortunately | |
77 read locks don't block other reads or writes to the | |
78 repository, so this shouldn't have any impact on the usage of | |
79 the source repository. | |
80 | |
81 The alternative would be locking on every operation that | |
82 needs locks (there are currently two: getting the file and | |
83 getting the parent map) and releasing immediately after, | |
84 but this approach can take even 40% longer.""" | |
85 self.sourcerepo.lock_read() | |
86 | |
87 def after(self): | |
88 self.sourcerepo.unlock() | |
89 | |
90 def getheads(self): | |
91 if not self.rev: | |
92 return [self.branch.last_revision()] | |
93 try: | |
94 r = RevisionSpec.from_string(self.rev) | |
95 info = r.in_history(self.branch) | |
96 except errors.BzrError: | |
97 raise util.Abort(_('%s is not a valid revision in current branch') | |
98 % self.rev) | |
99 return [info.rev_id] | |
100 | |
101 def getfile(self, name, rev): | |
102 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
|
103 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
|
104 kind = None |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
105 if fileid is not None: |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
106 kind = revtree.kind(fileid) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
107 if kind not in supportedkinds: |
7053 | 108 # the file is not available anymore - was deleted |
109 raise IOError(_('%s is not available in %s anymore') % | |
110 (name, rev)) | |
8423
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
111 if kind == 'symlink': |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
112 target = revtree.get_symlink_target(fileid) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
113 if target is None: |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
114 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
|
115 % (name, rev)) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
116 return target |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
117 else: |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
118 sio = revtree.get_file(fileid) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
119 return sio.read() |
7053 | 120 |
121 def getmode(self, name, rev): | |
122 return self._modecache[(name, rev)] | |
123 | |
124 def getchanges(self, version): | |
125 # set up caches: modecache and revtree | |
126 self._modecache = {} | |
127 self._revtree = self.sourcerepo.revision_tree(version) | |
128 # get the parentids from the cache | |
129 parentids = self._parentids.pop(version) | |
130 # only diff against first parent id | |
131 prevtree = self.sourcerepo.revision_tree(parentids[0]) | |
132 return self._gettreechanges(self._revtree, prevtree) | |
133 | |
134 def getcommit(self, version): | |
135 rev = self.sourcerepo.get_revision(version) | |
136 # populate parent id cache | |
137 if not rev.parent_ids: | |
138 parents = [] | |
139 self._parentids[version] = (revision.NULL_REVISION,) | |
140 else: | |
141 parents = self._filterghosts(rev.parent_ids) | |
142 self._parentids[version] = parents | |
143 | |
144 return commit(parents=parents, | |
8305
7a0fcdd3828f
convert/bzr: handle Bazaar timestamps correctly (issue1652).
Greg Ward <greg-hg@gerg.ca>
parents:
8250
diff
changeset
|
145 date='%d %d' % (rev.timestamp, -rev.timezone), |
7053 | 146 author=self.recode(rev.committer), |
147 # bzr returns bytestrings or unicode, depending on the content | |
148 desc=self.recode(rev.message), | |
149 rev=version) | |
150 | |
151 def gettags(self): | |
152 if not self.branch.supports_tags(): | |
153 return {} | |
154 tagdict = self.branch.tags.get_tag_dict() | |
155 bytetags = {} | |
156 for name, rev in tagdict.iteritems(): | |
157 bytetags[self.recode(name)] = rev | |
158 return bytetags | |
159 | |
160 def getchangedfiles(self, rev, i): | |
161 self._modecache = {} | |
162 curtree = self.sourcerepo.revision_tree(rev) | |
163 if i is not None: | |
8165
78658990c725
convert/bzr: make it work with filemaps (issue1631)
Patrick Mezard <pmezard@gmail.com>
parents:
8148
diff
changeset
|
164 parentid = self._parentids[rev][i] |
7053 | 165 else: |
166 # no parent id, get the empty revision | |
167 parentid = revision.NULL_REVISION | |
168 | |
169 prevtree = self.sourcerepo.revision_tree(parentid) | |
170 changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]] | |
171 return changes | |
172 | |
173 def _gettreechanges(self, current, origin): | |
10394
4612cded5176
fix coding style (reported by pylint)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10282
diff
changeset
|
174 revid = current._revision_id |
7053 | 175 changes = [] |
176 renames = {} | |
177 for (fileid, paths, changed_content, versioned, parent, name, | |
178 kind, executable) in current.iter_changes(origin): | |
179 | |
180 if paths[0] == u'' or paths[1] == u'': | |
181 # ignore changes to tree root | |
182 continue | |
183 | |
184 # bazaar tracks directories, mercurial does not, so | |
185 # we have to rename the directory contents | |
186 if kind[1] == 'directory': | |
8126
13b36eb14324
convert/bzr: handle files replaced by directories (issue1623)
Patrick Mezard <pmezard@gmail.com>
parents:
8045
diff
changeset
|
187 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
|
188 # 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
|
189 # so it can be removed. |
13b36eb14324
convert/bzr: handle files replaced by directories (issue1623)
Patrick Mezard <pmezard@gmail.com>
parents:
8045
diff
changeset
|
190 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
|
191 |
7053 | 192 if None not in paths and paths[0] != paths[1]: |
193 # neither an add nor an delete - a move | |
194 # rename all directory contents manually | |
195 subdir = origin.inventory.path2id(paths[0]) | |
196 # get all child-entries of the directory | |
197 for name, entry in origin.inventory.iter_entries(subdir): | |
198 # hg does not track directory renames | |
199 if entry.kind == 'directory': | |
200 continue | |
201 frompath = self.recode(paths[0] + '/' + name) | |
202 topath = self.recode(paths[1] + '/' + name) | |
203 # register the files as changed | |
204 changes.append((frompath, revid)) | |
205 changes.append((topath, revid)) | |
206 # add to mode cache | |
10282
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
10263
diff
changeset
|
207 mode = ((entry.executable and 'x') |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
10263
diff
changeset
|
208 or (entry.kind == 'symlink' and 's') |
7053 | 209 or '') |
210 self._modecache[(topath, revid)] = mode | |
211 # register the change as move | |
212 renames[topath] = frompath | |
213 | |
214 # no futher changes, go to the next change | |
215 continue | |
216 | |
217 # we got unicode paths, need to convert them | |
218 path, topath = [self.recode(part) for part in paths] | |
219 | |
220 if topath is None: | |
221 # file deleted | |
222 changes.append((path, revid)) | |
223 continue | |
224 | |
225 # renamed | |
226 if path and path != topath: | |
227 renames[topath] = path | |
8035
cb77c0fbec39
convert: remove renamed source files (issue1505)
Xavier ALT <dex@phoenix-ind.net>
parents:
7060
diff
changeset
|
228 changes.append((path, revid)) |
7053 | 229 |
230 # populate the mode cache | |
231 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
|
232 mode = ((executable and 'x') or (kind == 'symlink' and 'l') |
7053 | 233 or '') |
234 self._modecache[(topath, revid)] = mode | |
235 changes.append((topath, revid)) | |
236 | |
237 return changes, renames | |
238 | |
239 def _filterghosts(self, ids): | |
240 """Filters out ghost revisions which hg does not support, see | |
241 <http://bazaar-vcs.org/GhostRevision> | |
242 """ | |
243 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
|
244 parents = tuple([parent for parent in ids if parent in parentmap]) |
7053 | 245 return parents |
246 | |
247 def recode(self, s, encoding=None): | |
248 """This version of recode tries to encode unicode to bytecode, | |
249 and preferably using the UTF-8 codec. | |
250 Other types than Unicode are silently returned, this is by | |
251 intention, e.g. the None-type is not going to be encoded but instead | |
252 just passed through | |
253 """ | |
254 if not encoding: | |
255 encoding = self.encoding or 'utf-8' | |
256 | |
257 if isinstance(s, unicode): | |
258 return s.encode(encoding) | |
259 else: | |
260 # leave it alone | |
261 return s |