17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
19
from cStringIO import StringIO
23
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
24
S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
28
from bzrlib.lazy_import import lazy_import
29
lazy_import(globals(), """
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)
45
from tempfile import (
45
from bzrlib.errors import (BzrError,
46
BzrBadParameterNotUnicode,
51
from bzrlib.symbol_versioning import (deprecated_function,
56
from bzrlib.symbol_versioning import (
53
60
from bzrlib.trace import mutter
159
166
if e.errno == errno.ENOENT:
162
raise BzrError("lstat/stat of (%r): %r" % (f, e))
169
raise errors.BzrError("lstat/stat of (%r): %r" % (f, e))
165
172
def fancy_rename(old, new, rename_func, unlink_func):
186
193
file_existed = False
188
195
rename_func(new, tmp_name)
189
except (NoSuchFile,), e:
196
except (errors.NoSuchFile,), e:
191
198
except IOError, e:
192
199
# RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
193
# function raises an IOError with errno == None when a rename fails.
200
# function raises an IOError with errno is None when a rename fails.
194
201
# This then gets caught here.
195
202
if e.errno not in (None, errno.ENOENT, errno.ENOTDIR):
197
204
except Exception, e:
198
if (not hasattr(e, 'errno')
205
if (getattr(e, 'errno', None) is None
199
206
or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
221
228
# choke on a Unicode string containing a relative path if
222
229
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
224
_fs_enc = sys.getfilesystemencoding()
231
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
225
232
def _posix_abspath(path):
226
233
# jam 20060426 rather than encoding to fsencoding
227
234
# copy posixpath.abspath, but use os.getcwdu instead
302
309
pathjoin = os.path.join
303
310
normpath = os.path.normpath
304
311
getcwd = os.getcwdu
305
mkdtemp = tempfile.mkdtemp
306
312
rename = os.rename
307
313
dirname = os.path.dirname
308
314
basename = os.path.basename
309
rmtree = shutil.rmtree
315
# These were already imported into local scope
316
# mkdtemp = tempfile.mkdtemp
317
# rmtree = shutil.rmtree
311
319
MIN_ABS_PATHLENGTH = 1
441
449
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
452
# XXX: Most callers of this can actually do something smarter by
458
453
# looking at the inventory
574
569
tt = time.gmtime(t)
576
571
elif timezone == 'original':
579
574
tt = time.gmtime(t + offset)
580
575
elif timezone == 'local':
581
576
tt = time.localtime(t)
582
577
offset = local_time_offset(t)
584
raise BzrError("unsupported timezone format %r" % timezone,
585
['options are "utc", "original", "local"'])
579
raise errors.BzrError("unsupported timezone format %r" % timezone,
580
['options are "utc", "original", "local"'])
586
581
if date_fmt is None:
587
582
date_fmt = "%a %Y-%m-%d %H:%M:%S"
596
591
return time.strftime('%Y%m%d%H%M%S', time.gmtime(when))
594
def format_delta(delta):
595
"""Get a nice looking string for a time delta.
597
:param delta: The time difference in seconds, can be positive or negative.
598
positive indicates time in the past, negative indicates time in the
599
future. (usually time.time() - stored_time)
600
:return: String formatted to show approximate resolution
606
direction = 'in the future'
610
if seconds < 90: # print seconds up to 90 seconds
612
return '%d second %s' % (seconds, direction,)
614
return '%d seconds %s' % (seconds, direction)
616
minutes = int(seconds / 60)
617
seconds -= 60 * minutes
622
if minutes < 90: # print minutes, seconds up to 90 minutes
624
return '%d minute, %d second%s %s' % (
625
minutes, seconds, plural_seconds, direction)
627
return '%d minutes, %d second%s %s' % (
628
minutes, seconds, plural_seconds, direction)
630
hours = int(minutes / 60)
631
minutes -= 60 * hours
638
return '%d hour, %d minute%s %s' % (hours, minutes,
639
plural_minutes, direction)
640
return '%d hours, %d minute%s %s' % (hours, minutes,
641
plural_minutes, direction)
601
644
"""Return size of given open file."""
611
654
except (NotImplementedError, AttributeError):
612
655
# If python doesn't have os.urandom, or it doesn't work,
613
656
# then try to first pull random data from /dev/urandom
614
if os.path.exists("/dev/urandom"):
615
658
rand_bytes = file('/dev/urandom', 'rb').read
616
659
# Otherwise, use this hack as a last resort
660
except (IOError, OSError):
618
661
# not well seeded, but better than nothing
619
662
def rand_bytes(n):
642
685
## decomposition (might be too tricksy though.)
644
687
def splitpath(p):
645
"""Turn string into list of parts.
651
>>> splitpath('a/./b')
653
>>> splitpath('a/.b')
655
>>> splitpath('a/../b')
656
Traceback (most recent call last):
658
BzrError: sorry, '..' not allowed in path
660
assert isinstance(p, types.StringTypes)
688
"""Turn string into list of parts."""
689
assert isinstance(p, basestring)
662
691
# split on either delimiter because people might use either on
677
706
assert isinstance(p, list)
679
if (f == '..') or (f == None) or (f == ''):
680
raise BzrError("sorry, %r not allowed in path" % f)
708
if (f == '..') or (f is None) or (f == ''):
709
raise errors.BzrError("sorry, %r not allowed in path" % f)
681
710
return pathjoin(*p)
705
734
def link_or_copy(src, dest):
706
735
"""Hardlink a file, or copy it if it can't be hardlinked."""
707
736
if not hardlinks_good():
737
shutil.copyfile(src, dest)
711
740
os.link(src, dest)
712
741
except (OSError, IOError), e:
713
742
if e.errno != errno.EXDEV:
744
shutil.copyfile(src, dest)
717
746
def delete_any(full_path):
718
747
"""Delete a file or directory."""
870
900
def supports_executable():
871
901
return sys.platform != "win32"
904
def set_or_unset_env(env_variable, value):
905
"""Modify the environment, setting or removing the env_variable.
907
:param env_variable: The environment variable in question
908
:param value: The value to set the environment to. If None, then
909
the variable will be removed.
910
:return: The original value of the environment variable.
912
orig_val = os.environ.get(env_variable)
914
if orig_val is not None:
915
del os.environ[env_variable]
917
if isinstance(value, unicode):
918
value = value.encode(bzrlib.user_encoding)
919
os.environ[env_variable] = value
874
923
_validWin32PathRE = re.compile(r'^([A-Za-z]:[/\\])?[^:<>*"?\|]*$')
945
994
pending.append(dir)
997
def copy_tree(from_path, to_path, handlers={}):
998
"""Copy all of the entries in from_path into to_path.
1000
:param from_path: The base directory to copy.
1001
:param to_path: The target directory. If it does not exist, it will
1003
:param handlers: A dictionary of functions, which takes a source and
1004
destinations for files, directories, etc.
1005
It is keyed on the file kind, such as 'directory', 'symlink', or 'file'
1006
'file', 'directory', and 'symlink' should always exist.
1007
If they are missing, they will be replaced with 'os.mkdir()',
1008
'os.readlink() + os.symlink()', and 'shutil.copy2()', respectively.
1010
# Now, just copy the existing cached tree to the new location
1011
# We use a cheap trick here.
1012
# Absolute paths are prefixed with the first parameter
1013
# relative paths are prefixed with the second.
1014
# So we can get both the source and target returned
1015
# without any extra work.
1017
def copy_dir(source, dest):
1020
def copy_link(source, dest):
1021
"""Copy the contents of a symlink"""
1022
link_to = os.readlink(source)
1023
os.symlink(link_to, dest)
1025
real_handlers = {'file':shutil.copy2,
1026
'symlink':copy_link,
1027
'directory':copy_dir,
1029
real_handlers.update(handlers)
1031
if not os.path.exists(to_path):
1032
real_handlers['directory'](from_path, to_path)
1034
for dir_info, entries in walkdirs(from_path, prefix=to_path):
1035
for relpath, name, kind, st, abspath in entries:
1036
real_handlers[kind](abspath, relpath)
948
1039
def path_prefix_key(path):
949
1040
"""Generate a prefix-order path key for path.
958
1049
key_a = path_prefix_key(path_a)
959
1050
key_b = path_prefix_key(path_b)
960
1051
return cmp(key_a, key_b)
1054
_cached_user_encoding = None
1057
def get_user_encoding():
1058
"""Find out what the preferred user encoding is.
1060
This is generally the encoding that is used for command line parameters
1061
and file contents. This may be different from the terminal encoding
1062
or the filesystem encoding.
1064
:return: A string defining the preferred user encoding
1066
global _cached_user_encoding
1067
if _cached_user_encoding is not None:
1068
return _cached_user_encoding
1070
if sys.platform == 'darwin':
1071
# work around egregious python 2.4 bug
1072
sys.platform = 'posix'
1076
sys.platform = 'darwin'
1081
_cached_user_encoding = locale.getpreferredencoding()
1082
except locale.Error, e:
1083
sys.stderr.write('bzr: warning: %s\n'
1084
' Could not determine what text encoding to use.\n'
1085
' This error usually means your Python interpreter\n'
1086
' doesn\'t support the locale set by $LANG (%s)\n'
1087
" Continuing with ascii encoding.\n"
1088
% (e, os.environ.get('LANG')))
1090
if _cached_user_encoding is None:
1091
_cached_user_encoding = 'ascii'
1092
return _cached_user_encoding
1095
def recv_all(socket, bytes):
1096
"""Receive an exact number of bytes.
1098
Regular Socket.recv() may return less than the requested number of bytes,
1099
dependning on what's in the OS buffer. MSG_WAITALL is not available
1100
on all platforms, but this should work everywhere. This will return
1101
less than the requested amount if the remote end closes.
1103
This isn't optimized and is intended mostly for use in testing.
1106
while len(b) < bytes:
1107
new = socket.recv(bytes - len(b))
1113
def dereference_path(path):
1114
"""Determine the real path to a file.
1116
All parent elements are dereferenced. But the file itself is not
1118
:param path: The original path. May be absolute or relative.
1119
:return: the real path *to* the file
1121
parent, base = os.path.split(path)
1122
# The pathjoin for '.' is a workaround for Python bug #1213894.
1123
# (initial path components aren't dereferenced)
1124
return pathjoin(realpath(pathjoin('.', parent)), base)