21
21
S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
25
26
from bzrlib.lazy_import import lazy_import
26
27
lazy_import(globals(), """
234
236
# source and target may be aliases of each other (e.g. on a
235
237
# case-insensitive filesystem), so we may have accidentally renamed
236
238
# source by when we tried to rename target
237
if not (file_existed and e.errno in (None, errno.ENOENT)):
239
failure_exc = sys.exc_info()
240
if (file_existed and e.errno in (None, errno.ENOENT)
241
and old.lower() == new.lower()):
242
# source and target are the same file on a case-insensitive
243
# filesystem, so we don't generate an exception
241
247
# If the file used to exist, rename it back into place
244
250
unlink_func(tmp_name)
246
252
rename_func(tmp_name, new)
253
if failure_exc is not None:
254
raise failure_exc[0], failure_exc[1], failure_exc[2]
249
257
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
687
695
return offset.days * 86400 + offset.seconds
689
697
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
698
_default_format_by_weekday_num = [wd + " %Y-%m-%d %H:%M:%S" for wd in weekdays]
691
701
def format_date(t, offset=0, timezone='original', date_fmt=None,
692
702
show_offset=True):
706
716
date_str = time.strftime(date_fmt, tt)
707
717
return date_str + offset_str
720
# Cache of formatted offset strings
724
def format_date_with_offset_in_original_timezone(t, offset=0,
725
_cache=_offset_cache):
726
"""Return a formatted date string in the original timezone.
728
This routine may be faster then format_date.
730
:param t: Seconds since the epoch.
731
:param offset: Timezone offset in seconds east of utc.
735
tt = time.gmtime(t + offset)
736
date_fmt = _default_format_by_weekday_num[tt[6]]
737
date_str = time.strftime(date_fmt, tt)
738
offset_str = _cache.get(offset, None)
739
if offset_str is None:
740
offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
741
_cache[offset] = offset_str
742
return date_str + offset_str
709
745
def format_local_date(t, offset=0, timezone='original', date_fmt=None,
710
746
show_offset=True):
711
747
"""Return an unicode date string formatted according to the current locale.
725
761
date_str = date_str.decode(get_user_encoding(), 'replace')
726
762
return date_str + offset_str
728
765
def _format_date(t, offset, timezone, date_fmt, show_offset):
729
766
if timezone == 'utc':
730
767
tt = time.gmtime(t)
921
_extension_load_failures = []
924
def failed_to_load_extension(exception):
925
"""Handle failing to load a binary extension.
927
This should be called from the ImportError block guarding the attempt to
928
import the native extension. If this function returns, the pure-Python
929
implementation should be loaded instead::
932
>>> import bzrlib._fictional_extension_pyx
933
>>> except ImportError, e:
934
>>> bzrlib.osutils.failed_to_load_extension(e)
935
>>> import bzrlib._fictional_extension_py
937
# NB: This docstring is just an example, not a doctest, because doctest
938
# currently can't cope with the use of lazy imports in this namespace --
941
# This currently doesn't report the failure at the time it occurs, because
942
# they tend to happen very early in startup when we can't check config
943
# files etc, and also we want to report all failures but not spam the user
945
from bzrlib import trace
946
exception_str = str(exception)
947
if exception_str not in _extension_load_failures:
948
trace.mutter("failed to load compiled extension: %s" % exception_str)
949
_extension_load_failures.append(exception_str)
952
def report_extension_load_failures():
953
if not _extension_load_failures:
955
from bzrlib.config import GlobalConfig
956
if GlobalConfig().get_user_option_as_bool('ignore_missing_extensions'):
958
# the warnings framework should by default show this only once
959
from bzrlib.trace import warning
961
"bzr: warning: some compiled extensions could not be loaded; "
962
"see <https://answers.launchpad.net/bzr/+faq/703>")
963
# we no longer show the specific missing extensions here, because it makes
964
# the message too long and scary - see
965
# https://bugs.launchpad.net/bzr/+bug/430529
885
969
from bzrlib._chunks_to_lines_pyx import chunks_to_lines
970
except ImportError, e:
971
failed_to_load_extension(e)
887
972
from bzrlib._chunks_to_lines_py import chunks_to_lines
1043
while len(head) >= len(base):
1129
if len(head) <= len(base) and head != base:
1130
raise errors.PathNotChild(rp, base)
1044
1131
if head == base:
1046
head, tail = os.path.split(head)
1133
head, tail = split(head)
1050
raise errors.PathNotChild(rp, base)
1138
return pathjoin(*reversed(s))
1083
1168
bit_iter = iter(rel.split('/'))
1084
1169
for bit in bit_iter:
1085
1170
lbit = bit.lower()
1086
for look in _listdir(current):
1172
next_entries = _listdir(current)
1173
except OSError: # enoent, eperm, etc
1174
# We can't find this in the filesystem, so just append the
1176
current = pathjoin(current, bit, *list(bit_iter))
1178
for look in next_entries:
1087
1179
if lbit == look.lower():
1088
1180
current = pathjoin(current, look)
1093
1185
# the target of a move, for example).
1094
1186
current = pathjoin(current, bit, *list(bit_iter))
1096
return current[len(abs_base)+1:]
1188
return current[len(abs_base):].lstrip('/')
1098
1190
# XXX - TODO - we need better detection/integration of case-insensitive
1099
1191
# file-systems; Linux often sees FAT32 devices (or NFS-mounted OSX
1238
1330
normalized_filename = _inaccessible_normalized_filename
1333
default_terminal_width = 80
1334
"""The default terminal width for ttys.
1336
This is defined so that higher levels can share a common fallback value when
1337
terminal_width() returns None.
1241
1341
def terminal_width():
1242
"""Return estimated terminal width."""
1342
"""Return terminal width.
1344
None is returned if the width can't established precisely.
1347
# If BZR_COLUMNS is set, take it, user is always right
1349
return int(os.environ['BZR_COLUMNS'])
1350
except (KeyError, ValueError):
1353
isatty = getattr(sys.stdout, 'isatty', None)
1354
if isatty is None or not isatty():
1355
# Don't guess, setting BZR_COLUMNS is the recommended way to override.
1243
1358
if sys.platform == 'win32':
1244
return win32utils.get_console_size()[0]
1359
return win32utils.get_console_size(defaultx=None)[0]
1247
1362
import struct, fcntl, termios
1248
1363
s = struct.pack('HHHH', 0, 0, 0, 0)
1249
1364
x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
1250
1365
width = struct.unpack('HHHH', x)[1]
1366
except (IOError, AttributeError):
1367
# If COLUMNS is set, take it
1255
width = int(os.environ['COLUMNS'])
1369
return int(os.environ['COLUMNS'])
1370
except (KeyError, ValueError):
1374
# Consider invalid values as meaning no width
1779
1896
from bzrlib._readdir_pyx import UTF8DirReader
1780
1897
file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1898
except ImportError, e:
1899
# This is one time where we won't warn that an extension failed to
1900
# load. The extension is never available on Windows anyway.
1782
1901
from bzrlib._readdir_py import (
1783
1902
_kind_from_mode as file_kind_from_stat_mode
1886
2005
anything goes wrong.
1888
2007
global _cached_local_concurrency
1889
2009
if _cached_local_concurrency is not None and use_cache:
1890
2010
return _cached_local_concurrency
1893
concurrency = _local_concurrency()
1894
except (OSError, IOError):
2012
concurrency = os.environ.get('BZR_CONCURRENCY', None)
2013
if concurrency is None:
2015
concurrency = _local_concurrency()
2016
except (OSError, IOError):
1897
2019
concurrency = int(concurrency)
1898
2020
except (TypeError, ValueError):