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(), """
21
29
from ntpath import (abspath as _nt_abspath,
24
32
realpath as _nt_realpath,
25
33
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)
43
from tempfile import (
45
from bzrlib.errors import (BzrError,
46
BzrBadParameterNotUnicode,
51
from bzrlib.symbol_versioning import (deprecated_function,
54
from bzrlib.symbol_versioning import (
53
58
from bzrlib.trace import mutter
122
127
return _mapper(_lstat(f).st_mode)
123
128
except OSError, e:
124
129
if getattr(e, 'errno', None) == errno.ENOENT:
125
raise bzrlib.errors.NoSuchFile(f)
130
raise errors.NoSuchFile(f)
159
164
if e.errno == errno.ENOENT:
162
raise BzrError("lstat/stat of (%r): %r" % (f, e))
167
raise errors.BzrError("lstat/stat of (%r): %r" % (f, e))
165
170
def fancy_rename(old, new, rename_func, unlink_func):
186
191
file_existed = False
188
193
rename_func(new, tmp_name)
189
except (NoSuchFile,), e:
194
except (errors.NoSuchFile,), e:
191
196
except IOError, e:
192
197
# RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
221
226
# choke on a Unicode string containing a relative path if
222
227
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
224
_fs_enc = sys.getfilesystemencoding()
229
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
225
230
def _posix_abspath(path):
226
231
# jam 20060426 rather than encoding to fsencoding
227
232
# copy posixpath.abspath, but use os.getcwdu instead
302
307
pathjoin = os.path.join
303
308
normpath = os.path.normpath
304
309
getcwd = os.getcwdu
305
mkdtemp = tempfile.mkdtemp
306
310
rename = os.rename
307
311
dirname = os.path.dirname
308
312
basename = os.path.basename
309
rmtree = shutil.rmtree
313
# These were already imported into local scope
314
# mkdtemp = tempfile.mkdtemp
315
# rmtree = shutil.rmtree
311
317
MIN_ABS_PATHLENGTH = 1
326
332
"""Error handler for shutil.rmtree function [for win32]
327
333
Helps to remove files and dirs marked as read-only.
329
type_, value = excinfo[:2]
335
exception = excinfo[1]
330
336
if function in (os.remove, os.rmdir) \
331
and type_ == OSError \
332
and value.errno == errno.EACCES:
333
bzrlib.osutils.make_writable(path)
337
and isinstance(exception, OSError) \
338
and exception.errno == errno.EACCES:
366
372
mutter('encoding stdout as sys.stdin encoding %r', output_encoding)
368
374
mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
375
if output_encoding == 'cp0':
376
# invalid encoding (cp0 means 'no codepage' on Windows)
377
output_encoding = bzrlib.user_encoding
378
mutter('cp0 is invalid encoding.'
379
' encoding stdout as bzrlib.user_encoding %r', output_encoding)
369
380
return output_encoding
441
452
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
455
# XXX: Most callers of this can actually do something smarter by
458
456
# looking at the inventory
581
579
tt = time.localtime(t)
582
580
offset = local_time_offset(t)
584
raise BzrError("unsupported timezone format %r" % timezone,
585
['options are "utc", "original", "local"'])
582
raise errors.BzrError("unsupported timezone format %r" % timezone,
583
['options are "utc", "original", "local"'])
586
584
if date_fmt is None:
587
585
date_fmt = "%a %Y-%m-%d %H:%M:%S"
596
594
return time.strftime('%Y%m%d%H%M%S', time.gmtime(when))
597
def format_delta(delta):
598
"""Get a nice looking string for a time delta.
600
:param delta: The time difference in seconds, can be positive or negative.
601
positive indicates time in the past, negative indicates time in the
602
future. (usually time.time() - stored_time)
603
:return: String formatted to show approximate resolution
609
direction = 'in the future'
613
if seconds < 90: # print seconds up to 90 seconds
615
return '%d second %s' % (seconds, direction,)
617
return '%d seconds %s' % (seconds, direction)
619
minutes = int(seconds / 60)
620
seconds -= 60 * minutes
625
if minutes < 90: # print minutes, seconds up to 90 minutes
627
return '%d minute, %d second%s %s' % (
628
minutes, seconds, plural_seconds, direction)
630
return '%d minutes, %d second%s %s' % (
631
minutes, seconds, plural_seconds, direction)
633
hours = int(minutes / 60)
634
minutes -= 60 * hours
641
return '%d hour, %d minute%s %s' % (hours, minutes,
642
plural_minutes, direction)
643
return '%d hours, %d minute%s %s' % (hours, minutes,
644
plural_minutes, direction)
601
647
"""Return size of given open file."""
611
657
except (NotImplementedError, AttributeError):
612
658
# If python doesn't have os.urandom, or it doesn't work,
613
659
# then try to first pull random data from /dev/urandom
614
if os.path.exists("/dev/urandom"):
615
661
rand_bytes = file('/dev/urandom', 'rb').read
616
662
# Otherwise, use this hack as a last resort
663
except (IOError, OSError):
618
664
# not well seeded, but better than nothing
619
665
def rand_bytes(n):
642
688
## decomposition (might be too tricksy though.)
644
690
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)
691
"""Turn string into list of parts."""
692
assert isinstance(p, basestring)
662
694
# split on either delimiter because people might use either on
677
709
assert isinstance(p, list)
679
711
if (f == '..') or (f is None) or (f == ''):
680
raise BzrError("sorry, %r not allowed in path" % f)
712
raise errors.BzrError("sorry, %r not allowed in path" % f)
681
713
return pathjoin(*p)
705
737
def link_or_copy(src, dest):
706
738
"""Hardlink a file, or copy it if it can't be hardlinked."""
707
739
if not hardlinks_good():
740
shutil.copyfile(src, dest)
711
743
os.link(src, dest)
712
744
except (OSError, IOError), e:
713
745
if e.errno != errno.EXDEV:
747
shutil.copyfile(src, dest)
717
749
def delete_any(full_path):
718
750
"""Delete a file or directory."""
798
830
return unicode_or_utf8_string.decode('utf8')
799
831
except UnicodeDecodeError:
800
raise BzrBadParameterNotUnicode(unicode_or_utf8_string)
832
raise errors.BzrBadParameterNotUnicode(unicode_or_utf8_string)
803
835
_platform_normalizes_filenames = False
902
934
if sys.platform != "win32":
904
936
if _validWin32PathRE.match(path) is None:
905
raise IllegalPath(path)
937
raise errors.IllegalPath(path)
908
940
def walkdirs(top, prefix=""):
1058
1090
" Continuing with ascii encoding.\n"
1059
1091
% (e, os.environ.get('LANG')))
1061
if _cached_user_encoding is None:
1093
# Windows returns 'cp0' to indicate there is no code page. So we'll just
1094
# treat that as ASCII, and not support printing unicode characters to the
1096
if _cached_user_encoding in (None, 'cp0'):
1062
1097
_cached_user_encoding = 'ascii'
1063
1098
return _cached_user_encoding
1101
def recv_all(socket, bytes):
1102
"""Receive an exact number of bytes.
1104
Regular Socket.recv() may return less than the requested number of bytes,
1105
dependning on what's in the OS buffer. MSG_WAITALL is not available
1106
on all platforms, but this should work everywhere. This will return
1107
less than the requested amount if the remote end closes.
1109
This isn't optimized and is intended mostly for use in testing.
1112
while len(b) < bytes:
1113
new = socket.recv(bytes - len(b))
1119
def dereference_path(path):
1120
"""Determine the real path to a file.
1122
All parent elements are dereferenced. But the file itself is not
1124
:param path: The original path. May be absolute or relative.
1125
:return: the real path *to* the file
1127
parent, base = os.path.split(path)
1128
# The pathjoin for '.' is a workaround for Python bug #1213894.
1129
# (initial path components aren't dereferenced)
1130
return pathjoin(realpath(pathjoin('.', parent)), base)