/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.64.30 by Ian Clatworthy
add heads analysis to info processor
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, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
0.64.32 by Ian Clatworthy
move single_plural into helpers
17
"""Miscellaneous useful stuff."""
18
19
20
def single_plural(n, single, plural):
21
    """Return a single or plural form of a noun based on number."""
22
    if n == 1:
23
        return single
24
    else:
25
        return plural
0.64.30 by Ian Clatworthy
add heads analysis to info processor
26
27
0.64.38 by Ian Clatworthy
clean-up doc ready for initial release
28
def defines_to_dict(defines):
29
    """Convert a list of definition strings to a dictionary."""
30
    if defines is None:
31
        return None
32
    result = {}
33
    for define in defines:
34
        kv = define.split('=', 1)
35
        if len(kv) == 1:
36
            result[define.strip()] = 1
37
        else:
38
            result[kv[0].strip()] = kv[1].strip()
39
    return result
40
41
0.64.30 by Ian Clatworthy
add heads analysis to info processor
42
def invert_dict(d):
43
    """Invert a dictionary with keys matching each value turned into a list."""
44
    # Based on recipe from ASPN
45
    result = {}
46
    for k, v in d.iteritems():
47
        keys = result.setdefault(v, [])
48
        keys.append(k)
49
    return result
0.75.1 by Brian de Alwis
Add support for multiple branches by supporting the 'reset' command.
50
0.77.8 by Ian Clatworthy
include subdir & multiple files tests
51
0.75.1 by Brian de Alwis
Add support for multiple branches by supporting the 'reset' command.
52
def invert_dictset(d):
53
    """Invert a dictionary with keys matching a set of values, turned into lists."""
54
    # Based on recipe from ASPN
55
    result = {}
56
    for k, c in d.iteritems():
57
        for v in c:
58
            keys = result.setdefault(v, [])
59
            keys.append(k)
60
    return result
0.77.8 by Ian Clatworthy
include subdir & multiple files tests
61
62
0.77.9 by Ian Clatworthy
common_directory tests & tweaks
63
def _common_path_and_rest(l1, l2, common=[]):
0.77.8 by Ian Clatworthy
include subdir & multiple files tests
64
    # From http://code.activestate.com/recipes/208993/
65
    if len(l1) < 1: return (common, l1, l2)
66
    if len(l2) < 1: return (common, l1, l2)
67
    if l1[0] != l2[0]: return (common, l1, l2)
0.77.9 by Ian Clatworthy
common_directory tests & tweaks
68
    return _common_path_and_rest(l1[1:], l2[1:], common+[l1[0]])
69
70
71
def common_path(path1, path2):
72
    """Find the common bit of 2 paths."""
73
    return ''.join(_common_path_and_rest(path1, path2)[0])
0.77.8 by Ian Clatworthy
include subdir & multiple files tests
74
75
76
def common_directory(paths):
77
    """Find the deepest common directory of a list of paths.
78
    
0.77.9 by Ian Clatworthy
common_directory tests & tweaks
79
    :return: if no paths are provided, None is returned;
80
      if there is no common directory, '' is returned;
81
      otherwise the common directory with a trailing / is returned.
0.77.8 by Ian Clatworthy
include subdir & multiple files tests
82
    """
83
    from bzrlib import osutils
84
    def get_dir_with_slash(path):
0.77.9 by Ian Clatworthy
common_directory tests & tweaks
85
        if path == '' or path.endswith('/'):
0.77.8 by Ian Clatworthy
include subdir & multiple files tests
86
            return path
87
        else:
88
            dirname, basename = osutils.split(path)
0.77.9 by Ian Clatworthy
common_directory tests & tweaks
89
            if dirname == '':
90
                return dirname
91
            else:
92
                return dirname + '/'
0.77.8 by Ian Clatworthy
include subdir & multiple files tests
93
94
    if not paths:
95
        return None
96
    elif len(paths) == 1:
97
        return get_dir_with_slash(paths[0])
98
    else:
0.77.9 by Ian Clatworthy
common_directory tests & tweaks
99
        common = common_path(paths[0], paths[1])
0.77.8 by Ian Clatworthy
include subdir & multiple files tests
100
        for path in paths[2:]:
101
            common = common_path(common, path)
0.77.9 by Ian Clatworthy
common_directory tests & tweaks
102
        return get_dir_with_slash(common)
0.78.2 by Ian Clatworthy
move escape_commit_message into helpers
103
104
105
def escape_commit_message(message):
106
    """Replace xml-incompatible control characters."""
107
    # This really ought to be provided by bzrlib.
108
    # Code copied from bzrlib.commit.
109
    
110
    # Python strings can include characters that can't be
111
    # represented in well-formed XML; escape characters that
112
    # aren't listed in the XML specification
113
    # (http://www.w3.org/TR/REC-xml/#NT-Char).
114
    import re
115
    message, _ = re.subn(
116
        u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
117
        lambda match: match.group(0).encode('unicode_escape'),
118
        message)
119
    return message
0.84.2 by Ian Clatworthy
make sure fast-export uses a binary stream on Windows
120
121
122
def binary_stream(stream):
123
    """Ensure a stream is binary on Windows.
124
125
    :return: the stream
126
    """
127
    try:
128
        import os
129
        if os.name == 'nt':
130
            fileno = getattr(stream, 'fileno', None)
131
            if fileno:
132
                no = fileno()
133
                if no >= 0:     # -1 means we're working as subprocess
134
                    import msvcrt
135
                    msvcrt.setmode(no, os.O_BINARY)
136
    except ImportError:
137
        pass
138
    return stream
0.64.193 by Ian Clatworthy
Smarter selection of branch format based on shared repository format
139
140
141
def best_format_for_objects_in_a_repository(repo):
142
    """Find the high-level format for branches and trees given a repository.
143
144
    When creating branches and working trees within a repository, Bazaar
145
    defaults to using the default format which may not be the best choice.
146
    This routine does a reverse lookup of the high-level format registry
147
    to find the high-level format that a shared repository was most likely
148
    created via.
149
150
    :return: the BzrDirFormat or None if no matches were found.
151
    """
152
    # Based on code from bzrlib/info.py ...
153
    from bzrlib import bzrdir
154
    repo_format = repo._format
155
    candidates  = []
156
    non_aliases = set(bzrdir.format_registry.keys())
157
    non_aliases.difference_update(bzrdir.format_registry.aliases())
158
    for key in non_aliases:
159
        format = bzrdir.format_registry.make_bzrdir(key)
160
        if format.repository_format == repo_format:
161
            candidates.append((key, format))
162
    if len(candidates):
163
        # Assume the first one. Is there any reason not to do that?
164
        name, format = candidates[0]
165
        return format
166
    else:
167
        return None
0.95.1 by Ian Clatworthy
Create a repository implicitly if one doesn't already exist
168
169
170
def open_destination_directory(location, format=None, verbose=True):
171
    """Open a destination directory and return the BzrDir.
172
173
    If destination has a control directory, it will be returned.
174
    Otherwise, the destination should be empty or non-existent and
175
    a shared repository will be created there.
176
177
    :param location: the destination directory
178
    :param format: the format to use or None for the default
179
    :param verbose: display the format used if a repository is created.
180
    :return: BzrDir for the destination
181
    """
182
    import os
0.64.213 by Ian Clatworthy
Smarter blob tracking by implicitly collecting statistics before starting the import
183
    from bzrlib import bzrdir, errors, trace, transport
0.95.1 by Ian Clatworthy
Create a repository implicitly if one doesn't already exist
184
    try:
185
        control, relpath = bzrdir.BzrDir.open_containing(location)
186
        # XXX: Check the relpath is None here?
187
        return control
188
    except errors.NotBranchError:
189
        pass
190
191
    # If the directory exists, check it is empty. Otherwise create it.
192
    if os.path.exists(location):
193
        contents = os.listdir(location)
194
        if contents:
195
            errors.BzrCommandError("Destination must have a .bzr directory, "
196
                " not yet exist or be empty - files found in %s" % (location,))
197
    else:
198
        try:
199
            os.mkdir(location)
200
        except IOError, ex:
201
            errors.BzrCommandError("Unable to create %s: %s" %
202
                (location, ex))
203
204
    # Create a repository for the nominated format.
0.64.213 by Ian Clatworthy
Smarter blob tracking by implicitly collecting statistics before starting the import
205
    trace.note("Creating destination repository ...")
0.95.1 by Ian Clatworthy
Create a repository implicitly if one doesn't already exist
206
    if format is None:
207
        format = bzrdir.format_registry.make_bzrdir('default')
208
    to_transport = transport.get_transport(location)
209
    to_transport.ensure_base()
210
    control = format.initialize_on_transport(to_transport)
211
    repo = control.create_repository(shared=True)
212
    if verbose:
213
        from bzrlib.info import show_bzrdir_info
214
        show_bzrdir_info(repo.bzrdir, verbose=0)
215
    return control