Mercurial > public > mercurial-scm > hg
comparison mercurial/util.py @ 9549:8b8920209317
util: move rename into posix.py and windows.py
author | Adrian Buehlmann <adrian@cadifra.com> |
---|---|
date | Wed, 07 Oct 2009 20:32:07 +0200 |
parents | 7732606b0767 |
children | f0417b6ff98a |
comparison
equal
deleted
inserted
replaced
9548:7732606b0767 | 9549:8b8920209317 |
---|---|
14 """ | 14 """ |
15 | 15 |
16 from i18n import _ | 16 from i18n import _ |
17 import error, osutil, encoding | 17 import error, osutil, encoding |
18 import cStringIO, errno, re, shutil, sys, tempfile, traceback | 18 import cStringIO, errno, re, shutil, sys, tempfile, traceback |
19 import os, stat, time, calendar, random, textwrap | 19 import os, stat, time, calendar, textwrap |
20 import imp | 20 import imp |
21 | 21 |
22 # Python compatibility | 22 # Python compatibility |
23 | 23 |
24 def sha1(s): | 24 def sha1(s): |
397 os.lstat(filename) | 397 os.lstat(filename) |
398 except: | 398 except: |
399 return False | 399 return False |
400 return True | 400 return True |
401 | 401 |
402 def rename(src, dst): | |
403 '''atomically rename file src to dst, replacing dst if it exists''' | |
404 try: | |
405 os.rename(src, dst) | |
406 except OSError, err: # FIXME: check err (EEXIST ?) | |
407 | |
408 # On windows, rename to existing file is not allowed, so we | |
409 # must delete destination first. But if a file is open, unlink | |
410 # schedules it for delete but does not delete it. Rename | |
411 # happens immediately even for open files, so we rename | |
412 # destination to a temporary name, then delete that. Then | |
413 # rename is safe to do. | |
414 # The temporary name is chosen at random to avoid the situation | |
415 # where a file is left lying around from a previous aborted run. | |
416 # The usual race condition this introduces can't be avoided as | |
417 # we need the name to rename into, and not the file itself. Due | |
418 # to the nature of the operation however, any races will at worst | |
419 # lead to the rename failing and the current operation aborting. | |
420 | |
421 def tempname(prefix): | |
422 for tries in xrange(10): | |
423 temp = '%s-%08x' % (prefix, random.randint(0, 0xffffffff)) | |
424 if not os.path.exists(temp): | |
425 return temp | |
426 raise IOError, (errno.EEXIST, "No usable temporary filename found") | |
427 | |
428 temp = tempname(dst) | |
429 os.rename(dst, temp) | |
430 try: | |
431 os.unlink(temp) | |
432 except: | |
433 # Some rude AV-scanners on Windows may cause the unlink to | |
434 # fail. Not aborting here just leaks the temp file, whereas | |
435 # aborting at this point may leave serious inconsistencies. | |
436 # Ideally, we would notify the user here. | |
437 pass | |
438 os.rename(src, dst) | |
439 | |
440 def unlink(f): | 402 def unlink(f): |
441 """unlink and remove the directory if it is empty""" | 403 """unlink and remove the directory if it is empty""" |
442 os.unlink(f) | 404 os.unlink(f) |
443 # try removing directories that might now be empty | 405 # try removing directories that might now be empty |
444 try: | 406 try: |