mercurial/util.py
author mpm@selenic.com
Thu, 30 Jun 2005 10:07:50 -0800
changeset 535 fba26990604a
parent 521 0fb8ade0f756
child 556 f6c6fa15ff70
permissions -rw-r--r--
Deal with failed clone/transaction interaction -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Deal with failed clone/transaction interaction > What is happening is that something in the transaction machinery is > causing the directory to be completely recreated. The transaction gets rolled back by its destructor. This is critical so it happens whenever an exception occurs that unwinds the stack. Unfortunately, what's happening with clone is we're trying to delete the directory during exception propagation. And a reference to the transaction is held in the exception backtrace stack frames so it still exists until the exception is completely resolved. So there's no way to do the directory delete inside the exception handling cleanly. But we can handle it similarly to the transaction itself: use an object with a destructor. manifest hash: fc38550a20d64d08333f256bbedc312493c1390b -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQFCxDT2ywK+sNU5EO8RAjikAJ0Tej56rAutxQDfYzVbFGtT1sEC5ACgmVds /fwdQyHn+FwshugqXLemUaM= =3f78 -----END PGP SIGNATURE-----
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
419
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
     1
# util.py - utility functions and platform specfic implementations
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
     2
#
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
     3
# Copyright 2005 K. Thananchayan <thananck@yahoo.com>
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
     4
#
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
     5
# This software may be used and distributed according to the terms
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
     6
# of the GNU General Public License, incorporated herein by reference.
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
     7
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
     8
import os
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
     9
508
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    10
class CommandError(Exception): pass
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    11
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    12
def explain_exit(code):
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    13
    """return a 2-tuple (desc, code) describing a process's status"""
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    14
    if os.WIFEXITED(code):
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    15
        val = os.WEXITSTATUS(code)
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    16
        return "exited with status %d" % val, val
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    17
    elif os.WIFSIGNALED(code):
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    18
        val = os.WTERMSIG(code)
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    19
        return "killed by signal %d" % val, val
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    20
    elif os.WIFSTOPPED(code):
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    21
        val = os.STOPSIG(code)
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    22
        return "stopped by signal %d" % val, val
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    23
    raise ValueError("invalid exit code")
515
03f27b1381f9 Whitespace cleanups
mpm@selenic.com
parents: 508
diff changeset
    24
521
0fb8ade0f756 [PATCH] Fix use of util.CommandError
mpm@selenic.com
parents: 515
diff changeset
    25
def system(cmd, errprefix=None):
508
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    26
    """execute a shell command that must succeed"""
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    27
    rc = os.system(cmd)
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    28
    if rc:
521
0fb8ade0f756 [PATCH] Fix use of util.CommandError
mpm@selenic.com
parents: 515
diff changeset
    29
        errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]),
0fb8ade0f756 [PATCH] Fix use of util.CommandError
mpm@selenic.com
parents: 515
diff changeset
    30
                            explain_exit(rc)[0])
0fb8ade0f756 [PATCH] Fix use of util.CommandError
mpm@selenic.com
parents: 515
diff changeset
    31
        if errprefix:
0fb8ade0f756 [PATCH] Fix use of util.CommandError
mpm@selenic.com
parents: 515
diff changeset
    32
            errmsg = "%s: %s" % (errprefix, errmsg)
508
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    33
        raise CommandError(errmsg)
42a660abaf75 [PATCH] Harden os.system
mpm@selenic.com
parents: 464
diff changeset
    34
421
43b8da7420a9 [PATCH] rename under the other OS
mpm@selenic.com
parents: 419
diff changeset
    35
def rename(src, dst):
43b8da7420a9 [PATCH] rename under the other OS
mpm@selenic.com
parents: 419
diff changeset
    36
    try:
43b8da7420a9 [PATCH] rename under the other OS
mpm@selenic.com
parents: 419
diff changeset
    37
        os.rename(src, dst)
43b8da7420a9 [PATCH] rename under the other OS
mpm@selenic.com
parents: 419
diff changeset
    38
    except:
43b8da7420a9 [PATCH] rename under the other OS
mpm@selenic.com
parents: 419
diff changeset
    39
        os.unlink(dst)
43b8da7420a9 [PATCH] rename under the other OS
mpm@selenic.com
parents: 419
diff changeset
    40
        os.rename(src, dst)
43b8da7420a9 [PATCH] rename under the other OS
mpm@selenic.com
parents: 419
diff changeset
    41
43b8da7420a9 [PATCH] rename under the other OS
mpm@selenic.com
parents: 419
diff changeset
    42
# Platfor specific varients
419
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
    43
if os.name == 'nt':
461
9ae0034f2772 [PATCH] /dev/null for other OS
mpm@selenic.com
parents: 441
diff changeset
    44
    nulldev = 'NUL:'
9ae0034f2772 [PATCH] /dev/null for other OS
mpm@selenic.com
parents: 441
diff changeset
    45
441
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    46
    def is_exec(f, last):
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    47
        return last
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    48
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    49
    def set_exec(f, mode):
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    50
        pass
515
03f27b1381f9 Whitespace cleanups
mpm@selenic.com
parents: 508
diff changeset
    51
419
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
    52
    def pconvert(path):
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
    53
        return path.replace("\\", "/")
422
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    54
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    55
    def makelock(info, pathname):
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    56
        ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    57
        os.write(ld, info)
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    58
        os.close(ld)
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    59
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    60
    def readlock(pathname):
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    61
        return file(pathname).read()
461
9ae0034f2772 [PATCH] /dev/null for other OS
mpm@selenic.com
parents: 441
diff changeset
    62
419
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
    63
else:
461
9ae0034f2772 [PATCH] /dev/null for other OS
mpm@selenic.com
parents: 441
diff changeset
    64
    nulldev = '/dev/null'
9ae0034f2772 [PATCH] /dev/null for other OS
mpm@selenic.com
parents: 441
diff changeset
    65
441
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    66
    def is_exec(f, last):
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    67
        return (os.stat(f).st_mode & 0100 != 0)
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    68
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    69
    def set_exec(f, mode):
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    70
        s = os.stat(f).st_mode
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    71
        if (s & 0100 != 0) == mode:
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    72
            return
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    73
        if mode:
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    74
            # Turn on +x for every +r bit when making a file executable
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    75
            # and obey umask.
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    76
            umask = os.umask(0)
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    77
            os.umask(umask)
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    78
            os.chmod(f, s | (s & 0444) >> 2 & ~umask)
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    79
        else:
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    80
            os.chmod(f, s & 0666)
e8af362cfb01 Permission handling for the other OS
mpm@selenic.com
parents: 422
diff changeset
    81
419
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
    82
    def pconvert(path):
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
    83
        return path
28511fc21073 [PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
diff changeset
    84
422
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    85
    def makelock(info, pathname):
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    86
        os.symlink(info, pathname)
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    87
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    88
    def readlock(pathname):
10c43444a38e [PATCH] Enables lock work under the other 'OS'
mpm@selenic.com
parents: 421
diff changeset
    89
        return os.readlink(pathname)