264
252
return _win32_fixdrive(_nt_abspath(unicode(path)).replace('\\', '/'))
267
def _win98_abspath(path):
268
"""Return the absolute version of a path.
269
Windows 98 safe implementation (python reimplementation
270
of Win32 API function GetFullPathNameW)
275
# \\HOST\path => //HOST/path
276
# //HOST/path => //HOST/path
277
# path => C:/cwd/path
280
# check for absolute path
281
drive = _nt_splitdrive(path)[0]
282
if drive == '' and path[:2] not in('//','\\\\'):
284
# we cannot simply os.path.join cwd and path
285
# because os.path.join('C:','/path') produce '/path'
286
# and this is incorrect
287
if path[:1] in ('/','\\'):
288
cwd = _nt_splitdrive(cwd)[0]
290
path = cwd + '\\' + path
291
return _win32_fixdrive(_nt_normpath(path).replace('\\', '/'))
293
if win32utils.winver == 'Windows 98':
294
_win32_abspath = _win98_abspath
297
255
def _win32_realpath(path):
298
256
# Real _nt_realpath doesn't have a problem with a unicode cwd
299
257
return _win32_fixdrive(_nt_realpath(unicode(path)).replace('\\', '/'))
638
596
return time.strftime('%Y%m%d%H%M%S', time.gmtime(when))
641
def format_delta(delta):
642
"""Get a nice looking string for a time delta.
644
:param delta: The time difference in seconds, can be positive or negative.
645
positive indicates time in the past, negative indicates time in the
646
future. (usually time.time() - stored_time)
647
:return: String formatted to show approximate resolution
653
direction = 'in the future'
657
if seconds < 90: # print seconds up to 90 seconds
659
return '%d second %s' % (seconds, direction,)
661
return '%d seconds %s' % (seconds, direction)
663
minutes = int(seconds / 60)
664
seconds -= 60 * minutes
669
if minutes < 90: # print minutes, seconds up to 90 minutes
671
return '%d minute, %d second%s %s' % (
672
minutes, seconds, plural_seconds, direction)
674
return '%d minutes, %d second%s %s' % (
675
minutes, seconds, plural_seconds, direction)
677
hours = int(minutes / 60)
678
minutes -= 60 * hours
685
return '%d hour, %d minute%s %s' % (hours, minutes,
686
plural_minutes, direction)
687
return '%d hours, %d minute%s %s' % (hours, minutes,
688
plural_minutes, direction)
691
601
"""Return size of given open file."""
885
798
return unicode_or_utf8_string.decode('utf8')
886
799
except UnicodeDecodeError:
887
raise errors.BzrBadParameterNotUnicode(unicode_or_utf8_string)
890
def safe_utf8(unicode_or_utf8_string):
891
"""Coerce unicode_or_utf8_string to a utf8 string.
893
If it is a str, it is returned.
894
If it is Unicode, it is encoded into a utf-8 string.
896
if isinstance(unicode_or_utf8_string, str):
897
# TODO: jam 20070209 This is overkill, and probably has an impact on
898
# performance if we are dealing with lots of apis that want a
901
# Make sure it is a valid utf-8 string
902
unicode_or_utf8_string.decode('utf-8')
903
except UnicodeDecodeError:
904
raise errors.BzrBadParameterNotUnicode(unicode_or_utf8_string)
905
return unicode_or_utf8_string
906
return unicode_or_utf8_string.encode('utf-8')
909
_revision_id_warning = ('Unicode revision ids were deprecated in bzr 0.15.'
910
' Revision id generators should be creating utf8'
914
def safe_revision_id(unicode_or_utf8_string, warn=True):
915
"""Revision ids should now be utf8, but at one point they were unicode.
917
:param unicode_or_utf8_string: A possibly Unicode revision_id. (can also be
919
:param warn: Functions that are sanitizing user data can set warn=False
920
:return: None or a utf8 revision id.
922
if (unicode_or_utf8_string is None
923
or unicode_or_utf8_string.__class__ == str):
924
return unicode_or_utf8_string
926
symbol_versioning.warn(_revision_id_warning, DeprecationWarning,
928
return cache_utf8.encode(unicode_or_utf8_string)
931
_file_id_warning = ('Unicode file ids were deprecated in bzr 0.15. File id'
932
' generators should be creating utf8 file ids.')
935
def safe_file_id(unicode_or_utf8_string, warn=True):
936
"""File ids should now be utf8, but at one point they were unicode.
938
This is the same as safe_utf8, except it uses the cached encode functions
939
to save a little bit of performance.
941
:param unicode_or_utf8_string: A possibly Unicode file_id. (can also be
943
:param warn: Functions that are sanitizing user data can set warn=False
944
:return: None or a utf8 file id.
946
if (unicode_or_utf8_string is None
947
or unicode_or_utf8_string.__class__ == str):
948
return unicode_or_utf8_string
950
symbol_versioning.warn(_file_id_warning, DeprecationWarning,
952
return cache_utf8.encode(unicode_or_utf8_string)
800
raise BzrBadParameterNotUnicode(unicode_or_utf8_string)
955
803
_platform_normalizes_filenames = False
1102
938
# depending on top and prefix - i.e. ./foo and foo as a pair leads to
1103
939
# potentially confusing output. We should make this more robust - but
1104
940
# not at a speed cost. RBC 20060731
1106
943
_directory = _directory_kind
1107
_listdir = os.listdir
1108
_kind_from_mode = _formats.get
1109
pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
945
pending = [(prefix, "", _directory, None, top)]
948
currentdir = pending.pop()
1111
949
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1112
relroot, _, _, _, top = pending.pop()
1114
relprefix = relroot + u'/'
1117
top_slash = top + u'/'
1120
append = dirblock.append
1121
for name in sorted(_listdir(top)):
1122
abspath = top_slash + name
1123
statvalue = _lstat(abspath)
1124
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1125
append((relprefix + name, name, kind, statvalue, abspath))
1126
yield (relroot, top), dirblock
1128
# push the user specified dirs from dirblock
1129
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1132
def _walkdirs_utf8(top, prefix=""):
1133
"""Yield data about all the directories in a tree.
1135
This yields the same information as walkdirs() only each entry is yielded
1136
in utf-8. On platforms which have a filesystem encoding of utf8 the paths
1137
are returned as exact byte-strings.
1139
:return: yields a tuple of (dir_info, [file_info])
1140
dir_info is (utf8_relpath, path-from-top)
1141
file_info is (utf8_relpath, utf8_name, kind, lstat, path-from-top)
1142
if top is an absolute path, path-from-top is also an absolute path.
1143
path-from-top might be unicode or utf8, but it is the correct path to
1144
pass to os functions to affect the file in question. (such as os.lstat)
1146
fs_encoding = sys.getfilesystemencoding()
1147
if (sys.platform == 'win32' or
1148
fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968')): # ascii
1149
return _walkdirs_unicode_to_utf8(top, prefix=prefix)
1151
return _walkdirs_fs_utf8(top, prefix=prefix)
1154
def _walkdirs_fs_utf8(top, prefix=""):
1155
"""See _walkdirs_utf8.
1157
This sub-function is called when we know the filesystem is already in utf8
1158
encoding. So we don't need to transcode filenames.
1161
_directory = _directory_kind
1162
_listdir = os.listdir
1163
_kind_from_mode = _formats.get
1165
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1166
# But we don't actually uses 1-3 in pending, so set them to None
1167
pending = [(safe_utf8(prefix), None, None, None, safe_utf8(top))]
1169
relroot, _, _, _, top = pending.pop()
1171
relprefix = relroot + '/'
1174
top_slash = top + '/'
1177
append = dirblock.append
1178
for name in sorted(_listdir(top)):
1179
abspath = top_slash + name
1180
statvalue = _lstat(abspath)
1181
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1182
append((relprefix + name, name, kind, statvalue, abspath))
1183
yield (relroot, top), dirblock
1185
# push the user specified dirs from dirblock
1186
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1189
def _walkdirs_unicode_to_utf8(top, prefix=""):
1190
"""See _walkdirs_utf8
1192
Because Win32 has a Unicode api, all of the 'path-from-top' entries will be
1194
This is currently the fallback code path when the filesystem encoding is
1195
not UTF-8. It may be better to implement an alternative so that we can
1196
safely handle paths that are not properly decodable in the current
1199
_utf8_encode = codecs.getencoder('utf8')
1201
_directory = _directory_kind
1202
_listdir = os.listdir
1203
_kind_from_mode = _formats.get
1205
pending = [(safe_utf8(prefix), None, None, None, safe_unicode(top))]
1207
relroot, _, _, _, top = pending.pop()
1209
relprefix = relroot + '/'
1212
top_slash = top + u'/'
1215
append = dirblock.append
1216
for name in sorted(_listdir(top)):
1217
name_utf8 = _utf8_encode(name)[0]
1218
abspath = top_slash + name
1219
statvalue = _lstat(abspath)
1220
kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
1221
append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1222
yield (relroot, top), dirblock
1224
# push the user specified dirs from dirblock
1225
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
952
relroot = currentdir[0] + '/'
955
for name in sorted(_listdir(top)):
956
abspath = top + '/' + name
957
statvalue = lstat(abspath)
958
dirblock.append((relroot + name, name,
959
file_kind_from_stat_mode(statvalue.st_mode),
961
yield (currentdir[0], top), dirblock
962
# push the user specified dirs from dirblock
963
for dir in reversed(dirblock):
964
if dir[2] == _directory:
1228
968
def copy_tree(from_path, to_path, handlers={}):
1321
1057
' doesn\'t support the locale set by $LANG (%s)\n'
1322
1058
" Continuing with ascii encoding.\n"
1323
1059
% (e, os.environ.get('LANG')))
1324
user_encoding = 'ascii'
1326
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1327
# treat that as ASCII, and not support printing unicode characters to the
1329
if user_encoding in (None, 'cp0'):
1330
user_encoding = 'ascii'
1334
codecs.lookup(user_encoding)
1336
sys.stderr.write('bzr: warning:'
1337
' unknown encoding %s.'
1338
' Continuing with ascii encoding.\n'
1341
user_encoding = 'ascii'
1344
_cached_user_encoding = user_encoding
1346
return user_encoding
1349
def recv_all(socket, bytes):
1350
"""Receive an exact number of bytes.
1352
Regular Socket.recv() may return less than the requested number of bytes,
1353
dependning on what's in the OS buffer. MSG_WAITALL is not available
1354
on all platforms, but this should work everywhere. This will return
1355
less than the requested amount if the remote end closes.
1357
This isn't optimized and is intended mostly for use in testing.
1360
while len(b) < bytes:
1361
new = socket.recv(bytes - len(b))
1367
def dereference_path(path):
1368
"""Determine the real path to a file.
1370
All parent elements are dereferenced. But the file itself is not
1372
:param path: The original path. May be absolute or relative.
1373
:return: the real path *to* the file
1375
parent, base = os.path.split(path)
1376
# The pathjoin for '.' is a workaround for Python bug #1213894.
1377
# (initial path components aren't dereferenced)
1378
return pathjoin(realpath(pathjoin('.', parent)), base)
1061
if _cached_user_encoding is None:
1062
_cached_user_encoding = 'ascii'
1063
return _cached_user_encoding