comparison hgext3rd/fastimport/vendor/python_fastimport/helpers.py @ 86:28704a2a7461 vendor/python-fastimport

Import python-fastimport-0.9.8
author Roy Marples <roy@marples.name>
date Tue, 19 Jan 2021 22:56:34 +0000
parents
children
comparison
equal deleted inserted replaced
85:1f5544a8870b 86:28704a2a7461
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 import sys
18
19
20 def _common_path_and_rest(l1, l2, common=[]):
21 # From http://code.activestate.com/recipes/208993/
22 if len(l1) < 1: return (common, l1, l2)
23 if len(l2) < 1: return (common, l1, l2)
24 if l1[0] != l2[0]: return (common, l1, l2)
25 return _common_path_and_rest(
26 l1[1:],
27 l2[1:],
28 common + [
29 l1[0:1] # return a byte string in python 3 unlike l1[0] that
30 # would return an integer.
31 ]
32 )
33
34
35 def common_path(path1, path2):
36 """Find the common bit of 2 paths."""
37 return b''.join(_common_path_and_rest(path1, path2)[0])
38
39
40 def common_directory(paths):
41 """Find the deepest common directory of a list of paths.
42
43 :return: if no paths are provided, None is returned;
44 if there is no common directory, '' is returned;
45 otherwise the common directory with a trailing / is returned.
46 """
47 import posixpath
48 def get_dir_with_slash(path):
49 if path == b'' or path.endswith(b'/'):
50 return path
51 else:
52 dirname, basename = posixpath.split(path)
53 if dirname == b'':
54 return dirname
55 else:
56 return dirname + b'/'
57
58 if not paths:
59 return None
60 elif len(paths) == 1:
61 return get_dir_with_slash(paths[0])
62 else:
63 common = common_path(paths[0], paths[1])
64 for path in paths[2:]:
65 common = common_path(common, path)
66 return get_dir_with_slash(common)
67
68
69 def is_inside(directory, fname):
70 """True if fname is inside directory.
71
72 The parameters should typically be passed to osutils.normpath first, so
73 that . and .. and repeated slashes are eliminated, and the separators
74 are canonical for the platform.
75
76 The empty string as a dir name is taken as top-of-tree and matches
77 everything.
78 """
79 # XXX: Most callers of this can actually do something smarter by
80 # looking at the inventory
81 if directory == fname:
82 return True
83
84 if directory == b'':
85 return True
86
87 if not directory.endswith(b'/'):
88 directory += b'/'
89
90 return fname.startswith(directory)
91
92
93 def is_inside_any(dir_list, fname):
94 """True if fname is inside any of given dirs."""
95 for dirname in dir_list:
96 if is_inside(dirname, fname):
97 return True
98 return False
99
100
101 def utf8_bytes_string(s):
102 """Convert a string to a bytes string (if necessary, encode in utf8)"""
103 if sys.version_info[0] == 2:
104 if isinstance(s, str):
105 return s
106 else:
107 return s.encode('utf8')
108 else:
109 if isinstance(s, str):
110 return bytes(s, encoding='utf8')
111 else:
112 return s
113
114
115 def repr_bytes(obj):
116 """Return a bytes representation of the object"""
117 if sys.version_info[0] == 2:
118 return repr(obj)
119 else:
120 return bytes(obj)
121
122
123 class newobject(object):
124 """
125 A magical object class that provides Python 2 compatibility methods::
126 next
127 __unicode__
128 __nonzero__
129
130 Subclasses of this class can merely define the Python 3 methods (__next__,
131 __str__, and __bool__).
132
133 This is a copy/paste of the future.types.newobject class of the future
134 package.
135 """
136 def next(self):
137 if hasattr(self, '__next__'):
138 return type(self).__next__(self)
139 raise TypeError('newobject is not an iterator')
140
141 def __unicode__(self):
142 # All subclasses of the builtin object should have __str__ defined.
143 # Note that old-style classes do not have __str__ defined.
144 if hasattr(self, '__str__'):
145 s = type(self).__str__(self)
146 else:
147 s = str(self)
148 if isinstance(s, unicode):
149 return s
150 else:
151 return s.decode('utf-8')
152
153 def __nonzero__(self):
154 if hasattr(self, '__bool__'):
155 return type(self).__bool__(self)
156 # object has no __nonzero__ method
157 return True
158
159 # Are these ever needed?
160 # def __div__(self):
161 # return self.__truediv__()
162
163 # def __idiv__(self, other):
164 # return self.__itruediv__(other)
165
166 def __long__(self):
167 if not hasattr(self, '__int__'):
168 return NotImplemented
169 return self.__int__() # not type(self).__int__(self)
170
171 # def __new__(cls, *args, **kwargs):
172 # """
173 # dict() -> new empty dictionary
174 # dict(mapping) -> new dictionary initialized from a mapping object's
175 # (key, value) pairs
176 # dict(iterable) -> new dictionary initialized as if via:
177 # d = {}
178 # for k, v in iterable:
179 # d[k] = v
180 # dict(**kwargs) -> new dictionary initialized with the name=value pairs
181 # in the keyword argument list. For example: dict(one=1, two=2)
182 # """
183
184 # if len(args) == 0:
185 # return super(newdict, cls).__new__(cls)
186 # elif type(args[0]) == newdict:
187 # return args[0]
188 # else:
189 # value = args[0]
190 # return super(newdict, cls).__new__(cls, value)
191
192 def __native__(self):
193 """
194 Hook for the future.utils.native() function
195 """
196 return object(self)
197
198
199 def binary_stream(stream):
200 """Ensure a stream is binary on Windows.
201
202 :return: the stream
203 """
204 try:
205 import os
206 if os.name == 'nt':
207 fileno = getattr(stream, 'fileno', None)
208 if fileno:
209 no = fileno()
210 if no >= 0: # -1 means we're working as subprocess
211 import msvcrt
212 msvcrt.setmode(no, os.O_BINARY)
213 except ImportError:
214 pass
215 return stream
216
217
218 def invert_dictset(d):
219 """Invert a dictionary with keys matching a set of values, turned into lists."""
220 # Based on recipe from ASPN
221 result = {}
222 for k, c in d.items():
223 for v in c:
224 keys = result.setdefault(v, [])
225 keys.append(k)
226 return result
227
228
229 def invert_dict(d):
230 """Invert a dictionary with keys matching each value turned into a list."""
231 # Based on recipe from ASPN
232 result = {}
233 for k, v in d.items():
234 keys = result.setdefault(v, [])
235 keys.append(k)
236 return result
237
238
239 def defines_to_dict(defines):
240 """Convert a list of definition strings to a dictionary."""
241 if defines is None:
242 return None
243 result = {}
244 for define in defines:
245 kv = define.split('=', 1)
246 if len(kv) == 1:
247 result[define.strip()] = 1
248 else:
249 result[kv[0].strip()] = kv[1].strip()
250 return result
251
252
253 def get_source_stream(source):
254 if source == '-' or source is None:
255 import sys
256 stream = binary_stream(sys.stdin)
257 elif source.endswith('.gz'):
258 import gzip
259 stream = gzip.open(source, "rb")
260 else:
261 stream = open(source, "rb")
262 return stream
263
264
265