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