Split out reftracker.
[bzr-fastimport.git] / helpers.py
blob97ab6b3b099760a1a349f6b7fa9292902b281c4f
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, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 """Miscellaneous useful stuff."""
19 from fastimport.helpers import (
20 common_path,
24 def common_directory(paths):
25 """Find the deepest common directory of a list of paths.
27 :return: if no paths are provided, None is returned;
28 if there is no common directory, '' is returned;
29 otherwise the common directory with a trailing / is returned.
30 """
31 from bzrlib import osutils
32 def get_dir_with_slash(path):
33 if path == '' or path.endswith('/'):
34 return path
35 else:
36 dirname, basename = osutils.split(path)
37 if dirname == '':
38 return dirname
39 else:
40 return dirname + '/'
42 if not paths:
43 return None
44 elif len(paths) == 1:
45 return get_dir_with_slash(paths[0])
46 else:
47 common = common_path(paths[0], paths[1])
48 for path in paths[2:]:
49 common = common_path(common, path)
50 return get_dir_with_slash(common)
53 def escape_commit_message(message):
54 """Replace xml-incompatible control characters."""
55 # This really ought to be provided by bzrlib.
56 # Code copied from bzrlib.commit.
58 # Python strings can include characters that can't be
59 # represented in well-formed XML; escape characters that
60 # aren't listed in the XML specification
61 # (http://www.w3.org/TR/REC-xml/#NT-Char).
62 import re
63 message, _ = re.subn(
64 u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
65 lambda match: match.group(0).encode('unicode_escape'),
66 message)
67 return message
70 def best_format_for_objects_in_a_repository(repo):
71 """Find the high-level format for branches and trees given a repository.
73 When creating branches and working trees within a repository, Bazaar
74 defaults to using the default format which may not be the best choice.
75 This routine does a reverse lookup of the high-level format registry
76 to find the high-level format that a shared repository was most likely
77 created via.
79 :return: the BzrDirFormat or None if no matches were found.
80 """
81 # Based on code from bzrlib/info.py ...
82 from bzrlib import bzrdir
83 repo_format = repo._format
84 candidates = []
85 non_aliases = set(bzrdir.format_registry.keys())
86 non_aliases.difference_update(bzrdir.format_registry.aliases())
87 for key in non_aliases:
88 format = bzrdir.format_registry.make_bzrdir(key)
89 # LocalGitBzrDirFormat has no repository_format
90 if hasattr(format, "repository_format"):
91 if format.repository_format == repo_format:
92 candidates.append((key, format))
93 if len(candidates):
94 # Assume the first one. Is there any reason not to do that?
95 name, format = candidates[0]
96 return format
97 else:
98 return None
101 def open_destination_directory(location, format=None, verbose=True):
102 """Open a destination directory and return the BzrDir.
104 If destination has a control directory, it will be returned.
105 Otherwise, the destination should be empty or non-existent and
106 a shared repository will be created there.
108 :param location: the destination directory
109 :param format: the format to use or None for the default
110 :param verbose: display the format used if a repository is created.
111 :return: BzrDir for the destination
113 import os
114 from bzrlib import bzrdir, errors, trace, transport
115 try:
116 control, relpath = bzrdir.BzrDir.open_containing(location)
117 # XXX: Check the relpath is None here?
118 return control
119 except errors.NotBranchError:
120 pass
122 # If the directory exists, check it is empty. Otherwise create it.
123 if os.path.exists(location):
124 contents = os.listdir(location)
125 if contents:
126 errors.BzrCommandError("Destination must have a .bzr directory, "
127 " not yet exist or be empty - files found in %s" % (location,))
128 else:
129 try:
130 os.mkdir(location)
131 except IOError, ex:
132 errors.BzrCommandError("Unable to create %s: %s" %
133 (location, ex))
135 # Create a repository for the nominated format.
136 trace.note("Creating destination repository ...")
137 if format is None:
138 format = bzrdir.format_registry.make_bzrdir('default')
139 to_transport = transport.get_transport(location)
140 to_transport.ensure_base()
141 control = format.initialize_on_transport(to_transport)
142 repo = control.create_repository(shared=True)
143 if verbose:
144 from bzrlib.info import show_bzrdir_info
145 show_bzrdir_info(repo.bzrdir, verbose=0)
146 return control