474
634
def local_time_offset(t=None):
475
635
"""Return offset of local zone from GMT, either at present or at time t."""
476
# python2.3 localtime() can't take None
480
if time.localtime(t).tm_isdst and time.daylight:
483
return -time.timezone
638
offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
639
return offset.days * 86400 + offset.seconds
641
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
486
def format_date(t, offset=0, timezone='original', date_fmt=None,
643
def format_date(t, offset=0, timezone='original', date_fmt=None,
487
644
show_offset=True):
488
## TODO: Perhaps a global option to use either universal or local time?
489
## Or perhaps just let people set $TZ?
490
assert isinstance(t, float)
645
"""Return a formatted date string.
647
:param t: Seconds since the epoch.
648
:param offset: Timezone offset in seconds east of utc.
649
:param timezone: How to display the time: 'utc', 'original' for the
650
timezone specified by offset, or 'local' for the process's current
652
:param date_fmt: strftime format.
653
:param show_offset: Whether to append the timezone.
655
(date_fmt, tt, offset_str) = \
656
_format_date(t, offset, timezone, date_fmt, show_offset)
657
date_fmt = date_fmt.replace('%a', weekdays[tt[6]])
658
date_str = time.strftime(date_fmt, tt)
659
return date_str + offset_str
661
def format_local_date(t, offset=0, timezone='original', date_fmt=None,
663
"""Return an unicode date string formatted according to the current locale.
665
:param t: Seconds since the epoch.
666
:param offset: Timezone offset in seconds east of utc.
667
:param timezone: How to display the time: 'utc', 'original' for the
668
timezone specified by offset, or 'local' for the process's current
670
:param date_fmt: strftime format.
671
:param show_offset: Whether to append the timezone.
673
(date_fmt, tt, offset_str) = \
674
_format_date(t, offset, timezone, date_fmt, show_offset)
675
date_str = time.strftime(date_fmt, tt)
676
if not isinstance(date_str, unicode):
677
date_str = date_str.decode(bzrlib.user_encoding, 'replace')
678
return date_str + offset_str
680
def _format_date(t, offset, timezone, date_fmt, show_offset):
492
681
if timezone == 'utc':
493
682
tt = time.gmtime(t)
495
684
elif timezone == 'original':
498
687
tt = time.gmtime(t + offset)
499
688
elif timezone == 'local':
500
689
tt = time.localtime(t)
501
690
offset = local_time_offset(t)
503
raise BzrError("unsupported timezone format %r" % timezone,
504
['options are "utc", "original", "local"'])
692
raise errors.UnsupportedTimezoneFormat(timezone)
505
693
if date_fmt is None:
506
694
date_fmt = "%a %Y-%m-%d %H:%M:%S"
508
696
offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
511
return (time.strftime(date_fmt, tt) + offset_str)
699
return (date_fmt, tt, offset_str)
514
702
def compact_date(when):
515
703
return time.strftime('%Y%m%d%H%M%S', time.gmtime(when))
706
def format_delta(delta):
707
"""Get a nice looking string for a time delta.
709
:param delta: The time difference in seconds, can be positive or negative.
710
positive indicates time in the past, negative indicates time in the
711
future. (usually time.time() - stored_time)
712
:return: String formatted to show approximate resolution
718
direction = 'in the future'
722
if seconds < 90: # print seconds up to 90 seconds
724
return '%d second %s' % (seconds, direction,)
726
return '%d seconds %s' % (seconds, direction)
728
minutes = int(seconds / 60)
729
seconds -= 60 * minutes
734
if minutes < 90: # print minutes, seconds up to 90 minutes
736
return '%d minute, %d second%s %s' % (
737
minutes, seconds, plural_seconds, direction)
739
return '%d minutes, %d second%s %s' % (
740
minutes, seconds, plural_seconds, direction)
742
hours = int(minutes / 60)
743
minutes -= 60 * hours
750
return '%d hour, %d minute%s %s' % (hours, minutes,
751
plural_minutes, direction)
752
return '%d hours, %d minute%s %s' % (hours, minutes,
753
plural_minutes, direction)
520
756
"""Return size of given open file."""
816
1254
to exclude some directories, they are then not descended into.
818
1256
The data yielded is of the form:
819
[(relpath, basename, kind, lstat, path_from_top), ...]
1257
((directory-relpath, directory-path-from-top),
1258
[(relpath, basename, kind, lstat, path-from-top), ...]),
1259
- directory-relpath is the relative path of the directory being returned
1260
with respect to top. prefix is prepended to this.
1261
- directory-path-from-root is the path including top for this directory.
1262
It is suitable for use with os functions.
1263
- relpath is the relative path within the subtree being walked.
1264
- basename is the basename of the path
1265
- kind is the kind of the file now. If unknown then the file is not
1266
present within the tree - but it may be recorded as versioned. See
1268
- lstat is the stat data *if* the file was statted.
1269
- planned, not implemented:
1270
path_from_tree_root is the path from the root of the tree.
821
1272
:param prefix: Prefix the relpaths that are yielded with 'prefix'. This
822
1273
allows one to walk a subtree but get paths that are relative to a tree
823
1274
rooted higher up.
824
1275
:return: an iterator over the dirs.
1277
#TODO there is a bit of a smell where the results of the directory-
1278
# summary in this, and the path from the root, may not agree
1279
# depending on top and prefix - i.e. ./foo and foo as a pair leads to
1280
# potentially confusing output. We should make this more robust - but
1281
# not at a speed cost. RBC 20060731
828
1283
_directory = _directory_kind
830
pending = [(prefix, "", _directory, None, top)]
1284
_listdir = os.listdir
1285
_kind_from_mode = file_kind_from_stat_mode
1286
pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
833
currentdir = pending.pop()
834
1288
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
837
relroot = currentdir[0] + '/'
1289
relroot, _, _, _, top = pending.pop()
1291
relprefix = relroot + u'/'
1294
top_slash = top + u'/'
1297
append = dirblock.append
1299
names = sorted(_listdir(top))
1301
if not _is_error_enotdir(e):
1305
abspath = top_slash + name
1306
statvalue = _lstat(abspath)
1307
kind = _kind_from_mode(statvalue.st_mode)
1308
append((relprefix + name, name, kind, statvalue, abspath))
1309
yield (relroot, top), dirblock
1311
# push the user specified dirs from dirblock
1312
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1315
class DirReader(object):
1316
"""An interface for reading directories."""
1318
def top_prefix_to_starting_dir(self, top, prefix=""):
1319
"""Converts top and prefix to a starting dir entry
1321
:param top: A utf8 path
1322
:param prefix: An optional utf8 path to prefix output relative paths
1324
:return: A tuple starting with prefix, and ending with the native
1327
raise NotImplementedError(self.top_prefix_to_starting_dir)
1329
def read_dir(self, prefix, top):
1330
"""Read a specific dir.
1332
:param prefix: A utf8 prefix to be preprended to the path basenames.
1333
:param top: A natively encoded path to read.
1334
:return: A list of the directories contents. Each item contains:
1335
(utf8_relpath, utf8_name, kind, lstatvalue, native_abspath)
1337
raise NotImplementedError(self.read_dir)
1340
_selected_dir_reader = None
1343
def _walkdirs_utf8(top, prefix=""):
1344
"""Yield data about all the directories in a tree.
1346
This yields the same information as walkdirs() only each entry is yielded
1347
in utf-8. On platforms which have a filesystem encoding of utf8 the paths
1348
are returned as exact byte-strings.
1350
:return: yields a tuple of (dir_info, [file_info])
1351
dir_info is (utf8_relpath, path-from-top)
1352
file_info is (utf8_relpath, utf8_name, kind, lstat, path-from-top)
1353
if top is an absolute path, path-from-top is also an absolute path.
1354
path-from-top might be unicode or utf8, but it is the correct path to
1355
pass to os functions to affect the file in question. (such as os.lstat)
1357
global _selected_dir_reader
1358
if _selected_dir_reader is None:
1359
fs_encoding = _fs_enc.upper()
1360
if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1361
# Win98 doesn't have unicode apis like FindFirstFileW
1362
# TODO: We possibly could support Win98 by falling back to the
1363
# original FindFirstFile, and using TCHAR instead of WCHAR,
1364
# but that gets a bit tricky, and requires custom compiling
1367
from bzrlib._walkdirs_win32 import Win32ReadDir
1369
_selected_dir_reader = UnicodeDirReader()
1371
_selected_dir_reader = Win32ReadDir()
1372
elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1373
# ANSI_X3.4-1968 is a form of ASCII
1374
_selected_dir_reader = UnicodeDirReader()
1377
from bzrlib._readdir_pyx import UTF8DirReader
1379
# No optimised code path
1380
_selected_dir_reader = UnicodeDirReader()
1382
_selected_dir_reader = UTF8DirReader()
1383
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1384
# But we don't actually uses 1-3 in pending, so set them to None
1385
pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
1386
read_dir = _selected_dir_reader.read_dir
1387
_directory = _directory_kind
1389
relroot, _, _, _, top = pending[-1].pop()
1392
dirblock = sorted(read_dir(relroot, top))
1393
yield (relroot, top), dirblock
1394
# push the user specified dirs from dirblock
1395
next = [d for d in reversed(dirblock) if d[2] == _directory]
1397
pending.append(next)
1400
class UnicodeDirReader(DirReader):
1401
"""A dir reader for non-utf8 file systems, which transcodes."""
1403
__slots__ = ['_utf8_encode']
1406
self._utf8_encode = codecs.getencoder('utf8')
1408
def top_prefix_to_starting_dir(self, top, prefix=""):
1409
"""See DirReader.top_prefix_to_starting_dir."""
1410
return (safe_utf8(prefix), None, None, None, safe_unicode(top))
1412
def read_dir(self, prefix, top):
1413
"""Read a single directory from a non-utf8 file system.
1415
top, and the abspath element in the output are unicode, all other paths
1416
are utf8. Local disk IO is done via unicode calls to listdir etc.
1418
This is currently the fallback code path when the filesystem encoding is
1419
not UTF-8. It may be better to implement an alternative so that we can
1420
safely handle paths that are not properly decodable in the current
1423
See DirReader.read_dir for details.
1425
_utf8_encode = self._utf8_encode
1427
_listdir = os.listdir
1428
_kind_from_mode = file_kind_from_stat_mode
1431
relprefix = prefix + '/'
1434
top_slash = top + u'/'
1437
append = dirblock.append
840
1438
for name in sorted(_listdir(top)):
841
abspath = top + '/' + name
842
statvalue = lstat(abspath)
843
dirblock.append ((relroot + name, name, file_kind_from_stat_mode(statvalue.st_mode), statvalue, abspath))
845
# push the user specified dirs from dirblock
846
for dir in reversed(dirblock):
847
if dir[2] == _directory:
1440
name_utf8 = _utf8_encode(name)[0]
1441
except UnicodeDecodeError:
1442
raise errors.BadFilenameEncoding(
1443
_utf8_encode(relprefix)[0] + name, _fs_enc)
1444
abspath = top_slash + name
1445
statvalue = _lstat(abspath)
1446
kind = _kind_from_mode(statvalue.st_mode)
1447
append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1451
def copy_tree(from_path, to_path, handlers={}):
1452
"""Copy all of the entries in from_path into to_path.
1454
:param from_path: The base directory to copy.
1455
:param to_path: The target directory. If it does not exist, it will
1457
:param handlers: A dictionary of functions, which takes a source and
1458
destinations for files, directories, etc.
1459
It is keyed on the file kind, such as 'directory', 'symlink', or 'file'
1460
'file', 'directory', and 'symlink' should always exist.
1461
If they are missing, they will be replaced with 'os.mkdir()',
1462
'os.readlink() + os.symlink()', and 'shutil.copy2()', respectively.
1464
# Now, just copy the existing cached tree to the new location
1465
# We use a cheap trick here.
1466
# Absolute paths are prefixed with the first parameter
1467
# relative paths are prefixed with the second.
1468
# So we can get both the source and target returned
1469
# without any extra work.
1471
def copy_dir(source, dest):
1474
def copy_link(source, dest):
1475
"""Copy the contents of a symlink"""
1476
link_to = os.readlink(source)
1477
os.symlink(link_to, dest)
1479
real_handlers = {'file':shutil.copy2,
1480
'symlink':copy_link,
1481
'directory':copy_dir,
1483
real_handlers.update(handlers)
1485
if not os.path.exists(to_path):
1486
real_handlers['directory'](from_path, to_path)
1488
for dir_info, entries in walkdirs(from_path, prefix=to_path):
1489
for relpath, name, kind, st, abspath in entries:
1490
real_handlers[kind](abspath, relpath)
1493
def path_prefix_key(path):
1494
"""Generate a prefix-order path key for path.
1496
This can be used to sort paths in the same way that walkdirs does.
1498
return (dirname(path) , path)
1501
def compare_paths_prefix_order(path_a, path_b):
1502
"""Compare path_a and path_b to generate the same order walkdirs uses."""
1503
key_a = path_prefix_key(path_a)
1504
key_b = path_prefix_key(path_b)
1505
return cmp(key_a, key_b)
1508
_cached_user_encoding = None
1511
def get_user_encoding(use_cache=True):
1512
"""Find out what the preferred user encoding is.
1514
This is generally the encoding that is used for command line parameters
1515
and file contents. This may be different from the terminal encoding
1516
or the filesystem encoding.
1518
:param use_cache: Enable cache for detected encoding.
1519
(This parameter is turned on by default,
1520
and required only for selftesting)
1522
:return: A string defining the preferred user encoding
1524
global _cached_user_encoding
1525
if _cached_user_encoding is not None and use_cache:
1526
return _cached_user_encoding
1528
if sys.platform == 'darwin':
1529
# python locale.getpreferredencoding() always return
1530
# 'mac-roman' on darwin. That's a lie.
1531
sys.platform = 'posix'
1533
if os.environ.get('LANG', None) is None:
1534
# If LANG is not set, we end up with 'ascii', which is bad
1535
# ('mac-roman' is more than ascii), so we set a default which
1536
# will give us UTF-8 (which appears to work in all cases on
1537
# OSX). Users are still free to override LANG of course, as
1538
# long as it give us something meaningful. This work-around
1539
# *may* not be needed with python 3k and/or OSX 10.5, but will
1540
# work with them too -- vila 20080908
1541
os.environ['LANG'] = 'en_US.UTF-8'
1544
sys.platform = 'darwin'
1549
user_encoding = locale.getpreferredencoding()
1550
except locale.Error, e:
1551
sys.stderr.write('bzr: warning: %s\n'
1552
' Could not determine what text encoding to use.\n'
1553
' This error usually means your Python interpreter\n'
1554
' doesn\'t support the locale set by $LANG (%s)\n'
1555
" Continuing with ascii encoding.\n"
1556
% (e, os.environ.get('LANG')))
1557
user_encoding = 'ascii'
1559
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1560
# treat that as ASCII, and not support printing unicode characters to the
1563
# For python scripts run under vim, we get '', so also treat that as ASCII
1564
if user_encoding in (None, 'cp0', ''):
1565
user_encoding = 'ascii'
1569
codecs.lookup(user_encoding)
1571
sys.stderr.write('bzr: warning:'
1572
' unknown encoding %s.'
1573
' Continuing with ascii encoding.\n'
1576
user_encoding = 'ascii'
1579
_cached_user_encoding = user_encoding
1581
return user_encoding
1584
def get_host_name():
1585
"""Return the current unicode host name.
1587
This is meant to be used in place of socket.gethostname() because that
1588
behaves inconsistently on different platforms.
1590
if sys.platform == "win32":
1592
return win32utils.get_host_name()
1595
return socket.gethostname().decode(get_user_encoding())
1598
def recv_all(socket, bytes):
1599
"""Receive an exact number of bytes.
1601
Regular Socket.recv() may return less than the requested number of bytes,
1602
dependning on what's in the OS buffer. MSG_WAITALL is not available
1603
on all platforms, but this should work everywhere. This will return
1604
less than the requested amount if the remote end closes.
1606
This isn't optimized and is intended mostly for use in testing.
1609
while len(b) < bytes:
1610
new = until_no_eintr(socket.recv, bytes - len(b))
1617
def send_all(socket, bytes):
1618
"""Send all bytes on a socket.
1620
Regular socket.sendall() can give socket error 10053 on Windows. This
1621
implementation sends no more than 64k at a time, which avoids this problem.
1624
for pos in xrange(0, len(bytes), chunk_size):
1625
until_no_eintr(socket.sendall, bytes[pos:pos+chunk_size])
1628
def dereference_path(path):
1629
"""Determine the real path to a file.
1631
All parent elements are dereferenced. But the file itself is not
1633
:param path: The original path. May be absolute or relative.
1634
:return: the real path *to* the file
1636
parent, base = os.path.split(path)
1637
# The pathjoin for '.' is a workaround for Python bug #1213894.
1638
# (initial path components aren't dereferenced)
1639
return pathjoin(realpath(pathjoin('.', parent)), base)
1642
def supports_mapi():
1643
"""Return True if we can use MAPI to launch a mail client."""
1644
return sys.platform == "win32"
1647
def resource_string(package, resource_name):
1648
"""Load a resource from a package and return it as a string.
1650
Note: Only packages that start with bzrlib are currently supported.
1652
This is designed to be a lightweight implementation of resource
1653
loading in a way which is API compatible with the same API from
1655
http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access.
1656
If and when pkg_resources becomes a standard library, this routine
1659
# Check package name is within bzrlib
1660
if package == "bzrlib":
1661
resource_relpath = resource_name
1662
elif package.startswith("bzrlib."):
1663
package = package[len("bzrlib."):].replace('.', os.sep)
1664
resource_relpath = pathjoin(package, resource_name)
1666
raise errors.BzrError('resource package %s not in bzrlib' % package)
1668
# Map the resource to a file and read its contents
1669
base = dirname(bzrlib.__file__)
1670
if getattr(sys, 'frozen', None): # bzr.exe
1671
base = abspath(pathjoin(base, '..', '..'))
1672
filename = pathjoin(base, resource_relpath)
1673
return open(filename, 'rU').read()
1676
def file_kind_from_stat_mode_thunk(mode):
1677
global file_kind_from_stat_mode
1678
if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
1680
from bzrlib._readdir_pyx import UTF8DirReader
1681
file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1683
from bzrlib._readdir_py import (
1684
_kind_from_mode as file_kind_from_stat_mode
1686
return file_kind_from_stat_mode(mode)
1687
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
1690
def file_kind(f, _lstat=os.lstat):
1692
return file_kind_from_stat_mode(_lstat(f).st_mode)
1694
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
1695
raise errors.NoSuchFile(f)
1699
def until_no_eintr(f, *a, **kw):
1700
"""Run f(*a, **kw), retrying if an EINTR error occurs."""
1701
# Borrowed from Twisted's twisted.python.util.untilConcludes function.
1705
except (IOError, OSError), e:
1706
if e.errno == errno.EINTR:
1711
if sys.platform == "win32":
1714
return msvcrt.getch()
1719
fd = sys.stdin.fileno()
1720
settings = termios.tcgetattr(fd)
1723
ch = sys.stdin.read(1)
1725
termios.tcsetattr(fd, termios.TCSADRAIN, settings)