113
113
raise BzrError("lstat/stat of (%r): %r" % (f, 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
if (not hasattr(e, 'errno')
143
or e.errno not in (errno.ENOENT, errno.ENOTDIR)):
150
# This may throw an exception, in which case success will
152
rename_func(old, new)
156
# If the file used to exist, rename it back into place
157
# otherwise just delete it from the tmp location
159
unlink_func(tmp_name)
161
rename_func(tmp_name, final_path)
163
# Default is to just use the python builtins
164
abspath = os.path.abspath
165
realpath = os.path.realpath
166
pathjoin = os.path.join
167
normpath = os.path.normpath
169
mkdtemp = tempfile.mkdtemp
171
dirname = os.path.dirname
172
basename = os.path.basename
115
174
if os.name == "posix":
116
175
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
117
176
# choke on a Unicode string containing a relative path if
120
179
_fs_enc = sys.getfilesystemencoding()
121
180
def abspath(path):
122
181
return os.path.abspath(path.encode(_fs_enc)).decode(_fs_enc)
123
183
def realpath(path):
124
184
return os.path.realpath(path.encode(_fs_enc)).decode(_fs_enc)
125
pathjoin = os.path.join
126
normpath = os.path.normpath
128
mkdtemp = tempfile.mkdtemp
186
if sys.platform == 'win32':
130
187
# We need to use the Unicode-aware os.path.abspath and
131
188
# os.path.realpath on Windows systems.
132
189
def abspath(path):
133
190
return os.path.abspath(path).replace('\\', '/')
134
192
def realpath(path):
135
193
return os.path.realpath(path).replace('\\', '/')
136
195
def pathjoin(*args):
137
196
return os.path.join(*args).replace('\\', '/')
138
198
def normpath(path):
139
199
return os.path.normpath(path).replace('\\', '/')
141
202
return os.getcwdu().replace('\\', '/')
142
204
def mkdtemp(*args, **kwargs):
143
205
return tempfile.mkdtemp(*args, **kwargs).replace('\\', '/')
144
# Because these shrink the path, we can use the original
145
# versions on any platform
146
dirname = os.path.dirname
147
basename = os.path.basename
207
def rename(old, new):
208
fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
149
210
def normalizepath(f):
150
211
if hasattr(os.path, 'realpath'):