~a-s-usov/bzr-fastimport/fastimport

277.2.1 by Jelmer Vernooij
Move pure-fastimport code into its own directory, in preparation of splitting it into a separate package.
1
# Copyright (C) 2008 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
334 by Jelmer Vernooij
Remove old FSF address. Thanks Dan Callaghan.
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
277.2.1 by Jelmer Vernooij
Move pure-fastimport code into its own directory, in preparation of splitting it into a separate package.
15
16
"""Miscellaneous useful stuff."""
17
277.2.8 by Jelmer Vernooij
Use modes for FileModifyCommand.
18
import stat
19
277.2.1 by Jelmer Vernooij
Move pure-fastimport code into its own directory, in preparation of splitting it into a separate package.
20
21
def escape_commit_message(message):
22
    """Replace xml-incompatible control characters."""
23
    # This really ought to be provided by bzrlib.
24
    # Code copied from bzrlib.commit.
25
26
    # Python strings can include characters that can't be
27
    # represented in well-formed XML; escape characters that
28
    # aren't listed in the XML specification
29
    # (http://www.w3.org/TR/REC-xml/#NT-Char).
30
    import re
31
    message, _ = re.subn(
32
        u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
33
        lambda match: match.group(0).encode('unicode_escape'),
34
        message)
35
    return message
36
37
38
def best_format_for_objects_in_a_repository(repo):
39
    """Find the high-level format for branches and trees given a repository.
40
41
    When creating branches and working trees within a repository, Bazaar
42
    defaults to using the default format which may not be the best choice.
43
    This routine does a reverse lookup of the high-level format registry
44
    to find the high-level format that a shared repository was most likely
45
    created via.
46
47
    :return: the BzrDirFormat or None if no matches were found.
48
    """
49
    # Based on code from bzrlib/info.py ...
50
    from bzrlib import bzrdir
51
    repo_format = repo._format
52
    candidates  = []
53
    non_aliases = set(bzrdir.format_registry.keys())
54
    non_aliases.difference_update(bzrdir.format_registry.aliases())
55
    for key in non_aliases:
56
        format = bzrdir.format_registry.make_bzrdir(key)
57
        # LocalGitBzrDirFormat has no repository_format
58
        if hasattr(format, "repository_format"):
59
            if format.repository_format == repo_format:
60
                candidates.append((key, format))
61
    if len(candidates):
62
        # Assume the first one. Is there any reason not to do that?
63
        name, format = candidates[0]
64
        return format
65
    else:
66
        return None
67
68
69
def open_destination_directory(location, format=None, verbose=True):
70
    """Open a destination directory and return the BzrDir.
71
72
    If destination has a control directory, it will be returned.
73
    Otherwise, the destination should be empty or non-existent and
74
    a shared repository will be created there.
75
76
    :param location: the destination directory
77
    :param format: the format to use or None for the default
78
    :param verbose: display the format used if a repository is created.
79
    :return: BzrDir for the destination
80
    """
81
    import os
82
    from bzrlib import bzrdir, errors, trace, transport
83
    try:
84
        control, relpath = bzrdir.BzrDir.open_containing(location)
85
        # XXX: Check the relpath is None here?
86
        return control
87
    except errors.NotBranchError:
88
        pass
89
90
    # If the directory exists, check it is empty. Otherwise create it.
91
    if os.path.exists(location):
92
        contents = os.listdir(location)
93
        if contents:
94
            errors.BzrCommandError("Destination must have a .bzr directory, "
95
                " not yet exist or be empty - files found in %s" % (location,))
96
    else:
97
        try:
98
            os.mkdir(location)
99
        except IOError, ex:
100
            errors.BzrCommandError("Unable to create %s: %s" %
101
                (location, ex))
102
103
    # Create a repository for the nominated format.
104
    trace.note("Creating destination repository ...")
105
    if format is None:
106
        format = bzrdir.format_registry.make_bzrdir('default')
107
    to_transport = transport.get_transport(location)
108
    to_transport.ensure_base()
109
    control = format.initialize_on_transport(to_transport)
110
    repo = control.create_repository(shared=True)
111
    if verbose:
112
        from bzrlib.info import show_bzrdir_info
113
        show_bzrdir_info(repo.bzrdir, verbose=0)
114
    return control
277.2.8 by Jelmer Vernooij
Use modes for FileModifyCommand.
115
116
117
def kind_to_mode(kind, executable):
118
    if kind == "file":
119
        if executable == True:
120
            return stat.S_IFREG | 0755
121
        elif executable == False:
122
            return stat.S_IFREG | 0644
123
        else:
124
            raise AssertionError("Executable %r invalid" % executable)
125
    elif kind == "symlink":
126
        return stat.S_IFLNK
127
    elif kind == "directory":
128
        return stat.S_IFDIR
129
    elif kind == "tree-reference":
130
        return 0160000
131
    else:
132
        raise AssertionError("Unknown file kind '%s'" % kind)
133
134
135
def mode_to_kind(mode):
136
    # Note: Output from git-fast-export slightly different to spec
137
    if mode in (0644, 0100644):
138
        return 'file', False
139
    elif mode in (0755, 0100755):
140
        return 'file', True
141
    elif mode == 0040000:
142
        return 'directory', False
143
    elif mode == 0120000:
144
        return 'symlink', False
145
    elif mode == 0160000:
146
        return 'tree-reference', False
147
    else:
148
        raise AssertionError("invalid mode %o" % mode)