1
# Copyright (C) 2008 Canonical Ltd
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.
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.
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/>.
16
"""Miscellaneous useful stuff."""
18
from __future__ import absolute_import
23
def escape_commit_message(message):
24
"""Replace xml-incompatible control characters."""
25
# This really ought to be provided by breezy.
26
# Code copied from breezy.commit.
28
# Python strings can include characters that can't be
29
# represented in well-formed XML; escape characters that
30
# aren't listed in the XML specification
31
# (http://www.w3.org/TR/REC-xml/#NT-Char).
34
u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
35
lambda match: match.group(0).encode('unicode_escape'),
40
def best_format_for_objects_in_a_repository(repo):
41
"""Find the high-level format for branches and trees given a repository.
43
When creating branches and working trees within a repository, Bazaar
44
defaults to using the default format which may not be the best choice.
45
This routine does a reverse lookup of the high-level format registry
46
to find the high-level format that a shared repository was most likely
49
:return: the BzrDirFormat or None if no matches were found.
51
# Based on code from breezy/info.py ...
52
from ... import bzrdir
53
repo_format = repo._format
55
non_aliases = set(bzrdir.format_registry.keys())
56
non_aliases.difference_update(bzrdir.format_registry.aliases())
57
for key in non_aliases:
58
format = bzrdir.format_registry.make_bzrdir(key)
59
# LocalGitBzrDirFormat has no repository_format
60
if hasattr(format, "repository_format"):
61
if format.repository_format == repo_format:
62
candidates.append((key, format))
64
# Assume the first one. Is there any reason not to do that?
65
name, format = candidates[0]
71
def open_destination_directory(location, format=None, verbose=True):
72
"""Open a destination directory and return the BzrDir.
74
If destination has a control directory, it will be returned.
75
Otherwise, the destination should be empty or non-existent and
76
a shared repository will be created there.
78
:param location: the destination directory
79
:param format: the format to use or None for the default
80
:param verbose: display the format used if a repository is created.
81
:return: BzrDir for the destination
84
from ... import bzrdir, errors, trace, transport
86
control, relpath = bzrdir.BzrDir.open_containing(location)
87
# XXX: Check the relpath is None here?
89
except errors.NotBranchError:
92
# If the directory exists, check it is empty. Otherwise create it.
93
if os.path.exists(location):
94
contents = os.listdir(location)
96
errors.BzrCommandError("Destination must have a .bzr directory, "
97
" not yet exist or be empty - files found in %s" % (location,))
102
errors.BzrCommandError("Unable to create %s: %s" %
105
# Create a repository for the nominated format.
106
trace.note("Creating destination repository ...")
108
format = bzrdir.format_registry.make_bzrdir('default')
109
to_transport = transport.get_transport(location)
110
to_transport.ensure_base()
111
control = format.initialize_on_transport(to_transport)
112
repo = control.create_repository(shared=True)
114
from ...info import show_bzrdir_info
115
show_bzrdir_info(repo.bzrdir, verbose=0)
119
def kind_to_mode(kind, executable):
121
if executable == True:
122
return stat.S_IFREG | 0755
123
elif executable == False:
124
return stat.S_IFREG | 0644
126
raise AssertionError("Executable %r invalid" % executable)
127
elif kind == "symlink":
129
elif kind == "directory":
131
elif kind == "tree-reference":
134
raise AssertionError("Unknown file kind '%s'" % kind)
137
def mode_to_kind(mode):
138
# Note: Output from git-fast-export slightly different to spec
139
if mode in (0644, 0100644):
141
elif mode in (0755, 0100755):
143
elif mode == 0040000:
144
return 'directory', False
145
elif mode == 0120000:
146
return 'symlink', False
147
elif mode == 0160000:
148
return 'tree-reference', False
150
raise AssertionError("invalid mode %o" % mode)
153
def binary_stream(stream):
154
"""Ensure a stream is binary on Windows.
161
fileno = getattr(stream, 'fileno', None)
164
if no >= 0: # -1 means we're working as subprocess
166
msvcrt.setmode(no, os.O_BINARY)
172
def single_plural(n, single, plural):
173
"""Return a single or plural form of a noun based on number."""
180
def invert_dictset(d):
181
"""Invert a dictionary with keys matching a set of values, turned into lists."""
182
# Based on recipe from ASPN
184
for k, c in d.iteritems():
186
keys = result.setdefault(v, [])
192
"""Invert a dictionary with keys matching each value turned into a list."""
193
# Based on recipe from ASPN
195
for k, v in d.iteritems():
196
keys = result.setdefault(v, [])