/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/plugins/fastimport/helpers.py

Bundle bzr-fastimport.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 
 
16
"""Miscellaneous useful stuff."""
 
17
 
 
18
import stat
 
19
 
 
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
 
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)
 
149
 
 
150
 
 
151
def binary_stream(stream):
 
152
    """Ensure a stream is binary on Windows.
 
153
 
 
154
    :return: the stream
 
155
    """
 
156
    try:
 
157
        import os
 
158
        if os.name == 'nt':
 
159
            fileno = getattr(stream, 'fileno', None)
 
160
            if fileno:
 
161
                no = fileno()
 
162
                if no >= 0:     # -1 means we're working as subprocess
 
163
                    import msvcrt
 
164
                    msvcrt.setmode(no, os.O_BINARY)
 
165
    except ImportError:
 
166
        pass
 
167
    return stream
 
168
 
 
169
 
 
170
def single_plural(n, single, plural):
 
171
    """Return a single or plural form of a noun based on number."""
 
172
    if n == 1:
 
173
        return single
 
174
    else:
 
175
        return plural
 
176
 
 
177
 
 
178
def invert_dictset(d):
 
179
    """Invert a dictionary with keys matching a set of values, turned into lists."""
 
180
    # Based on recipe from ASPN
 
181
    result = {}
 
182
    for k, c in d.iteritems():
 
183
        for v in c:
 
184
            keys = result.setdefault(v, [])
 
185
            keys.append(k)
 
186
    return result
 
187
 
 
188
 
 
189
def invert_dict(d):
 
190
    """Invert a dictionary with keys matching each value turned into a list."""
 
191
    # Based on recipe from ASPN
 
192
    result = {}
 
193
    for k, v in d.iteritems():
 
194
        keys = result.setdefault(v, [])
 
195
        keys.append(k)
 
196
    return result
 
197
 
 
198