634
469
def local_time_offset(t=None):
635
470
"""Return offset of local zone from GMT, either at present or at time t."""
471
# python2.3 localtime() can't take None
638
offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
639
return offset.days * 86400 + offset.seconds
475
if time.localtime(t).tm_isdst and time.daylight:
478
return -time.timezone
641
weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
643
def format_date(t, offset=0, timezone='original', date_fmt=None,
481
def format_date(t, offset=0, timezone='original', date_fmt=None,
644
482
show_offset=True):
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):
483
## TODO: Perhaps a global option to use either universal or local time?
484
## Or perhaps just let people set $TZ?
485
assert isinstance(t, float)
681
487
if timezone == 'utc':
682
488
tt = time.gmtime(t)
684
490
elif timezone == 'original':
687
493
tt = time.gmtime(t + offset)
688
494
elif timezone == 'local':
689
495
tt = time.localtime(t)
690
496
offset = local_time_offset(t)
692
raise errors.UnsupportedTimezoneFormat(timezone)
498
raise BzrError("unsupported timezone format %r" % timezone,
499
['options are "utc", "original", "local"'])
693
500
if date_fmt is None:
694
501
date_fmt = "%a %Y-%m-%d %H:%M:%S"
696
503
offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
699
return (date_fmt, tt, offset_str)
506
return (time.strftime(date_fmt, tt) + offset_str)
702
509
def compact_date(when):
703
510
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)
756
515
"""Return size of given open file."""
1175
811
to exclude some directories, they are then not descended into.
1177
813
The data yielded is of the form:
1178
((directory-relpath, directory-path-from-top),
1179
[(relpath, basename, kind, lstat, path-from-top), ...]),
1180
- directory-relpath is the relative path of the directory being returned
1181
with respect to top. prefix is prepended to this.
1182
- directory-path-from-root is the path including top for this directory.
1183
It is suitable for use with os functions.
1184
- relpath is the relative path within the subtree being walked.
1185
- basename is the basename of the path
1186
- kind is the kind of the file now. If unknown then the file is not
1187
present within the tree - but it may be recorded as versioned. See
1189
- lstat is the stat data *if* the file was statted.
1190
- planned, not implemented:
1191
path_from_tree_root is the path from the root of the tree.
814
[(relpath, basename, kind, lstat, path_from_top), ...]
1193
:param prefix: Prefix the relpaths that are yielded with 'prefix'. This
1194
allows one to walk a subtree but get paths that are relative to a tree
1196
816
:return: an iterator over the dirs.
1198
#TODO there is a bit of a smell where the results of the directory-
1199
# summary in this, and the path from the root, may not agree
1200
# depending on top and prefix - i.e. ./foo and foo as a pair leads to
1201
# potentially confusing output. We should make this more robust - but
1202
# not at a speed cost. RBC 20060731
1204
820
_directory = _directory_kind
1205
_listdir = os.listdir
1206
_kind_from_mode = file_kind_from_stat_mode
1207
pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
822
pending = [("", "", _directory, None, top)]
825
currentdir = pending.pop()
1209
826
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1210
relroot, _, _, _, top = pending.pop()
1212
relprefix = relroot + u'/'
1215
top_slash = top + u'/'
1218
append = dirblock.append
1220
names = sorted(_listdir(top))
1222
if not _is_error_enotdir(e):
1226
abspath = top_slash + name
1227
statvalue = _lstat(abspath)
1228
kind = _kind_from_mode(statvalue.st_mode)
1229
append((relprefix + name, name, kind, statvalue, abspath))
1230
yield (relroot, top), dirblock
1232
# push the user specified dirs from dirblock
1233
pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
1236
class DirReader(object):
1237
"""An interface for reading directories."""
1239
def top_prefix_to_starting_dir(self, top, prefix=""):
1240
"""Converts top and prefix to a starting dir entry
1242
:param top: A utf8 path
1243
:param prefix: An optional utf8 path to prefix output relative paths
1245
:return: A tuple starting with prefix, and ending with the native
1248
raise NotImplementedError(self.top_prefix_to_starting_dir)
1250
def read_dir(self, prefix, top):
1251
"""Read a specific dir.
1253
:param prefix: A utf8 prefix to be preprended to the path basenames.
1254
:param top: A natively encoded path to read.
1255
:return: A list of the directories contents. Each item contains:
1256
(utf8_relpath, utf8_name, kind, lstatvalue, native_abspath)
1258
raise NotImplementedError(self.read_dir)
1261
_selected_dir_reader = None
1264
def _walkdirs_utf8(top, prefix=""):
1265
"""Yield data about all the directories in a tree.
1267
This yields the same information as walkdirs() only each entry is yielded
1268
in utf-8. On platforms which have a filesystem encoding of utf8 the paths
1269
are returned as exact byte-strings.
1271
:return: yields a tuple of (dir_info, [file_info])
1272
dir_info is (utf8_relpath, path-from-top)
1273
file_info is (utf8_relpath, utf8_name, kind, lstat, path-from-top)
1274
if top is an absolute path, path-from-top is also an absolute path.
1275
path-from-top might be unicode or utf8, but it is the correct path to
1276
pass to os functions to affect the file in question. (such as os.lstat)
1278
global _selected_dir_reader
1279
if _selected_dir_reader is None:
1280
fs_encoding = _fs_enc.upper()
1281
if sys.platform == "win32" and win32utils.winver == 'Windows NT':
1282
# Win98 doesn't have unicode apis like FindFirstFileW
1283
# TODO: We possibly could support Win98 by falling back to the
1284
# original FindFirstFile, and using TCHAR instead of WCHAR,
1285
# but that gets a bit tricky, and requires custom compiling
1288
from bzrlib._walkdirs_win32 import Win32ReadDir
1290
_selected_dir_reader = UnicodeDirReader()
1292
_selected_dir_reader = Win32ReadDir()
1293
elif fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1294
# ANSI_X3.4-1968 is a form of ASCII
1295
_selected_dir_reader = UnicodeDirReader()
1298
from bzrlib._readdir_pyx import UTF8DirReader
1300
# No optimised code path
1301
_selected_dir_reader = UnicodeDirReader()
1303
_selected_dir_reader = UTF8DirReader()
1304
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
1305
# But we don't actually uses 1-3 in pending, so set them to None
1306
pending = [[_selected_dir_reader.top_prefix_to_starting_dir(top, prefix)]]
1307
read_dir = _selected_dir_reader.read_dir
1308
_directory = _directory_kind
1310
relroot, _, _, _, top = pending[-1].pop()
1313
dirblock = sorted(read_dir(relroot, top))
1314
yield (relroot, top), dirblock
1315
# push the user specified dirs from dirblock
1316
next = [d for d in reversed(dirblock) if d[2] == _directory]
1318
pending.append(next)
1321
class UnicodeDirReader(DirReader):
1322
"""A dir reader for non-utf8 file systems, which transcodes."""
1324
__slots__ = ['_utf8_encode']
1327
self._utf8_encode = codecs.getencoder('utf8')
1329
def top_prefix_to_starting_dir(self, top, prefix=""):
1330
"""See DirReader.top_prefix_to_starting_dir."""
1331
return (safe_utf8(prefix), None, None, None, safe_unicode(top))
1333
def read_dir(self, prefix, top):
1334
"""Read a single directory from a non-utf8 file system.
1336
top, and the abspath element in the output are unicode, all other paths
1337
are utf8. Local disk IO is done via unicode calls to listdir etc.
1339
This is currently the fallback code path when the filesystem encoding is
1340
not UTF-8. It may be better to implement an alternative so that we can
1341
safely handle paths that are not properly decodable in the current
1344
See DirReader.read_dir for details.
1346
_utf8_encode = self._utf8_encode
1348
_listdir = os.listdir
1349
_kind_from_mode = file_kind_from_stat_mode
1352
relprefix = prefix + '/'
1355
top_slash = top + u'/'
1358
append = dirblock.append
829
relroot = currentdir[0] + '/'
1359
832
for name in sorted(_listdir(top)):
1361
name_utf8 = _utf8_encode(name)[0]
1362
except UnicodeDecodeError:
1363
raise errors.BadFilenameEncoding(
1364
_utf8_encode(relprefix)[0] + name, _fs_enc)
1365
abspath = top_slash + name
1366
statvalue = _lstat(abspath)
1367
kind = _kind_from_mode(statvalue.st_mode)
1368
append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
1372
def copy_tree(from_path, to_path, handlers={}):
1373
"""Copy all of the entries in from_path into to_path.
1375
:param from_path: The base directory to copy.
1376
:param to_path: The target directory. If it does not exist, it will
1378
:param handlers: A dictionary of functions, which takes a source and
1379
destinations for files, directories, etc.
1380
It is keyed on the file kind, such as 'directory', 'symlink', or 'file'
1381
'file', 'directory', and 'symlink' should always exist.
1382
If they are missing, they will be replaced with 'os.mkdir()',
1383
'os.readlink() + os.symlink()', and 'shutil.copy2()', respectively.
1385
# Now, just copy the existing cached tree to the new location
1386
# We use a cheap trick here.
1387
# Absolute paths are prefixed with the first parameter
1388
# relative paths are prefixed with the second.
1389
# So we can get both the source and target returned
1390
# without any extra work.
1392
def copy_dir(source, dest):
1395
def copy_link(source, dest):
1396
"""Copy the contents of a symlink"""
1397
link_to = os.readlink(source)
1398
os.symlink(link_to, dest)
1400
real_handlers = {'file':shutil.copy2,
1401
'symlink':copy_link,
1402
'directory':copy_dir,
1404
real_handlers.update(handlers)
1406
if not os.path.exists(to_path):
1407
real_handlers['directory'](from_path, to_path)
1409
for dir_info, entries in walkdirs(from_path, prefix=to_path):
1410
for relpath, name, kind, st, abspath in entries:
1411
real_handlers[kind](abspath, relpath)
1414
def path_prefix_key(path):
1415
"""Generate a prefix-order path key for path.
1417
This can be used to sort paths in the same way that walkdirs does.
1419
return (dirname(path) , path)
1422
def compare_paths_prefix_order(path_a, path_b):
1423
"""Compare path_a and path_b to generate the same order walkdirs uses."""
1424
key_a = path_prefix_key(path_a)
1425
key_b = path_prefix_key(path_b)
1426
return cmp(key_a, key_b)
1429
_cached_user_encoding = None
1432
def get_user_encoding(use_cache=True):
1433
"""Find out what the preferred user encoding is.
1435
This is generally the encoding that is used for command line parameters
1436
and file contents. This may be different from the terminal encoding
1437
or the filesystem encoding.
1439
:param use_cache: Enable cache for detected encoding.
1440
(This parameter is turned on by default,
1441
and required only for selftesting)
1443
:return: A string defining the preferred user encoding
1445
global _cached_user_encoding
1446
if _cached_user_encoding is not None and use_cache:
1447
return _cached_user_encoding
1449
if sys.platform == 'darwin':
1450
# python locale.getpreferredencoding() always return
1451
# 'mac-roman' on darwin. That's a lie.
1452
sys.platform = 'posix'
1454
if os.environ.get('LANG', None) is None:
1455
# If LANG is not set, we end up with 'ascii', which is bad
1456
# ('mac-roman' is more than ascii), so we set a default which
1457
# will give us UTF-8 (which appears to work in all cases on
1458
# OSX). Users are still free to override LANG of course, as
1459
# long as it give us something meaningful. This work-around
1460
# *may* not be needed with python 3k and/or OSX 10.5, but will
1461
# work with them too -- vila 20080908
1462
os.environ['LANG'] = 'en_US.UTF-8'
1465
sys.platform = 'darwin'
1470
user_encoding = locale.getpreferredencoding()
1471
except locale.Error, e:
1472
sys.stderr.write('bzr: warning: %s\n'
1473
' Could not determine what text encoding to use.\n'
1474
' This error usually means your Python interpreter\n'
1475
' doesn\'t support the locale set by $LANG (%s)\n'
1476
" Continuing with ascii encoding.\n"
1477
% (e, os.environ.get('LANG')))
1478
user_encoding = 'ascii'
1480
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1481
# treat that as ASCII, and not support printing unicode characters to the
1484
# For python scripts run under vim, we get '', so also treat that as ASCII
1485
if user_encoding in (None, 'cp0', ''):
1486
user_encoding = 'ascii'
1490
codecs.lookup(user_encoding)
1492
sys.stderr.write('bzr: warning:'
1493
' unknown encoding %s.'
1494
' Continuing with ascii encoding.\n'
1497
user_encoding = 'ascii'
1500
_cached_user_encoding = user_encoding
1502
return user_encoding
1505
def get_host_name():
1506
"""Return the current unicode host name.
1508
This is meant to be used in place of socket.gethostname() because that
1509
behaves inconsistently on different platforms.
1511
if sys.platform == "win32":
1513
return win32utils.get_host_name()
1516
return socket.gethostname().decode(get_user_encoding())
1519
def recv_all(socket, bytes):
1520
"""Receive an exact number of bytes.
1522
Regular Socket.recv() may return less than the requested number of bytes,
1523
dependning on what's in the OS buffer. MSG_WAITALL is not available
1524
on all platforms, but this should work everywhere. This will return
1525
less than the requested amount if the remote end closes.
1527
This isn't optimized and is intended mostly for use in testing.
1530
while len(b) < bytes:
1531
new = socket.recv(bytes - len(b))
1538
def send_all(socket, bytes):
1539
"""Send all bytes on a socket.
1541
Regular socket.sendall() can give socket error 10053 on Windows. This
1542
implementation sends no more than 64k at a time, which avoids this problem.
1545
for pos in xrange(0, len(bytes), chunk_size):
1546
socket.sendall(bytes[pos:pos+chunk_size])
1549
def dereference_path(path):
1550
"""Determine the real path to a file.
1552
All parent elements are dereferenced. But the file itself is not
1554
:param path: The original path. May be absolute or relative.
1555
:return: the real path *to* the file
1557
parent, base = os.path.split(path)
1558
# The pathjoin for '.' is a workaround for Python bug #1213894.
1559
# (initial path components aren't dereferenced)
1560
return pathjoin(realpath(pathjoin('.', parent)), base)
1563
def supports_mapi():
1564
"""Return True if we can use MAPI to launch a mail client."""
1565
return sys.platform == "win32"
1568
def resource_string(package, resource_name):
1569
"""Load a resource from a package and return it as a string.
1571
Note: Only packages that start with bzrlib are currently supported.
1573
This is designed to be a lightweight implementation of resource
1574
loading in a way which is API compatible with the same API from
1576
http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access.
1577
If and when pkg_resources becomes a standard library, this routine
1580
# Check package name is within bzrlib
1581
if package == "bzrlib":
1582
resource_relpath = resource_name
1583
elif package.startswith("bzrlib."):
1584
package = package[len("bzrlib."):].replace('.', os.sep)
1585
resource_relpath = pathjoin(package, resource_name)
1587
raise errors.BzrError('resource package %s not in bzrlib' % package)
1589
# Map the resource to a file and read its contents
1590
base = dirname(bzrlib.__file__)
1591
if getattr(sys, 'frozen', None): # bzr.exe
1592
base = abspath(pathjoin(base, '..', '..'))
1593
filename = pathjoin(base, resource_relpath)
1594
return open(filename, 'rU').read()
1597
def file_kind_from_stat_mode_thunk(mode):
1598
global file_kind_from_stat_mode
1599
if file_kind_from_stat_mode is file_kind_from_stat_mode_thunk:
1601
from bzrlib._readdir_pyx import UTF8DirReader
1602
file_kind_from_stat_mode = UTF8DirReader().kind_from_mode
1604
from bzrlib._readdir_py import (
1605
_kind_from_mode as file_kind_from_stat_mode
1607
return file_kind_from_stat_mode(mode)
1608
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
1611
def file_kind(f, _lstat=os.lstat):
1613
return file_kind_from_stat_mode(_lstat(f).st_mode)
1615
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
1616
raise errors.NoSuchFile(f)
833
abspath = top + '/' + name
834
statvalue = lstat(abspath)
835
dirblock.append ((relroot + name, name, file_kind_from_stat_mode(statvalue.st_mode), statvalue, abspath))
837
# push the user specified dirs from dirblock
838
for dir in reversed(dirblock):
839
if dir[2] == _directory: