1
# Bazaar -- distributed version control
3
# Copyright (C) 2005 by Canonical Ltd
1
# Copyright (C) 2005, 2006 Canonical Ltd
5
3
# This program is free software; you can redistribute it and/or modify
6
4
# it under the terms of the GNU General Public License as published by
17
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
17
from cStringIO import StringIO
21
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
22
S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
26
from bzrlib.lazy_import import lazy_import
27
lazy_import(globals(), """
29
from datetime import datetime
21
31
from ntpath import (abspath as _nt_abspath,
24
34
realpath as _nt_realpath,
25
35
splitdrive as _nt_splitdrive,
28
from os import listdir
33
from shutil import copyfile
35
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
36
S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
44
from tempfile import (
45
from bzrlib.errors import (BzrError,
46
BzrBadParameterNotUnicode,
51
from bzrlib.symbol_versioning import (deprecated_function,
55
from bzrlib.symbol_versioning import (
53
59
from bzrlib.trace import mutter
122
128
return _mapper(_lstat(f).st_mode)
123
129
except OSError, e:
124
130
if getattr(e, 'errno', None) == errno.ENOENT:
125
raise bzrlib.errors.NoSuchFile(f)
131
raise errors.NoSuchFile(f)
159
165
if e.errno == errno.ENOENT:
162
raise BzrError("lstat/stat of (%r): %r" % (f, e))
168
raise errors.BzrError("lstat/stat of (%r): %r" % (f, e))
165
171
def fancy_rename(old, new, rename_func, unlink_func):
186
192
file_existed = False
188
194
rename_func(new, tmp_name)
189
except (NoSuchFile,), e:
195
except (errors.NoSuchFile,), e:
191
197
except IOError, e:
192
198
# RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
221
227
# choke on a Unicode string containing a relative path if
222
228
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
224
_fs_enc = sys.getfilesystemencoding()
230
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
225
231
def _posix_abspath(path):
226
232
# jam 20060426 rather than encoding to fsencoding
227
233
# copy posixpath.abspath, but use os.getcwdu instead
302
308
pathjoin = os.path.join
303
309
normpath = os.path.normpath
304
310
getcwd = os.getcwdu
305
mkdtemp = tempfile.mkdtemp
306
311
rename = os.rename
307
312
dirname = os.path.dirname
308
313
basename = os.path.basename
309
rmtree = shutil.rmtree
314
split = os.path.split
315
splitext = os.path.splitext
316
# These were already imported into local scope
317
# mkdtemp = tempfile.mkdtemp
318
# rmtree = shutil.rmtree
311
320
MIN_ABS_PATHLENGTH = 1
326
335
"""Error handler for shutil.rmtree function [for win32]
327
336
Helps to remove files and dirs marked as read-only.
329
type_, value = excinfo[:2]
338
exception = excinfo[1]
330
339
if function in (os.remove, os.rmdir) \
331
and type_ == OSError \
332
and value.errno == errno.EACCES:
333
bzrlib.osutils.make_writable(path)
340
and isinstance(exception, OSError) \
341
and exception.errno == errno.EACCES:
366
375
mutter('encoding stdout as sys.stdin encoding %r', output_encoding)
368
377
mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
378
if output_encoding == 'cp0':
379
# invalid encoding (cp0 means 'no codepage' on Windows)
380
output_encoding = bzrlib.user_encoding
381
mutter('cp0 is invalid encoding.'
382
' encoding stdout as bzrlib.user_encoding %r', output_encoding)
385
codecs.lookup(output_encoding)
387
sys.stderr.write('bzr: warning:'
388
' unknown terminal encoding %s.\n'
389
' Using encoding %s instead.\n'
390
% (output_encoding, bzrlib.user_encoding)
392
output_encoding = bzrlib.user_encoding
369
394
return output_encoding
441
466
The empty string as a dir name is taken as top-of-tree and matches
444
>>> is_inside('src', pathjoin('src', 'foo.c'))
446
>>> is_inside('src', 'srccontrol')
448
>>> is_inside('src', pathjoin('src', 'a', 'a', 'a', 'foo.c'))
450
>>> is_inside('foo.c', 'foo.c')
452
>>> is_inside('foo.c', '')
454
>>> is_inside('', 'foo.c')
457
469
# XXX: Most callers of this can actually do something smarter by
458
470
# looking at the inventory
555
567
def local_time_offset(t=None):
556
568
"""Return offset of local zone from GMT, either at present or at time t."""
557
# python2.3 localtime() can't take None
561
if time.localtime(t).tm_isdst and time.daylight:
564
return -time.timezone
571
offset = datetime.fromtimestamp(t) - datetime.utcfromtimestamp(t)
572
return offset.days * 86400 + offset.seconds
567
575
def format_date(t, offset=0, timezone='original', date_fmt=None,
581
589
tt = time.localtime(t)
582
590
offset = local_time_offset(t)
584
raise BzrError("unsupported timezone format %r" % timezone,
585
['options are "utc", "original", "local"'])
592
raise errors.BzrError("unsupported timezone format %r" % timezone,
593
['options are "utc", "original", "local"'])
586
594
if date_fmt is None:
587
595
date_fmt = "%a %Y-%m-%d %H:%M:%S"
659
667
except (NotImplementedError, AttributeError):
660
668
# If python doesn't have os.urandom, or it doesn't work,
661
669
# then try to first pull random data from /dev/urandom
662
if os.path.exists("/dev/urandom"):
663
671
rand_bytes = file('/dev/urandom', 'rb').read
664
672
# Otherwise, use this hack as a last resort
673
except (IOError, OSError):
666
674
# not well seeded, but better than nothing
667
675
def rand_bytes(n):
690
698
## decomposition (might be too tricksy though.)
692
700
def splitpath(p):
693
"""Turn string into list of parts.
699
>>> splitpath('a/./b')
701
>>> splitpath('a/.b')
703
>>> splitpath('a/../b')
704
Traceback (most recent call last):
706
BzrError: sorry, '..' not allowed in path
708
assert isinstance(p, types.StringTypes)
701
"""Turn string into list of parts."""
702
assert isinstance(p, basestring)
710
704
# split on either delimiter because people might use either on
725
719
assert isinstance(p, list)
727
721
if (f == '..') or (f is None) or (f == ''):
728
raise BzrError("sorry, %r not allowed in path" % f)
722
raise errors.BzrError("sorry, %r not allowed in path" % f)
729
723
return pathjoin(*p)
753
747
def link_or_copy(src, dest):
754
748
"""Hardlink a file, or copy it if it can't be hardlinked."""
755
749
if not hardlinks_good():
750
shutil.copyfile(src, dest)
759
753
os.link(src, dest)
760
754
except (OSError, IOError), e:
761
755
if e.errno != errno.EXDEV:
757
shutil.copyfile(src, dest)
765
759
def delete_any(full_path):
766
760
"""Delete a file or directory."""
783
777
def contains_whitespace(s):
784
778
"""True if there are any whitespace characters in s."""
785
for ch in string.whitespace:
779
# string.whitespace can include '\xa0' in certain locales, because it is
780
# considered "non-breaking-space" as part of ISO-8859-1. But it
781
# 1) Isn't a breaking whitespace
782
# 2) Isn't one of ' \t\r\n' which are characters we sometimes use as
784
# 3) '\xa0' isn't unicode safe since it is >128.
785
# So we are following textwrap's example and hard-coding our own.
786
# We probably could ignore \v and \f, too.
787
for ch in u' \t\n\r\v\f':
846
848
return unicode_or_utf8_string.decode('utf8')
847
849
except UnicodeDecodeError:
848
raise BzrBadParameterNotUnicode(unicode_or_utf8_string)
850
raise errors.BzrBadParameterNotUnicode(unicode_or_utf8_string)
851
853
_platform_normalizes_filenames = False
920
922
return sys.platform != "win32"
925
def supports_posix_readonly():
926
"""Return True if 'readonly' has POSIX semantics, False otherwise.
928
Notably, a win32 readonly file cannot be deleted, unlike POSIX where the
929
directory controls creation/deletion, etc.
931
And under win32, readonly means that the directory itself cannot be
932
deleted. The contents of a readonly directory can be changed, unlike POSIX
933
where files in readonly directories cannot be added, deleted or renamed.
935
return sys.platform != "win32"
923
938
def set_or_unset_env(env_variable, value):
924
939
"""Modify the environment, setting or removing the env_variable.
950
965
if sys.platform != "win32":
952
967
if _validWin32PathRE.match(path) is None:
953
raise IllegalPath(path)
968
raise errors.IllegalPath(path)
956
971
def walkdirs(top, prefix=""):
1073
1088
_cached_user_encoding = None
1076
def get_user_encoding():
1091
def get_user_encoding(use_cache=True):
1077
1092
"""Find out what the preferred user encoding is.
1079
1094
This is generally the encoding that is used for command line parameters
1080
1095
and file contents. This may be different from the terminal encoding
1081
1096
or the filesystem encoding.
1098
:param use_cache: Enable cache for detected encoding.
1099
(This parameter is turned on by default,
1100
and required only for selftesting)
1083
1102
:return: A string defining the preferred user encoding
1085
1104
global _cached_user_encoding
1086
if _cached_user_encoding is not None:
1105
if _cached_user_encoding is not None and use_cache:
1087
1106
return _cached_user_encoding
1089
1108
if sys.platform == 'darwin':
1105
1124
' doesn\'t support the locale set by $LANG (%s)\n'
1106
1125
" Continuing with ascii encoding.\n"
1107
1126
% (e, os.environ.get('LANG')))
1109
if _cached_user_encoding is None:
1110
_cached_user_encoding = 'ascii'
1111
return _cached_user_encoding
1127
user_encoding = 'ascii'
1129
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1130
# treat that as ASCII, and not support printing unicode characters to the
1132
if user_encoding in (None, 'cp0'):
1133
user_encoding = 'ascii'
1137
codecs.lookup(user_encoding)
1139
sys.stderr.write('bzr: warning:'
1140
' unknown encoding %s.'
1141
' Continuing with ascii encoding.\n'
1144
user_encoding = 'ascii'
1147
_cached_user_encoding = user_encoding
1149
return user_encoding
1152
def recv_all(socket, bytes):
1153
"""Receive an exact number of bytes.
1155
Regular Socket.recv() may return less than the requested number of bytes,
1156
dependning on what's in the OS buffer. MSG_WAITALL is not available
1157
on all platforms, but this should work everywhere. This will return
1158
less than the requested amount if the remote end closes.
1160
This isn't optimized and is intended mostly for use in testing.
1163
while len(b) < bytes:
1164
new = socket.recv(bytes - len(b))
1170
def dereference_path(path):
1171
"""Determine the real path to a file.
1173
All parent elements are dereferenced. But the file itself is not
1175
:param path: The original path. May be absolute or relative.
1176
:return: the real path *to* the file
1178
parent, base = os.path.split(path)
1179
# The pathjoin for '.' is a workaround for Python bug #1213894.
1180
# (initial path components aren't dereferenced)
1181
return pathjoin(realpath(pathjoin('.', parent)), base)