110
113
raise BzrError("lstat/stat of (%r): %r" % (f, e))
112
def normalizepath(f):
113
if hasattr(os.path, 'realpath'):
117
[p,e] = os.path.split(f)
118
if e == "" or e == "." or e == "..":
121
return os.path.join(F(p), e)
115
def fancy_rename(old, new, rename_func, unlink_func):
116
"""A fancy rename, when you don't have atomic rename.
118
:param old: The old path, to rename from
119
:param new: The new path, to rename to
120
:param rename_func: The potentially non-atomic rename function
121
:param unlink_func: A way to delete the target file if the full rename succeeds
124
# sftp rename doesn't allow overwriting, so play tricks:
126
base = os.path.basename(new)
127
dirname = os.path.dirname(new)
128
tmp_name = u'tmp.%s.%.9f.%d.%d' % (base, time.time(), os.getpid(), random.randint(0, 0x7FFFFFFF))
129
tmp_name = pathjoin(dirname, tmp_name)
131
# Rename the file out of the way, but keep track if it didn't exist
132
# We don't want to grab just any exception
133
# something like EACCES should prevent us from continuing
134
# The downside is that the rename_func has to throw an exception
135
# with an errno = ENOENT, or NoSuchFile
138
rename_func(new, tmp_name)
139
except (NoSuchFile,), e:
142
# RBC 20060103 abstraction leakage: the paramiko SFTP clients rename
143
# function raises an IOError with errno == None when a rename fails.
144
# This then gets caught here.
145
if e.errno is not None:
148
if (not hasattr(e, 'errno')
149
or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
156
# This may throw an exception, in which case success will
158
rename_func(old, new)
162
# If the file used to exist, rename it back into place
163
# otherwise just delete it from the tmp location
165
unlink_func(tmp_name)
167
rename_func(tmp_name, new)
169
# Default is to just use the python builtins
170
abspath = os.path.abspath
171
realpath = os.path.realpath
172
pathjoin = os.path.join
173
normpath = os.path.normpath
175
mkdtemp = tempfile.mkdtemp
177
dirname = os.path.dirname
178
basename = os.path.basename
123
180
if os.name == "posix":
124
181
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
128
185
_fs_enc = sys.getfilesystemencoding()
129
186
def abspath(path):
130
187
return os.path.abspath(path.encode(_fs_enc)).decode(_fs_enc)
131
189
def realpath(path):
132
190
return os.path.realpath(path.encode(_fs_enc)).decode(_fs_enc)
192
if sys.platform == 'win32':
134
193
# We need to use the Unicode-aware os.path.abspath and
135
194
# os.path.realpath on Windows systems.
136
abspath = os.path.abspath
137
realpath = os.path.realpath
196
return os.path.abspath(path).replace('\\', '/')
199
return os.path.realpath(path).replace('\\', '/')
202
return os.path.join(*args).replace('\\', '/')
205
return os.path.normpath(path).replace('\\', '/')
208
return os.getcwdu().replace('\\', '/')
210
def mkdtemp(*args, **kwargs):
211
return tempfile.mkdtemp(*args, **kwargs).replace('\\', '/')
213
def rename(old, new):
214
fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
217
def normalizepath(f):
218
if hasattr(os.path, 'realpath'):
222
[p,e] = os.path.split(f)
223
if e == "" or e == "." or e == "..":
226
return pathjoin(F(p), e)
139
229
def backup_file(fn):
140
230
"""Copy a file to a backup.
195
279
def is_inside(dir, fname):
196
280
"""True if fname is inside dir.
198
The parameters should typically be passed to os.path.normpath first, so
282
The parameters should typically be passed to osutils.normpath first, so
199
283
that . and .. and repeated slashes are eliminated, and the separators
200
284
are canonical for the platform.
202
286
The empty string as a dir name is taken as top-of-tree and matches
205
>>> is_inside('src', os.path.join('src', 'foo.c'))
289
>>> is_inside('src', pathjoin('src', 'foo.c'))
207
291
>>> is_inside('src', 'srccontrol')
209
>>> is_inside('src', os.path.join('src', 'a', 'a', 'a', 'foo.c'))
293
>>> is_inside('src', pathjoin('src', 'a', 'a', 'a', 'foo.c'))
211
295
>>> is_inside('foo.c', 'foo.c')