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
63
# On win32, O_BINARY is used to indicate the file should
64
# be opened in binary mode, rather than text mode.
65
# On other platforms, O_BINARY doesn't exist, because
66
# they always open in binary mode, so it is okay to
67
# OR with 0 on those platforms
68
O_BINARY = getattr(os, 'O_BINARY', 0)
56
71
def make_readonly(filename):
57
72
"""Make a filename read-only."""
58
73
mod = os.stat(filename).st_mode
114
129
return _mapper(_lstat(f).st_mode)
115
130
except OSError, e:
116
131
if getattr(e, 'errno', None) == errno.ENOENT:
117
raise bzrlib.errors.NoSuchFile(f)
132
raise errors.NoSuchFile(f)
137
"""Return the current umask"""
138
# Assume that people aren't messing with the umask while running
139
# XXX: This is not thread safe, but there is no way to get the
140
# umask without setting it
121
146
def kind_marker(kind):
122
147
if kind == 'file':
168
193
file_existed = False
170
195
rename_func(new, tmp_name)
171
except (NoSuchFile,), e:
196
except (errors.NoSuchFile,), e:
173
198
except IOError, e:
174
199
# RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
175
# function raises an IOError with errno == None when a rename fails.
200
# function raises an IOError with errno is None when a rename fails.
176
201
# This then gets caught here.
177
202
if e.errno not in (None, errno.ENOENT, errno.ENOTDIR):
179
204
except Exception, e:
180
if (not hasattr(e, 'errno')
205
if (getattr(e, 'errno', None) is None
181
206
or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
423
449
The empty string as a dir name is taken as top-of-tree and matches
426
>>> is_inside('src', pathjoin('src', 'foo.c'))
428
>>> is_inside('src', 'srccontrol')
430
>>> is_inside('src', pathjoin('src', 'a', 'a', 'a', 'foo.c'))
432
>>> is_inside('foo.c', 'foo.c')
434
>>> is_inside('foo.c', '')
436
>>> is_inside('', 'foo.c')
439
452
# XXX: Most callers of this can actually do something smarter by
440
453
# looking at the inventory
556
569
tt = time.gmtime(t)
558
571
elif timezone == 'original':
561
574
tt = time.gmtime(t + offset)
562
575
elif timezone == 'local':
563
576
tt = time.localtime(t)
564
577
offset = local_time_offset(t)
566
raise BzrError("unsupported timezone format %r" % timezone,
567
['options are "utc", "original", "local"'])
579
raise errors.BzrError("unsupported timezone format %r" % timezone,
580
['options are "utc", "original", "local"'])
568
581
if date_fmt is None:
569
582
date_fmt = "%a %Y-%m-%d %H:%M:%S"
578
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)
583
644
"""Return size of given open file."""
593
654
except (NotImplementedError, AttributeError):
594
655
# If python doesn't have os.urandom, or it doesn't work,
595
656
# then try to first pull random data from /dev/urandom
596
if os.path.exists("/dev/urandom"):
597
658
rand_bytes = file('/dev/urandom', 'rb').read
598
659
# Otherwise, use this hack as a last resort
660
except (IOError, OSError):
600
661
# not well seeded, but better than nothing
601
662
def rand_bytes(n):
624
685
## decomposition (might be too tricksy though.)
626
687
def splitpath(p):
627
"""Turn string into list of parts.
633
>>> splitpath('a/./b')
635
>>> splitpath('a/.b')
637
>>> splitpath('a/../b')
638
Traceback (most recent call last):
640
BzrError: sorry, '..' not allowed in path
642
assert isinstance(p, types.StringTypes)
688
"""Turn string into list of parts."""
689
assert isinstance(p, basestring)
644
691
# split on either delimiter because people might use either on
687
734
def link_or_copy(src, dest):
688
735
"""Hardlink a file, or copy it if it can't be hardlinked."""
689
736
if not hardlinks_good():
737
shutil.copyfile(src, dest)
693
740
os.link(src, dest)
694
741
except (OSError, IOError), e:
695
742
if e.errno != errno.EXDEV:
744
shutil.copyfile(src, dest)
699
746
def delete_any(full_path):
700
747
"""Delete a file or directory."""
852
900
def supports_executable():
853
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
856
923
_validWin32PathRE = re.compile(r'^([A-Za-z]:[/\\])?[^:<>*"?\|]*$')
875
942
to exclude some directories, they are then not descended into.
877
944
The data yielded is of the form:
878
[(relpath, basename, kind, lstat, path_from_top), ...]
945
((directory-relpath, directory-path-from-top),
946
[(relpath, basename, kind, lstat), ...]),
947
- directory-relpath is the relative path of the directory being returned
948
with respect to top. prefix is prepended to this.
949
- directory-path-from-root is the path including top for this directory.
950
It is suitable for use with os functions.
951
- relpath is the relative path within the subtree being walked.
952
- basename is the basename of the path
953
- kind is the kind of the file now. If unknown then the file is not
954
present within the tree - but it may be recorded as versioned. See
956
- lstat is the stat data *if* the file was statted.
957
- planned, not implemented:
958
path_from_tree_root is the path from the root of the tree.
880
960
:param prefix: Prefix the relpaths that are yielded with 'prefix'. This
881
961
allows one to walk a subtree but get paths that are relative to a tree
882
962
rooted higher up.
883
963
:return: an iterator over the dirs.
965
#TODO there is a bit of a smell where the results of the directory-
966
# summary in this, and the path from the root, may not agree
967
# depending on top and prefix - i.e. ./foo and foo as a pair leads to
968
# potentially confusing output. We should make this more robust - but
969
# not at a speed cost. RBC 20060731
887
972
_directory = _directory_kind
973
_listdir = os.listdir
889
974
pending = [(prefix, "", _directory, None, top)]
899
984
for name in sorted(_listdir(top)):
900
985
abspath = top + '/' + name
901
986
statvalue = lstat(abspath)
902
dirblock.append ((relroot + name, name, file_kind_from_stat_mode(statvalue.st_mode), statvalue, abspath))
987
dirblock.append((relroot + name, name,
988
file_kind_from_stat_mode(statvalue.st_mode),
990
yield (currentdir[0], top), dirblock
904
991
# push the user specified dirs from dirblock
905
992
for dir in reversed(dirblock):
906
993
if dir[2] == _directory:
907
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)
910
1039
def path_prefix_key(path):
911
1040
"""Generate a prefix-order path key for path.
920
1049
key_a = path_prefix_key(path_a)
921
1050
key_b = path_prefix_key(path_b)
922
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