Mercurial > hg
annotate hgext/convert/bzr.py @ 12409:0eaf7d32a5d8
test-ssh: test absolute paths in SSH URLs
author | Brodie Rao <brodie@bitheap.org> |
---|---|
date | Fri, 24 Sep 2010 15:50:57 -0500 |
parents | 516b000fbb7e |
children | 6ba2fc0a87ab |
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')): |
10939
9f6731b03906
convert: mark strings for translation
Martin Geisler <mg@lazybytes.net>
parents:
10938
diff
changeset
|
40 raise NoRepo(_('%s does not look like a Bazaar repository') |
9f6731b03906
convert: mark strings for translation
Martin Geisler <mg@lazybytes.net>
parents:
10938
diff
changeset
|
41 % path) |
7973
db3a68fd9387
convert: attempt to check repo type before checking for tool
Matt Mackall <mpm@selenic.com>
parents:
7060
diff
changeset
|
42 |
7053 | 43 try: |
44 # access bzrlib stuff | |
45 branch | |
46 except NameError: | |
10939
9f6731b03906
convert: mark strings for translation
Martin Geisler <mg@lazybytes.net>
parents:
10938
diff
changeset
|
47 raise NoRepo(_('Bazaar modules could not be loaded')) |
7053 | 48 |
49 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
|
50 self._checkrepotype(path) |
7053 | 51 self.branch = branch.Branch.open(path) |
52 self.sourcerepo = self.branch.repository | |
53 self._parentids = {} | |
54 | |
8470
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
55 def _checkrepotype(self, path): |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
56 # 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
|
57 # 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
|
58 try: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
59 from bzrlib import bzrdir |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
60 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
|
61 try: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
62 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
|
63 branch = tree.branch |
12063
516b000fbb7e
cleanup: remove unused variables
Brodie Rao <brodie@bitheap.org>
parents:
11134
diff
changeset
|
64 except (errors.NoWorkingTree, errors.NotLocalUrl): |
8470
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
65 tree = None |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
66 branch = dir.open_branch() |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
67 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
|
68 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
|
69 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
|
70 '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
|
71 'branch instead.\n')) |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
72 except: |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
73 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
|
74 |
7053 | 75 def before(self): |
76 """Before the conversion begins, acquire a read lock | |
77 for all the operations that might need it. Fortunately | |
78 read locks don't block other reads or writes to the | |
79 repository, so this shouldn't have any impact on the usage of | |
80 the source repository. | |
81 | |
82 The alternative would be locking on every operation that | |
83 needs locks (there are currently two: getting the file and | |
84 getting the parent map) and releasing immediately after, | |
85 but this approach can take even 40% longer.""" | |
86 self.sourcerepo.lock_read() | |
87 | |
88 def after(self): | |
89 self.sourcerepo.unlock() | |
90 | |
91 def getheads(self): | |
92 if not self.rev: | |
93 return [self.branch.last_revision()] | |
94 try: | |
95 r = RevisionSpec.from_string(self.rev) | |
96 info = r.in_history(self.branch) | |
97 except errors.BzrError: | |
98 raise util.Abort(_('%s is not a valid revision in current branch') | |
99 % self.rev) | |
100 return [info.rev_id] | |
101 | |
102 def getfile(self, name, rev): | |
103 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
|
104 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
|
105 kind = None |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
106 if fileid is not None: |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
107 kind = revtree.kind(fileid) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
108 if kind not in supportedkinds: |
7053 | 109 # the file is not available anymore - was deleted |
110 raise IOError(_('%s is not available in %s anymore') % | |
111 (name, rev)) | |
11134
33010ff1fd6f
convert: merge sources getmode() into getfile()
Patrick Mezard <pmezard@gmail.com>
parents:
10939
diff
changeset
|
112 mode = self._modecache[(name, rev)] |
8423
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
113 if kind == 'symlink': |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
114 target = revtree.get_symlink_target(fileid) |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
115 if target is None: |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
116 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
|
117 % (name, rev)) |
11134
33010ff1fd6f
convert: merge sources getmode() into getfile()
Patrick Mezard <pmezard@gmail.com>
parents:
10939
diff
changeset
|
118 return target, mode |
8423
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
119 else: |
eb7be0e752d9
convert/bzr: fix symlinks target (issue1626/2)
Patrick Mezard <pmezard@gmail.com>
parents:
8165
diff
changeset
|
120 sio = revtree.get_file(fileid) |
11134
33010ff1fd6f
convert: merge sources getmode() into getfile()
Patrick Mezard <pmezard@gmail.com>
parents:
10939
diff
changeset
|
121 return sio.read(), mode |
7053 | 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): | |
10394
4612cded5176
fix coding style (reported by pylint)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
10282
diff
changeset
|
173 revid = current._revision_id |
7053 | 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 | |
10282
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
10263
diff
changeset
|
206 mode = ((entry.executable and 'x') |
08a0f04b56bd
many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents:
10263
diff
changeset
|
207 or (entry.kind == 'symlink' and 's') |
7053 | 208 or '') |
209 self._modecache[(topath, revid)] = mode | |
210 # register the change as move | |
211 renames[topath] = frompath | |
212 | |
213 # no futher changes, go to the next change | |
214 continue | |
215 | |
216 # we got unicode paths, need to convert them | |
217 path, topath = [self.recode(part) for part in paths] | |
218 | |
219 if topath is None: | |
220 # file deleted | |
221 changes.append((path, revid)) | |
222 continue | |
223 | |
224 # renamed | |
225 if path and path != topath: | |
226 renames[topath] = path | |
8035
cb77c0fbec39
convert: remove renamed source files (issue1505)
Xavier ALT <dex@phoenix-ind.net>
parents:
7060
diff
changeset
|
227 changes.append((path, revid)) |
7053 | 228 |
229 # populate the mode cache | |
230 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
|
231 mode = ((executable and 'x') or (kind == 'symlink' and 'l') |
7053 | 232 or '') |
233 self._modecache[(topath, revid)] = mode | |
234 changes.append((topath, revid)) | |
235 | |
236 return changes, renames | |
237 | |
238 def _filterghosts(self, ids): | |
239 """Filters out ghost revisions which hg does not support, see | |
240 <http://bazaar-vcs.org/GhostRevision> | |
241 """ | |
242 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
|
243 parents = tuple([parent for parent in ids if parent in parentmap]) |
7053 | 244 return parents |
245 | |
246 def recode(self, s, encoding=None): | |
247 """This version of recode tries to encode unicode to bytecode, | |
248 and preferably using the UTF-8 codec. | |
249 Other types than Unicode are silently returned, this is by | |
250 intention, e.g. the None-type is not going to be encoded but instead | |
251 just passed through | |
252 """ | |
253 if not encoding: | |
254 encoding = self.encoding or 'utf-8' | |
255 | |
256 if isinstance(s, unicode): | |
257 return s.encode(encoding) | |
258 else: | |
259 # leave it alone | |
260 return s |