/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.200.252 by Jelmer Vernooij
Clarify history, copyright.
1
# Copyright (C) 2007 Canonical Ltd
0.252.32 by Jelmer Vernooij
update copyright
2
# Copyright (C) 2008-2010 Jelmer Vernooij <jelmer@samba.org>
0.200.252 by Jelmer Vernooij
Clarify history, copyright.
3
# Copyright (C) 2008 John Carr
0.200.18 by John Arbash Meinel
Start splitting up the Git{Branch,Dir,Repository} into separate modules, etc.
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
"""Converters, etc for going between Bazaar and Git ids."""
20
0.200.1594 by Jelmer Vernooij
Use absolute_import everywhere.
21
from __future__ import absolute_import
22
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
23
import base64
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
24
import stat
25
0.200.292 by Jelmer Vernooij
Fix formatting.
26
from bzrlib import (
0.200.926 by Jelmer Vernooij
Fix formatting, drop support for Bazaar < 2.0.
27
    bencode,
0.200.292 by Jelmer Vernooij
Fix formatting.
28
    errors,
29
    foreign,
0.200.490 by Jelmer Vernooij
Warn about unusual modes and escaped XML-invalid characters.
30
    trace,
0.200.292 by Jelmer Vernooij
Fix formatting.
31
    )
32
from bzrlib.inventory import (
33
    ROOT_ID,
34
    )
0.200.152 by Jelmer Vernooij
Fix syntax errors.
35
from bzrlib.foreign import (
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
36
    ForeignVcs,
37
    VcsMappingRegistry,
0.200.292 by Jelmer Vernooij
Fix formatting.
38
    ForeignRevision,
39
    )
0.200.701 by Jelmer Vernooij
Fix check in git repos.
40
from bzrlib.revision import (
41
    NULL_REVISION,
42
    )
0.200.1598 by Jelmer Vernooij
Print proper error when unknown fields are encountered.
43
from bzrlib.plugins.git.errors import (
44
    NoPushSupport,
45
    UnknownCommitExtra,
46
    )
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
47
from bzrlib.plugins.git.hg import (
48
    format_hg_metadata,
49
    extract_hg_metadata,
50
    )
0.252.2 by Jelmer Vernooij
Add functions for adding metadata to revision messages.
51
from bzrlib.plugins.git.roundtrip import (
52
    extract_bzr_metadata,
0.252.4 by Jelmer Vernooij
More work on roundtripping.
53
    inject_bzr_metadata,
0.200.1324 by Jelmer Vernooij
More work on roundtripping support.
54
    CommitSupplement,
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
55
    deserialize_fileid_map,
56
    serialize_fileid_map,
0.252.2 by Jelmer Vernooij
Add functions for adding metadata to revision messages.
57
    )
0.200.309 by Jelmer Vernooij
Add XML escaping to work around serialization bug in bzr.
58
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
59
DEFAULT_FILE_MODE = stat.S_IFREG | 0644
0.200.345 by Jelmer Vernooij
Keep track of file modes to use.
60
0.206.1 by Jelmer Vernooij
Use foreign utility functions.
61
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
62
def escape_file_id(file_id):
0.200.1419 by Jelmer Vernooij
Escape/unescape ^L characters.
63
    return file_id.replace('_', '__').replace(' ', '_s').replace('\x0c', '_c')
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
64
65
66
def unescape_file_id(file_id):
0.200.390 by Jelmer Vernooij
Fix file id unescape function when there are other underscores in the file id.
67
    ret = []
68
    i = 0
69
    while i < len(file_id):
70
        if file_id[i] != '_':
71
            ret.append(file_id[i])
72
        else:
73
            if file_id[i+1] == '_':
74
                ret.append("_")
75
            elif file_id[i+1] == 's':
76
                ret.append(" ")
0.200.1419 by Jelmer Vernooij
Escape/unescape ^L characters.
77
            elif file_id[i+1] == 'c':
78
                ret.append("\x0c")
0.200.390 by Jelmer Vernooij
Fix file id unescape function when there are other underscores in the file id.
79
            else:
0.200.826 by Jelmer Vernooij
Fix some long lines.
80
                raise AssertionError("unknown escape character %s" %
81
                    file_id[i+1])
0.200.390 by Jelmer Vernooij
Fix file id unescape function when there are other underscores in the file id.
82
            i += 1
83
        i += 1
84
    return "".join(ret)
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
85
86
0.200.376 by Jelmer Vernooij
Make sure author and committer names pushed to git contain < and >, otherwise the git parser barfs.
87
def fix_person_identifier(text):
88
    if "<" in text and ">" in text:
89
        return text
90
    return "%s <%s>" % (text, text)
91
92
0.200.490 by Jelmer Vernooij
Warn about unusual modes and escaped XML-invalid characters.
93
def warn_escaped(commit, num_escaped):
94
    trace.warning("Escaped %d XML-invalid characters in %s. Will be unable "
95
                  "to regenerate the SHA map.", num_escaped, commit)
96
97
98
def warn_unusual_mode(commit, path, mode):
0.200.826 by Jelmer Vernooij
Fix some long lines.
99
    trace.mutter("Unusual file mode %o for %s in %s. Storing as revision "
100
                 "property. ", mode, path, commit)
0.200.490 by Jelmer Vernooij
Warn about unusual modes and escaped XML-invalid characters.
101
102
0.206.1 by Jelmer Vernooij
Use foreign utility functions.
103
class BzrGitMapping(foreign.VcsMapping):
0.200.97 by Jelmer Vernooij
use mapping object.
104
    """Class that maps between Git and Bazaar semantics."""
105
    experimental = False
106
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
107
    BZR_FILE_IDS_FILE = None
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
108
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
109
    BZR_DUMMY_FILE = None
0.252.26 by Jelmer Vernooij
Add is_control_file method to BzrGitMapping.
110
0.200.1328 by Jelmer Vernooij
More test fixes.
111
    def is_special_file(self, filename):
112
        return (filename in (self.BZR_FILE_IDS_FILE, self.BZR_DUMMY_FILE))
113
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
114
    def __init__(self):
0.200.1263 by Jelmer Vernooij
Fix foreign_vcs_git.
115
        super(BzrGitMapping, self).__init__(foreign_vcs_git)
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
116
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
117
    def __eq__(self, other):
0.200.1020 by Jelmer Vernooij
Store testament-sha1 in metadata.
118
        return (type(self) == type(other) and
0.200.726 by Jelmer Vernooij
Factor out conversion of branch names to refs.
119
                self.revid_prefix == other.revid_prefix)
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
120
121
    @classmethod
122
    def revision_id_foreign_to_bzr(cls, git_rev_id):
0.200.97 by Jelmer Vernooij
use mapping object.
123
        """Convert a git revision id handle to a Bazaar revision id."""
0.200.891 by Jelmer Vernooij
Use ZERO_SHA constant where possible.
124
        from dulwich.protocol import ZERO_SHA
125
        if git_rev_id == ZERO_SHA:
0.200.769 by Jelmer Vernooij
Cope with open_branch() actually checking whether there is a branch present.
126
            return NULL_REVISION
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
127
        return "%s:%s" % (cls.revid_prefix, git_rev_id)
0.200.97 by Jelmer Vernooij
use mapping object.
128
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
129
    @classmethod
130
    def revision_id_bzr_to_foreign(cls, bzr_rev_id):
0.200.97 by Jelmer Vernooij
use mapping object.
131
        """Convert a Bazaar revision id to a git revision id handle."""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
132
        if not bzr_rev_id.startswith("%s:" % cls.revid_prefix):
133
            raise errors.InvalidRevisionId(bzr_rev_id, cls)
134
        return bzr_rev_id[len(cls.revid_prefix)+1:], cls()
0.200.97 by Jelmer Vernooij
use mapping object.
135
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
136
    def generate_file_id(self, path):
0.200.297 by Jelmer Vernooij
Cope with non-ascii characters in filenames (needs a test..).
137
        # Git paths are just bytestrings
138
        # We must just hope they are valid UTF-8..
0.200.157 by Jelmer Vernooij
Fix some bit of fetching.
139
        if path == "":
140
            return ROOT_ID
0.200.973 by Jelmer Vernooij
Add tests for generate_file_id.
141
        if type(path) is unicode:
142
            path = path.encode("utf-8")
0.200.297 by Jelmer Vernooij
Cope with non-ascii characters in filenames (needs a test..).
143
        return escape_file_id(path)
0.200.150 by Jelmer Vernooij
Abstract away file id generation.
144
0.252.26 by Jelmer Vernooij
Add is_control_file method to BzrGitMapping.
145
    def is_control_file(self, path):
146
        return path in (self.BZR_FILE_IDS_FILE, self.BZR_DUMMY_FILE)
147
0.230.2 by Jelmer Vernooij
Fix versionedfiles.
148
    def parse_file_id(self, file_id):
149
        if file_id == ROOT_ID:
150
            return ""
151
        return unescape_file_id(file_id)
152
0.252.31 by Jelmer Vernooij
Properly escape revids when using them in ref names.
153
    def revid_as_refname(self, revid):
154
        import urllib
155
        return "refs/bzr/%s" % urllib.quote(revid)
156
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
157
    def import_unusual_file_modes(self, rev, unusual_file_modes):
158
        if unusual_file_modes:
0.200.878 by Jelmer Vernooij
Fix determining of unusual file modes.
159
            ret = [(path, unusual_file_modes[path])
160
                   for path in sorted(unusual_file_modes.keys())]
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
161
            rev.properties['file-modes'] = bencode.bencode(ret)
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
162
0.200.547 by Jelmer Vernooij
Support getting unusual file modes out of revision properties.
163
    def export_unusual_file_modes(self, rev):
164
        try:
0.200.894 by Jelmer Vernooij
Simplify formatting a bit.
165
            file_modes = rev.properties['file-modes']
0.200.547 by Jelmer Vernooij
Support getting unusual file modes out of revision properties.
166
        except KeyError:
167
            return {}
0.200.894 by Jelmer Vernooij
Simplify formatting a bit.
168
        else:
169
            return dict([(self.generate_file_id(path), mode) for (path, mode) in bencode.bdecode(file_modes.encode("utf-8"))])
0.200.547 by Jelmer Vernooij
Support getting unusual file modes out of revision properties.
170
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
171
    def _generate_git_svn_metadata(self, rev, encoding):
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
172
        try:
0.200.894 by Jelmer Vernooij
Simplify formatting a bit.
173
            git_svn_id = rev.properties["git-svn-id"]
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
174
        except KeyError:
175
            return ""
0.200.894 by Jelmer Vernooij
Simplify formatting a bit.
176
        else:
177
            return "\ngit-svn-id: %s\n" % git_svn_id.encode(encoding)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
178
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
179
    def _generate_hg_message_tail(self, rev):
180
        extra = {}
181
        renames = []
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
182
        branch = 'default'
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
183
        for name in rev.properties:
184
            if name == 'hg:extra:branch':
185
                branch = rev.properties['hg:extra:branch']
186
            elif name.startswith('hg:extra'):
0.200.826 by Jelmer Vernooij
Fix some long lines.
187
                extra[name[len('hg:extra:'):]] = base64.b64decode(
188
                    rev.properties[name])
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
189
            elif name == 'hg:renames':
0.200.826 by Jelmer Vernooij
Fix some long lines.
190
                renames = bencode.bdecode(base64.b64decode(
191
                    rev.properties['hg:renames']))
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
192
            # TODO: Export other properties as 'bzr:' extras?
0.200.660 by Jelmer Vernooij
Fix encoding issues.
193
        ret = format_hg_metadata(renames, branch, extra)
194
        assert isinstance(ret, str)
195
        return ret
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
196
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
197
    def _extract_git_svn_metadata(self, rev, message):
198
        lines = message.split("\n")
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
199
        if not (lines[-1] == "" and len(lines) >= 2 and lines[-2].startswith("git-svn-id:")):
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
200
            return message
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
201
        git_svn_id = lines[-2].split(": ", 1)[1]
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
202
        rev.properties['git-svn-id'] = git_svn_id
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
203
        (url, rev, uuid) = parse_git_svn_id(git_svn_id)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
204
        # FIXME: Convert this to converted-from property somehow..
0.200.660 by Jelmer Vernooij
Fix encoding issues.
205
        ret = "\n".join(lines[:-2])
206
        assert isinstance(ret, str)
207
        return ret
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
208
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
209
    def _extract_hg_metadata(self, rev, message):
210
        (message, renames, branch, extra) = extract_hg_metadata(message)
211
        if branch is not None:
212
            rev.properties['hg:extra:branch'] = branch
213
        for name, value in extra.iteritems():
214
            rev.properties['hg:extra:' + name] = base64.b64encode(value)
0.200.639 by Jelmer Vernooij
Support renames in hg-git messages as well.
215
        if renames:
0.200.826 by Jelmer Vernooij
Fix some long lines.
216
            rev.properties['hg:renames'] = base64.b64encode(bencode.bencode(
217
                [(new, old) for (old, new) in renames.iteritems()]))
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
218
        return message
219
0.252.2 by Jelmer Vernooij
Add functions for adding metadata to revision messages.
220
    def _extract_bzr_metadata(self, rev, message):
221
        (message, metadata) = extract_bzr_metadata(message)
0.252.4 by Jelmer Vernooij
More work on roundtripping.
222
        return message, metadata
0.252.2 by Jelmer Vernooij
Add functions for adding metadata to revision messages.
223
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
224
    def _decode_commit_message(self, rev, message, encoding):
0.200.1324 by Jelmer Vernooij
More work on roundtripping support.
225
        return message.decode(encoding), CommitSupplement()
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
226
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
227
    def _encode_commit_message(self, rev, message, encoding):
228
        return message.encode(encoding)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
229
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
230
    def export_fileid_map(self, fileid_map):
231
        """Export a file id map to a fileid map.
232
233
        :param fileid_map: File id map, mapping paths to file ids
234
        :return: A Git blob object
235
        """
0.252.23 by Jelmer Vernooij
More work on roundtripping support.
236
        from dulwich.objects import Blob
237
        b = Blob()
238
        b.set_raw_chunks(serialize_fileid_map(fileid_map))
239
        return b
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
240
0.200.1509 by Jelmer Vernooij
Properly raise exception when pulling from git into bzr without experimental mappings.
241
    def export_commit(self, rev, tree_sha, parent_lookup, lossy,
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
242
                      verifiers):
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
243
        """Turn a Bazaar revision in to a Git commit
244
245
        :param tree_sha: Tree sha for the commit
0.200.826 by Jelmer Vernooij
Fix some long lines.
246
        :param parent_lookup: Function for looking up the GIT sha equiv of a
247
            bzr revision
0.200.1509 by Jelmer Vernooij
Properly raise exception when pulling from git into bzr without experimental mappings.
248
        :param lossy: Whether to store roundtripping information.
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
249
        :param verifiers: Verifiers info
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
250
        :return dulwich.objects.Commit represent the revision:
251
        """
252
        from dulwich.objects import Commit
253
        commit = Commit()
254
        commit.tree = tree_sha
0.200.1509 by Jelmer Vernooij
Properly raise exception when pulling from git into bzr without experimental mappings.
255
        if not lossy:
0.200.1324 by Jelmer Vernooij
More work on roundtripping support.
256
            metadata = CommitSupplement()
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
257
            metadata.verifiers = verifiers
0.252.8 by Jelmer Vernooij
Support ghost revisions while roundtripping.
258
        else:
259
            metadata = None
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
260
        parents = []
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
261
        for p in rev.parent_ids:
0.200.705 by Jelmer Vernooij
Cope with imports.
262
            try:
263
                git_p = parent_lookup(p)
264
            except KeyError:
265
                git_p = None
0.252.8 by Jelmer Vernooij
Support ghost revisions while roundtripping.
266
                if metadata is not None:
267
                    metadata.explicit_parent_ids = rev.parent_ids
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
268
            if git_p is not None:
269
                assert len(git_p) == 40, "unexpected length for %r" % git_p
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
270
                parents.append(git_p)
271
        commit.parents = parents
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
272
        try:
273
            encoding = rev.properties['git-explicit-encoding']
274
        except KeyError:
275
            encoding = rev.properties.get('git-implicit-encoding', 'utf-8')
276
        commit.encoding = rev.properties.get('git-explicit-encoding')
277
        commit.committer = fix_person_identifier(rev.committer.encode(
278
            encoding))
279
        commit.author = fix_person_identifier(
280
            rev.get_apparent_authors()[0].encode(encoding))
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
281
        commit.commit_time = long(rev.timestamp)
282
        if 'author-timestamp' in rev.properties:
283
            commit.author_time = long(rev.properties['author-timestamp'])
284
        else:
285
            commit.author_time = commit.commit_time
0.200.884 by Jelmer Vernooij
Cope with -0000 as timezone in Git commits.
286
        commit._commit_timezone_neg_utc = "commit-timezone-neg-utc" in rev.properties
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
287
        commit.commit_timezone = rev.timezone
0.200.884 by Jelmer Vernooij
Cope with -0000 as timezone in Git commits.
288
        commit._author_timezone_neg_utc = "author-timezone-neg-utc" in rev.properties
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
289
        if 'author-timezone' in rev.properties:
290
            commit.author_timezone = int(rev.properties['author-timezone'])
291
        else:
0.200.695 by Jelmer Vernooij
Clean up trailing whitespace.
292
            commit.author_timezone = commit.commit_timezone
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
293
        commit.message = self._encode_commit_message(rev, rev.message, 
294
            encoding)
0.252.40 by Jelmer Vernooij
Checks for roundtripping.
295
        assert type(commit.message) == str
0.252.8 by Jelmer Vernooij
Support ghost revisions while roundtripping.
296
        if metadata is not None:
0.252.4 by Jelmer Vernooij
More work on roundtripping.
297
            try:
298
                mapping_registry.parse_revision_id(rev.revision_id)
299
            except errors.InvalidRevisionId:
300
                metadata.revision_id = rev.revision_id
0.252.10 by Jelmer Vernooij
Support roundtripping custom revision properties.
301
            mapping_properties = set(
302
                ['author', 'author-timezone', 'author-timezone-neg-utc',
303
                 'commit-timezone-neg-utc', 'git-implicit-encoding',
0.252.15 by Jelmer Vernooij
Add file-modes to list of mapping properties.
304
                 'git-explicit-encoding', 'author-timestamp', 'file-modes'])
0.252.10 by Jelmer Vernooij
Support roundtripping custom revision properties.
305
            for k, v in rev.properties.iteritems():
306
                if not k in mapping_properties:
307
                    metadata.properties[k] = v
0.200.1510 by Jelmer Vernooij
Fix tests.
308
        if not lossy:
309
            if self.roundtripping:
310
                commit.message = inject_bzr_metadata(commit.message, metadata, 
311
                                                     encoding)
312
            else:
313
                raise NoPushSupport()
0.252.40 by Jelmer Vernooij
Checks for roundtripping.
314
        assert type(commit.message) == str
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
315
        return commit
316
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
317
    def import_fileid_map(self, blob):
318
        """Convert a git file id map blob.
319
320
        :param blob: Git blob object with fileid map
321
        :return: Dictionary mapping paths to file ids
322
        """
0.252.35 by Jelmer Vernooij
Ignore control files in inventories.
323
        return deserialize_fileid_map(blob.data)
0.252.22 by Jelmer Vernooij
Fix file id map (de)serialization.
324
0.252.44 by Jelmer Vernooij
Properly look up Bazaar revision ids for revision parents in case they are round-tripped.
325
    def import_commit(self, commit, lookup_parent_revid):
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
326
        """Convert a git commit to a bzr revision.
327
0.200.1021 by Jelmer Vernooij
Put testament sha1 in revisions.
328
        :return: a `bzrlib.revision.Revision` object, foreign revid and a
329
            testament sha1
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
330
        """
331
        if commit is None:
332
            raise AssertionError("Commit object can't be None")
0.200.1598 by Jelmer Vernooij
Print proper error when unknown fields are encountered.
333
        if commit.extra:
334
            raise UnknownCommitExtra(commit, [item[0] for item in commit.extra])
0.200.826 by Jelmer Vernooij
Fix some long lines.
335
        rev = ForeignRevision(commit.id, self,
336
                self.revision_id_foreign_to_bzr(commit.id))
0.252.4 by Jelmer Vernooij
More work on roundtripping.
337
        rev.git_metadata = None
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
338
        def decode_using_encoding(rev, commit, encoding):
339
            rev.committer = str(commit.committer).decode(encoding)
340
            if commit.committer != commit.author:
341
                rev.properties['author'] = str(commit.author).decode(encoding)
0.252.4 by Jelmer Vernooij
More work on roundtripping.
342
            rev.message, rev.git_metadata = self._decode_commit_message(
343
                rev, commit.message, encoding)
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
344
        if commit.encoding is not None:
345
            rev.properties['git-explicit-encoding'] = commit.encoding
346
            decode_using_encoding(rev, commit, commit.encoding)
347
        else:
348
            for encoding in ('utf-8', 'latin1'):
349
                try:
350
                    decode_using_encoding(rev, commit, encoding)
351
                except UnicodeDecodeError:
352
                    pass
353
                else:
354
                    if encoding != 'utf-8':
355
                        rev.properties['git-implicit-encoding'] = encoding
356
                    break
0.200.350 by Jelmer Vernooij
Support author_time
357
        if commit.commit_time != commit.author_time:
358
            rev.properties['author-timestamp'] = str(commit.author_time)
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
359
        if commit.commit_timezone != commit.author_timezone:
0.200.826 by Jelmer Vernooij
Fix some long lines.
360
            rev.properties['author-timezone'] = "%d" % commit.author_timezone
0.200.884 by Jelmer Vernooij
Cope with -0000 as timezone in Git commits.
361
        if commit._author_timezone_neg_utc:
362
            rev.properties['author-timezone-neg-utc'] = ""
363
        if commit._commit_timezone_neg_utc:
364
            rev.properties['commit-timezone-neg-utc'] = ""
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
365
        rev.timestamp = commit.commit_time
0.200.440 by Jelmer Vernooij
Remove silly mapping of timezones; dulwich uses offsets now as well.
366
        rev.timezone = commit.commit_timezone
0.261.5 by Jelmer Vernooij
Fix looking up of parents during fetch.
367
        rev.parent_ids = None
0.252.4 by Jelmer Vernooij
More work on roundtripping.
368
        if rev.git_metadata is not None:
0.252.6 by Jelmer Vernooij
Roundtripping support for revision ids works.
369
            md = rev.git_metadata
0.200.1021 by Jelmer Vernooij
Put testament sha1 in revisions.
370
            roundtrip_revid = md.revision_id
0.252.8 by Jelmer Vernooij
Support ghost revisions while roundtripping.
371
            if md.explicit_parent_ids:
372
                rev.parent_ids = md.explicit_parent_ids
0.252.10 by Jelmer Vernooij
Support roundtripping custom revision properties.
373
            rev.properties.update(md.properties)
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
374
            verifiers = md.verifiers
0.200.1021 by Jelmer Vernooij
Put testament sha1 in revisions.
375
        else:
376
            roundtrip_revid = None
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
377
            verifiers = {}
0.261.5 by Jelmer Vernooij
Fix looking up of parents during fetch.
378
        if rev.parent_ids is None:
379
            rev.parent_ids = tuple([lookup_parent_revid(p) for p in commit.parents])
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
380
        return rev, roundtrip_revid, verifiers
0.200.151 by Jelmer Vernooij
Support converting git objects to bzr objects.
381
0.252.43 by Jelmer Vernooij
Some refactoring, support proper file ids in revision deltas.
382
    def get_fileid_map(self, lookup_object, tree_sha):
383
        """Obtain a fileid map for a particular tree.
384
385
        :param lookup_object: Function for looking up an object
386
        :param tree_sha: SHA of the root tree
387
        :return: GitFileIdMap instance
388
        """
389
        try:
390
            file_id_map_sha = lookup_object(tree_sha)[self.BZR_FILE_IDS_FILE][1]
391
        except KeyError:
392
            file_ids = {}
393
        else:
394
            file_ids = self.import_fileid_map(lookup_object(file_id_map_sha))
395
        return GitFileIdMap(file_ids, self)
396
0.200.97 by Jelmer Vernooij
use mapping object.
397
0.200.190 by Jelmer Vernooij
Bless current mapping as v1.
398
class BzrGitMappingv1(BzrGitMapping):
399
    revid_prefix = 'git-v1'
400
    experimental = False
401
0.200.393 by Jelmer Vernooij
Provide __str__ implementation for mapping, fix docstring for ForeignGit.
402
    def __str__(self):
403
        return self.revid_prefix
404
0.200.190 by Jelmer Vernooij
Bless current mapping as v1.
405
406
class BzrGitMappingExperimental(BzrGitMappingv1):
0.200.104 by Jelmer Vernooij
Use bzr-foreign function names for converting between git and bzr revids.
407
    revid_prefix = 'git-experimental'
408
    experimental = True
0.200.912 by Jelmer Vernooij
Merge roundtrip support.
409
    roundtripping = True
0.200.97 by Jelmer Vernooij
use mapping object.
410
0.200.915 by Jelmer Vernooij
Cope with the fact that the old format didn't export file ids.
411
    BZR_FILE_IDS_FILE = '.bzrfileids'
412
413
    BZR_DUMMY_FILE = '.bzrdummy'
414
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
415
    def _decode_commit_message(self, rev, message, encoding):
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
416
        message = self._extract_hg_metadata(rev, message)
0.200.643 by Jelmer Vernooij
Attempt to parse git-svn-id metadata.
417
        message = self._extract_git_svn_metadata(rev, message)
0.252.4 by Jelmer Vernooij
More work on roundtripping.
418
        message, metadata = self._extract_bzr_metadata(rev, message)
419
        return message.decode(encoding), metadata
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
420
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
421
    def _encode_commit_message(self, rev, message, encoding):
422
        ret = message.encode(encoding)
0.200.638 by Jelmer Vernooij
Abstract support for hg-git metadata.
423
        ret += self._generate_hg_message_tail(rev)
0.200.727 by Jelmer Vernooij
Cope with different encodings better, rather than just stripping out
424
        ret += self._generate_git_svn_metadata(rev, encoding)
0.242.1 by Jelmer Vernooij
Add support for parsing hg-git metadata in the experimental mappings.
425
        return ret
426
0.252.44 by Jelmer Vernooij
Properly look up Bazaar revision ids for revision parents in case they are round-tripped.
427
    def import_commit(self, commit, lookup_parent_revid):
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
428
        rev, roundtrip_revid, verifiers = super(BzrGitMappingExperimental, self).import_commit(commit, lookup_parent_revid)
0.200.642 by Jelmer Vernooij
In experimental mappings, set 'converted_revision' property.
429
        rev.properties['converted_revision'] = "git %s\n" % commit.id
0.200.1029 by Jelmer Vernooij
Use dictionary with verifiers rather than requiring testament3-sha1 everywhere.
430
        return rev, roundtrip_revid, verifiers
0.200.642 by Jelmer Vernooij
In experimental mappings, set 'converted_revision' property.
431
0.200.97 by Jelmer Vernooij
use mapping object.
432
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
433
class GitMappingRegistry(VcsMappingRegistry):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
434
    """Registry with available git mappings."""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
435
436
    def revision_id_bzr_to_foreign(self, bzr_revid):
0.200.701 by Jelmer Vernooij
Fix check in git repos.
437
        if bzr_revid == NULL_REVISION:
0.200.892 by Jelmer Vernooij
Lazy import ZERO_SHA.
438
            from dulwich.protocol import ZERO_SHA
0.200.891 by Jelmer Vernooij
Use ZERO_SHA constant where possible.
439
            return ZERO_SHA, None
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
440
        if not bzr_revid.startswith("git-"):
441
            raise errors.InvalidRevisionId(bzr_revid, None)
442
        (mapping_version, git_sha) = bzr_revid.split(":", 1)
443
        mapping = self.get(mapping_version)
444
        return mapping.revision_id_bzr_to_foreign(bzr_revid)
445
446
    parse_revision_id = revision_id_bzr_to_foreign
447
448
449
mapping_registry = GitMappingRegistry()
450
mapping_registry.register_lazy('git-v1', "bzrlib.plugins.git.mapping",
0.200.826 by Jelmer Vernooij
Fix some long lines.
451
    "BzrGitMappingv1")
452
mapping_registry.register_lazy('git-experimental',
453
    "bzrlib.plugins.git.mapping", "BzrGitMappingExperimental")
0.200.1507 by Jelmer Vernooij
Add note on experimental mapping format.
454
# Uncomment the next line to enable the experimental bzr-git mappings.
455
# This will make sure all bzr metadata is pushed into git, allowing for
456
# full roundtripping later.
457
# NOTE: THIS IS EXPERIMENTAL. IT MAY EAT YOUR DATA OR CORRUPT
458
# YOUR BZR OR GIT REPOSITORIES. USE WITH CARE.
0.200.1416 by Jelmer Vernooij
Don't use experimental mapping by default.
459
#mapping_registry.set_default('git-experimental')
460
mapping_registry.set_default('git-v1')
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
461
462
463
class ForeignGit(ForeignVcs):
0.200.393 by Jelmer Vernooij
Provide __str__ implementation for mapping, fix docstring for ForeignGit.
464
    """The Git Stupid Content Tracker"""
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
465
0.243.1 by Jelmer Vernooij
Use foreign branch testing infrastructure.
466
    @property
467
    def branch_format(self):
468
        from bzrlib.plugins.git.branch import GitBranchFormat
469
        return GitBranchFormat()
470
0.200.657 by Jelmer Vernooij
Provide repository_format attribute, as required by newer foreign VCS tests in bzrlib.
471
    @property
472
    def repository_format(self):
473
        from bzrlib.plugins.git.repository import GitRepositoryFormat
474
        return GitRepositoryFormat()
475
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
476
    def __init__(self):
477
        super(ForeignGit, self).__init__(mapping_registry)
0.200.646 by Jelmer Vernooij
Store abbreviation in foreign branch.
478
        self.abbreviation = "git"
0.200.195 by Jelmer Vernooij
Return mapping in revision_id_bzr_to_foreign() as required by the interface.
479
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
480
    @classmethod
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
481
    def serialize_foreign_revid(self, foreign_revid):
482
        return foreign_revid
483
484
    @classmethod
0.200.198 by Jelmer Vernooij
Cope with move of show_foreign_revid.
485
    def show_foreign_revid(cls, foreign_revid):
486
        return { "git commit": foreign_revid }
487
488
0.200.1263 by Jelmer Vernooij
Fix foreign_vcs_git.
489
foreign_vcs_git = ForeignGit()
0.200.637 by Jelmer Vernooij
Allow single place for configuration of default mapping.
490
default_mapping = mapping_registry.get_default()()
0.200.212 by Jelmer Vernooij
Move conversion functions to mapping, use fetch_objects() from repository if present.
491
492
0.275.1 by Jelmer Vernooij
Use root_inventory.
493
def symlink_to_blob(symlink_target):
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
494
    from dulwich.objects import Blob
495
    blob = Blob()
0.200.795 by Jelmer Vernooij
simplify sha extraction for blobs, process multiple blobs at once.
496
    if type(symlink_target) == unicode:
497
        symlink_target = symlink_target.encode('utf-8')
0.200.798 by Jelmer Vernooij
Split out _inventory_to_objects into a function.
498
    blob.data = symlink_target
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
499
    return blob
500
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
501
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
502
def mode_is_executable(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
503
    """Check if mode should be considered executable."""
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
504
    return bool(mode & 0111)
505
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
506
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
507
def mode_kind(mode):
0.200.546 by Jelmer Vernooij
Add more docstrings, support storing unusual file modes.
508
    """Determine the Bazaar inventory kind based on Unix file mode."""
0.200.1538 by Jelmer Vernooij
More work on tree-reference support.
509
    if mode is None:
510
        return None
0.200.521 by Jelmer Vernooij
Abstract out kind mapping a bit, initial work on support tree-references.
511
    entry_kind = (mode & 0700000) / 0100000
512
    if entry_kind == 0:
513
        return 'directory'
514
    elif entry_kind == 1:
515
        file_kind = (mode & 070000) / 010000
516
        if file_kind == 0:
517
            return 'file'
518
        elif file_kind == 2:
519
            return 'symlink'
520
        elif file_kind == 6:
521
            return 'tree-reference'
522
        else:
523
            raise AssertionError(
524
                "Unknown file kind %d, perms=%o." % (file_kind, mode,))
525
    else:
526
        raise AssertionError(
527
            "Unknown kind, perms=%r." % (mode,))
528
0.200.354 by Jelmer Vernooij
Support symlinks in conversion to git.
529
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
530
def object_mode(kind, executable):
531
    if kind == 'directory':
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
532
        return stat.S_IFDIR
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
533
    elif kind == 'symlink':
0.245.1 by INADA Naoki
Handle executable mode for symlink.
534
        mode = stat.S_IFLNK
535
        if executable:
0.200.703 by Jelmer Vernooij
Merge support for executable symlinks.
536
            mode |= 0111
0.245.1 by INADA Naoki
Handle executable mode for symlink.
537
        return mode
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
538
    elif kind == 'file':
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
539
        mode = stat.S_IFREG | 0644
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
540
        if executable:
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
541
            mode |= 0111
542
        return mode
0.200.665 by Jelmer Vernooij
Add more checks for submodules.
543
    elif kind == 'tree-reference':
544
        from dulwich.objects import S_IFGITLINK
545
        return S_IFGITLINK
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
546
    else:
547
        raise AssertionError
548
549
0.238.6 by Jelmer Vernooij
Support sending git am-style patches with "bzr send --format=git".
550
def entry_mode(entry):
551
    """Determine the git file mode for an inventory entry."""
552
    return object_mode(entry.kind, entry.executable)
553
554
0.275.4 by Jelmer Vernooij
Pass children list to directory_to_tree .
555
def directory_to_tree(children, lookup_ie_sha1, unusual_modes, empty_file_name,
556
                      allow_empty=False):
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
557
    """Create a Git Tree object from a Bazaar directory.
558
0.275.4 by Jelmer Vernooij
Pass children list to directory_to_tree .
559
    :param children: Children inventory entries
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
560
    :param lookup_ie_sha1: Lookup the Git SHA1 for a inventory entry
561
    :param unusual_modes: Dictionary with unusual file modes by file ids
562
    :param empty_file_name: Name to use for dummy files in empty directories,
563
        None to ignore empty directories.
564
    """
565
    from dulwich.objects import Blob, Tree
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
566
    tree = Tree()
0.275.4 by Jelmer Vernooij
Pass children list to directory_to_tree .
567
    for name, value in children.iteritems():
568
        ie = children[name]
0.200.549 by Jelmer Vernooij
Fix storing of unusual file modes.
569
        try:
570
            mode = unusual_modes[ie.file_id]
571
        except KeyError:
572
            mode = entry_mode(ie)
0.200.808 by Jelmer Vernooij
Avoid recalculating tree shas we already have.
573
        hexsha = lookup_ie_sha1(ie)
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
574
        if hexsha is not None:
0.200.1152 by Jelmer Vernooij
Require dulwich 0.7.1.
575
            tree.add(name.encode("utf-8"), mode, hexsha)
0.275.4 by Jelmer Vernooij
Pass children list to directory_to_tree .
576
    if not allow_empty and len(tree) == 0:
0.200.589 by Jelmer Vernooij
Fix handling of empty trees.
577
        # Only the root can be an empty tree
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
578
        if empty_file_name is not None:
0.200.1152 by Jelmer Vernooij
Require dulwich 0.7.1.
579
            tree.add(empty_file_name, stat.S_IFREG | 0644, Blob().id)
0.252.30 by Jelmer Vernooij
Support creating dummy files for empty directories.
580
        else:
581
            return None
0.200.359 by Jelmer Vernooij
Simplify file mode handling, avoid inventory_to_tree_and_blobs as it is expensive if trees/blobs have already been converted.
582
    return tree
583
584
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
585
def extract_unusual_modes(rev):
586
    try:
0.200.826 by Jelmer Vernooij
Fix some long lines.
587
        foreign_revid, mapping = mapping_registry.parse_revision_id(
588
            rev.revision_id)
0.200.548 by Jelmer Vernooij
Extract unusual file modes from revision when reconstructing Trees.
589
    except errors.InvalidRevisionId:
590
        return {}
591
    else:
592
        return mapping.export_unusual_file_modes(rev)
593
594
0.200.652 by Jelmer Vernooij
Split out git-svn-id parser as separate function, implement ForeignGit.serialize_foreign_revid.
595
def parse_git_svn_id(text):
596
    (head, uuid) = text.rsplit(" ", 1)
597
    (full_url, rev) = head.rsplit("@", 1)
0.200.653 by Jelmer Vernooij
Fix typo in git-svn-id parser, return revnum as integer.
598
    return (full_url, int(rev), uuid)
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
599
600
601
class GitFileIdMap(object):
602
603
    def __init__(self, file_ids, mapping):
604
        self.file_ids = file_ids
605
        self.paths = None
606
        self.mapping = mapping
607
0.200.1569 by Jelmer Vernooij
Implement GitRevisionTree.all_file_ids().
608
    def all_file_ids(self):
609
        return self.file_ids.values()
610
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
611
    def set_file_id(self, path, file_id):
0.200.1209 by Jelmer Vernooij
Check for types in file id map.
612
        assert type(path) is str
613
        assert type(file_id) is str
0.200.1201 by Jelmer Vernooij
Implement _set_root_id.
614
        self.file_ids[path] = file_id
615
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
616
    def lookup_file_id(self, path):
0.200.984 by Jelmer Vernooij
Handle non-ascii characters in filenames.
617
        assert type(path) is str
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
618
        try:
0.200.973 by Jelmer Vernooij
Add tests for generate_file_id.
619
            file_id = self.file_ids[path]
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
620
        except KeyError:
0.200.973 by Jelmer Vernooij
Add tests for generate_file_id.
621
            file_id = self.mapping.generate_file_id(path)
622
        assert type(file_id) is str
623
        return file_id
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
624
625
    def lookup_path(self, file_id):
626
        if self.paths is None:
627
            self.paths = {}
628
            for k, v in self.file_ids.iteritems():
629
                self.paths[v] = k
630
        try:
0.200.984 by Jelmer Vernooij
Handle non-ascii characters in filenames.
631
            path = self.paths[file_id]
0.252.33 by Jelmer Vernooij
Fix file id map lookups.
632
        except KeyError:
633
            return self.mapping.parse_file_id(file_id)
0.200.984 by Jelmer Vernooij
Handle non-ascii characters in filenames.
634
        else:
635
            assert type(path) is str
636
            return path
0.200.1202 by Jelmer Vernooij
Implement has_or_had_id.
637
638
    def copy(self):
639
        return self.__class__(dict(self.file_ids), self.mapping)