Mercurial > hg
annotate hgext/convert/bzr.py @ 12129:07ac2a560fce stable
remove: properly set return code when warnings are issued
This removes the warn() function in favor of issuing warnings directly
for each kind of file that Mercurial won't remove.
This also uses three separate translatable strings instead of using
string formatting to build the message. This should make it easier to
localize.
author | Brodie Rao <brodie@bitheap.org> |
---|---|
date | Mon, 30 Aug 2010 20:27:25 -0400 |
parents | 33010ff1fd6f |
children | 516b000fbb7e |
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 |
dd24488cba2d
convert/bzr: warn when source is a lightweight checkout (issue1647)
Patrick Mezard <pmezard@gmail.com>
parents:
8434
diff
changeset
|
64 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
|
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 |