util.py revision b8b263b92f33162d0b1bd35f44a17e5538b9713f
12689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward"""distutils.util
22689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
3aebf706b4e845d7525d2d8e792f0e23fcfb3e6afGreg WardMiscellaneous utility functions -- anything that doesn't fit into
4aebf706b4e845d7525d2d8e792f0e23fcfb3e6afGreg Wardone of the other *util.py modules."""
52689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
62689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward# created 1999/03/08, Greg Ward
72689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
83ce77fd05ed00168f618b63401d770ccc4f04b09Greg Ward__revision__ = "$Id$"
92689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
10a7540bd043622de917fdc929310e1b5ca214ab83Greg Wardimport sys, os, string, re, shutil
112689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Wardfrom distutils.errors import *
127c1a6d477771955e3773849ef636fceda81bb3d5Greg Wardfrom distutils.spawn import spawn
132689e3ddce70e8acc5bc231a80221980d5bdfec3Greg Ward
14aa458bc46500a2b135cad66a4fd66cac69b8be51Greg Ward
15585df89f60ceb2e0a5b690f12f19c14093faa6fcGreg Warddef get_platform ():
1659399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    """Return a string that identifies the current platform.  This is used
1759399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    mainly to distinguish platform-specific build directories and
1859399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    platform-specific built distributions.  Typically includes the OS name
1959399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    and version and the architecture (as supplied by 'os.uname()'),
2059399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    although the exact information included depends on the OS; eg. for IRIX
2159399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    the architecture isn't particularly important (IRIX only runs on SGI
2259399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    hardware), but for Linux the kernel version isn't particularly
2359399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    important.
2459399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward
2559399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    Examples of returned values:
2659399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward       linux-i586
2759399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward       linux-alpha (?)
2859399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward       solaris-2.6-sun4u
2959399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward       irix-5.3
3059399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward       irix64-6.2
3159399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward
3259399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    For non-POSIX platforms, currently just returns 'sys.platform'.
33b75c485f0bc6394f616d4a0bc746e613fd7b1021Greg Ward    """
34ec84c21ce2d022ea95bb67ab711f7580036611e5Greg Ward    if os.name != "posix" or not hasattr(os, 'uname'):
3559399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        # XXX what about the architecture? NT is Intel or Alpha,
3659399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        # Mac OS is M68k or PPC, etc.
3759399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        return sys.platform
3859399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward
3959399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    # Try to distinguish various flavours of Unix
4059399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward
4159399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    (osname, host, release, version, machine) = os.uname()
4259399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    osname = string.lower(osname)
4359399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    if osname[:5] == "linux":
4459399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        # At least on Linux/Intel, 'machine' is the processor --
4559399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        # i386, etc.
4659399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        # XXX what about Alpha, SPARC, etc?
4759399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        return  "%s-%s" % (osname, machine)
4859399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    elif osname[:5] == "sunos":
4959399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        if release[0] >= "5":           # SunOS 5 == Solaris 2
5059399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward            osname = "solaris"
5159399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward            release = "%d.%s" % (int(release[0]) - 3, release[2:])
5259399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        # fall through to standard osname-release-machine representation
5359399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    elif osname[:4] == "irix":              # could be "irix64"!
5459399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward        return "%s-%s" % (osname, release)
5559399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward
5659399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward    return "%s-%s-%s" % (osname, release, machine)
5759399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward
5859399bb303a51e781ab7943088fa1c4db1d41dcbGreg Ward# get_platform ()
595091929c2cf04bfbd545835d2435e43bda6afa05Greg Ward
605091929c2cf04bfbd545835d2435e43bda6afa05Greg Ward
61d8dfb4c4b8d661acee263e3feb77974ced69e97dGreg Warddef convert_path (pathname):
62b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    """Return 'pathname' as a name that will work on the native filesystem,
63b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    i.e. split it on '/' and put it back together again using the current
64b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    directory separator.  Needed because filenames in the setup script are
65b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    always supplied in Unix style, and have to be converted to the local
66b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    convention before we can actually use them in the filesystem.  Raises
67b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    ValueError if 'pathname' is absolute (starts with '/') or contains
68b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    local directory separators (unless the local separator is '/', of
69b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    course).
70b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    """
717ec053544cf4849a138e70329ffeec1d6ab93e62Greg Ward    if os.sep == '/':
727ec053544cf4849a138e70329ffeec1d6ab93e62Greg Ward        return pathname
735091929c2cf04bfbd545835d2435e43bda6afa05Greg Ward    if pathname[0] == '/':
7402a1a2b077e969e5fef8504cece5852bf641552dGreg Ward        raise ValueError, "path '%s' cannot be absolute" % pathname
755091929c2cf04bfbd545835d2435e43bda6afa05Greg Ward    if pathname[-1] == '/':
7602a1a2b077e969e5fef8504cece5852bf641552dGreg Ward        raise ValueError, "path '%s' cannot end with '/'" % pathname
777ec053544cf4849a138e70329ffeec1d6ab93e62Greg Ward
787ec053544cf4849a138e70329ffeec1d6ab93e62Greg Ward    paths = string.split(pathname, '/')
797ec053544cf4849a138e70329ffeec1d6ab93e62Greg Ward    return apply(os.path.join, paths)
805091929c2cf04bfbd545835d2435e43bda6afa05Greg Ward
81d8dfb4c4b8d661acee263e3feb77974ced69e97dGreg Ward# convert_path ()
821b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward
831b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward
8467f75d4bcb3630c0f5b6761fb758072cc342157eGreg Warddef change_root (new_root, pathname):
8567f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward    """Return 'pathname' with 'new_root' prepended.  If 'pathname' is
8667f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward    relative, this is equivalent to "os.path.join(new_root,pathname)".
8767f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward    Otherwise, it requires making 'pathname' relative and then joining the
884b46ef9a4f35c50eed2e0993058be0cfe71e0b3bGreg Ward    two, which is tricky on DOS/Windows and Mac OS.
894b46ef9a4f35c50eed2e0993058be0cfe71e0b3bGreg Ward    """
904b46ef9a4f35c50eed2e0993058be0cfe71e0b3bGreg Ward    if os.name == 'posix':
91be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward        if not os.path.isabs(pathname):
92be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward            return os.path.join(new_root, pathname)
934b46ef9a4f35c50eed2e0993058be0cfe71e0b3bGreg Ward        else:
94be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward            return os.path.join(new_root, pathname[1:])
9567f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward
9667f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward    elif os.name == 'nt':
97be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward        (drive, path) = os.path.splitdrive(pathname)
984b46ef9a4f35c50eed2e0993058be0cfe71e0b3bGreg Ward        if path[0] == '\\':
994b46ef9a4f35c50eed2e0993058be0cfe71e0b3bGreg Ward            path = path[1:]
100be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward        return os.path.join(new_root, path)
10167f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward
10267f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward    elif os.name == 'mac':
103f5855746fe0851e5a80b32061cb819021285ff25Greg Ward        if not os.path.isabs(pathname):
104f5855746fe0851e5a80b32061cb819021285ff25Greg Ward            return os.path.join(new_root, pathname)
105f5855746fe0851e5a80b32061cb819021285ff25Greg Ward        else:
106f5855746fe0851e5a80b32061cb819021285ff25Greg Ward            # Chop off volume name from start of path
107f5855746fe0851e5a80b32061cb819021285ff25Greg Ward            elements = string.split(pathname, ":", 1)
108f5855746fe0851e5a80b32061cb819021285ff25Greg Ward            pathname = ":" + elements[1]
109f5855746fe0851e5a80b32061cb819021285ff25Greg Ward            return os.path.join(new_root, pathname)
11067f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward
11167f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward    else:
11267f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward        raise DistutilsPlatformError, \
11367f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward              "nothing known about platform '%s'" % os.name
11467f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward
11567f75d4bcb3630c0f5b6761fb758072cc342157eGreg Ward
116e7e35ac1c2e3c6b6a0836931b5c678d6af17129cGregory P. Smith_environ_checked = 0
117e7e35ac1c2e3c6b6a0836931b5c678d6af17129cGregory P. Smithdef check_environ ():
1181b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward    """Ensure that 'os.environ' has all the environment variables we
119b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    guarantee that users can use in config files, command-line options,
120b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    etc.  Currently this includes:
121b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward      HOME - user's home directory (Unix only)
122b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward      PLAT - description of the current platform, including hardware
123b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward             and OS (see 'get_platform()')
1241b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward    """
125e7e35ac1c2e3c6b6a0836931b5c678d6af17129cGregory P. Smith    global _environ_checked
126e7e35ac1c2e3c6b6a0836931b5c678d6af17129cGregory P. Smith    if _environ_checked:
127e7e35ac1c2e3c6b6a0836931b5c678d6af17129cGregory P. Smith        return
128e7e35ac1c2e3c6b6a0836931b5c678d6af17129cGregory P. Smith
1291b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward    if os.name == 'posix' and not os.environ.has_key('HOME'):
1301b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward        import pwd
131be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward        os.environ['HOME'] = pwd.getpwuid(os.getuid())[5]
1321b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward
1331b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward    if not os.environ.has_key('PLAT'):
134be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward        os.environ['PLAT'] = get_platform()
1351b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward
136e7e35ac1c2e3c6b6a0836931b5c678d6af17129cGregory P. Smith    _environ_checked = 1
137e7e35ac1c2e3c6b6a0836931b5c678d6af17129cGregory P. Smith
1381b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward
1391b4ede5f24814dc4baa8832414093aa745c3755cGreg Warddef subst_vars (str, local_vars):
140b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    """Perform shell/Perl-style variable substitution on 'string'.  Every
141b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    occurrence of '$' followed by a name, or a name enclosed in braces, is
142b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    considered a variable.  Every variable is substituted by the value
143b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    found in the 'local_vars' dictionary, or in 'os.environ' if it's not in
144b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    'local_vars'.  'os.environ' is first checked/ augmented to guarantee
145b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    that it contains certain values: see '_check_environ()'.  Raise
146b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    ValueError for any variables not found in either 'local_vars' or
147b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    'os.environ'.
148b8b263b92f33162d0b1bd35f44a17e5538b9713fGreg Ward    """
149be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward    check_environ()
1501b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward    def _subst (match, local_vars=local_vars):
1511b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward        var_name = match.group(1)
152be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward        if local_vars.has_key(var_name):
153be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward            return str(local_vars[var_name])
1541b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward        else:
1551b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward            return os.environ[var_name]
1561b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward
157be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward    return re.sub(r'\$([a-zA-Z_][a-zA-Z_0-9]*)', _subst, str)
1581b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward
1591b4ede5f24814dc4baa8832414093aa745c3755cGreg Ward# subst_vars ()
1607c1a6d477771955e3773849ef636fceda81bb3d5Greg Ward
1617c1a6d477771955e3773849ef636fceda81bb3d5Greg Ward
162e905513be0718c5a8edafe70efc0fe0d4f290573Greg Warddef grok_environment_error (exc, prefix="error: "):
163e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    """Generate a useful error message from an EnvironmentError (IOError or
164e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    OSError) exception object.  Handles Python 1.5.1 and 1.5.2 styles, and
165e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    does what it can to deal with exception objects that don't have a
166e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    filename (which happens when the error is due to a two-file operation,
167e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    such as 'rename()' or 'link()'.  Returns the error message as a string
168e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    prefixed with 'prefix'.
169e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    """
170e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    # check for Python 1.5.2-style {IO,OS}Error exception objects
171be86bdea734bc53b25698ff5961183cbb5352ffdGreg Ward    if hasattr(exc, 'filename') and hasattr(exc, 'strerror'):
172e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward        if exc.filename:
173e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward            error = prefix + "%s: %s" % (exc.filename, exc.strerror)
174e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward        else:
175e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward            # two-argument functions in posix module don't
176e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward            # include the filename in the exception object!
177e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward            error = prefix + "%s" % exc.strerror
178e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    else:
179e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward        error = prefix + str(exc[-1])
180e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward
181e905513be0718c5a8edafe70efc0fe0d4f290573Greg Ward    return error
1826a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
1836a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
1846a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward# Needed by 'split_quoted()'
1852b042ded19bc7efa43551da297c29dc142b7d73cGreg Ward_wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace)
1866a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward_squote_re = re.compile(r"'(?:[^'\\]|\\.)*'")
1876a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward_dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"')
1886a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
1896a2a3dbec59f267e05c0c507457dfd234263237bGreg Warddef split_quoted (s):
1906a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    """Split a string up according to Unix shell-like rules for quotes and
1916a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    backslashes.  In short: words are delimited by spaces, as long as those
1926a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    spaces are not escaped by a backslash, or inside a quoted string.
1936a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    Single and double quotes are equivalent, and the quote characters can
1946a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    be backslash-escaped.  The backslash is stripped from any two-character
1956a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    escape sequence, leaving only the escaped character.  The quote
1966a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    characters are stripped from any quoted string.  Returns a list of
1976a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    words.
1986a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    """
1996a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2006a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    # This is a nice algorithm for splitting up a single string, since it
2016a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    # doesn't require character-by-character examination.  It was a little
2026a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    # bit of a brain-bender to get it working right, though...
2036a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2046a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    s = string.strip(s)
2056a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    words = []
2066a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    pos = 0
2076a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2086a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    while s:
2096a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward        m = _wordchars_re.match(s, pos)
2106a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward        end = m.end()
2116a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward        if end == len(s):
2126a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            words.append(s[:end])
2136a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            break
2146a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2152b042ded19bc7efa43551da297c29dc142b7d73cGreg Ward        if s[end] in string.whitespace: # unescaped, unquoted whitespace: now
2166a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            words.append(s[:end])       # we definitely have a word delimiter
2176a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            s = string.lstrip(s[end:])
2186a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            pos = 0
2196a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2206a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward        elif s[end] == '\\':            # preserve whatever is being escaped;
2216a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward                                        # will become part of the current word
2226a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            s = s[:end] + s[end+1:]
2236a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            pos = end+1
2246a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2256a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward        else:
2266a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            if s[end] == "'":           # slurp singly-quoted string
2276a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward                m = _squote_re.match(s, end)
2286a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            elif s[end] == '"':         # slurp doubly-quoted string
2296a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward                m = _dquote_re.match(s, end)
2306a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            else:
2316a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward                raise RuntimeError, \
2326a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward                      "this can't happen (bad char '%c')" % s[end]
2336a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2346a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            if m is None:
2356a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward                raise ValueError, \
2366a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward                      "bad string (mismatched %s quotes?)" % s[end]
2376a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2386a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            (beg, end) = m.span()
2396a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            s = s[:beg] + s[beg+1:end-1] + s[end:]
2406a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            pos = m.end() - 2
2416a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2426a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward        if pos >= len(s):
2436a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            words.append(s)
2446a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward            break
2456a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2466a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward    return words
2476a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward
2486a2a3dbec59f267e05c0c507457dfd234263237bGreg Ward# split_quoted ()
2491c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward
2501c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward
2511c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Warddef execute (func, args, msg=None, verbose=0, dry_run=0):
2521c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    """Perform some action that affects the outside world (eg.  by writing
2531c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    to the filesystem).  Such actions are special because they are disabled
2541c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    by the 'dry_run' flag, and announce themselves if 'verbose' is true.
2551c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    This method takes care of all that bureaucracy for you; all you have to
2561c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    do is supply the function to call and an argument tuple for it (to
2571c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    embody the "external action" being performed), and an optional message
2581c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    to print.
2591c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    """
2601c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    # Generate a message if we weren't passed one
2611c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    if msg is None:
2621c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward        msg = "%s%s" % (func.__name__, `args`)
2631c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward        if msg[-2:] == ',)':        # correct for singleton tuple
2641c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward            msg = msg[0:-2] + ')'
2651c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward
2661c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    # Print it if verbosity level is high enough
2671c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    if verbose:
2681c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward        print msg
2691c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward
2701c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    # And do it, as long as we're not in dry-run mode
2711c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward    if not dry_run:
2721c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward        apply(func, args)
2731c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward
2741c16ac360a3fc63bfb1008c3a935907fe9064f26Greg Ward# execute()
275817dc098efd0c2cba674cee32950fc5626e12881Greg Ward
276817dc098efd0c2cba674cee32950fc5626e12881Greg Ward
277817dc098efd0c2cba674cee32950fc5626e12881Greg Warddef strtobool (val):
278817dc098efd0c2cba674cee32950fc5626e12881Greg Ward    """Convert a string representation of truth to true (1) or false (0).
279817dc098efd0c2cba674cee32950fc5626e12881Greg Ward    True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
280817dc098efd0c2cba674cee32950fc5626e12881Greg Ward    are 'n', 'no', 'f', 'false', 'off', and '0'.  Raises ValueError if
281817dc098efd0c2cba674cee32950fc5626e12881Greg Ward    'val' is anything else.
282817dc098efd0c2cba674cee32950fc5626e12881Greg Ward    """
283817dc098efd0c2cba674cee32950fc5626e12881Greg Ward    val = string.lower(val)
284817dc098efd0c2cba674cee32950fc5626e12881Greg Ward    if val in ('y', 'yes', 't', 'true', 'on', '1'):
285817dc098efd0c2cba674cee32950fc5626e12881Greg Ward        return 1
286817dc098efd0c2cba674cee32950fc5626e12881Greg Ward    elif val in ('n', 'no', 'f', 'false', 'off', '0'):
287817dc098efd0c2cba674cee32950fc5626e12881Greg Ward        return 0
288817dc098efd0c2cba674cee32950fc5626e12881Greg Ward    else:
289817dc098efd0c2cba674cee32950fc5626e12881Greg Ward        raise ValueError, "invalid truth value %s" % `val`
290