mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			290 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			290 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""distutils.util
 | 
						|
 | 
						|
Miscellaneous utility functions -- anything that doesn't fit into
 | 
						|
one of the other *util.py modules."""
 | 
						|
 | 
						|
# created 1999/03/08, Greg Ward
 | 
						|
 | 
						|
__revision__ = "$Id$"
 | 
						|
 | 
						|
import sys, os, string, re, shutil
 | 
						|
from distutils.errors import *
 | 
						|
from distutils.spawn import spawn
 | 
						|
 | 
						|
 | 
						|
def get_platform ():
 | 
						|
    """Return a string that identifies the current platform.  This is used
 | 
						|
    mainly to distinguish platform-specific build directories and
 | 
						|
    platform-specific built distributions.  Typically includes the OS name
 | 
						|
    and version and the architecture (as supplied by 'os.uname()'),
 | 
						|
    although the exact information included depends on the OS; eg. for IRIX
 | 
						|
    the architecture isn't particularly important (IRIX only runs on SGI
 | 
						|
    hardware), but for Linux the kernel version isn't particularly
 | 
						|
    important.
 | 
						|
 | 
						|
    Examples of returned values:
 | 
						|
       linux-i586
 | 
						|
       linux-alpha (?)
 | 
						|
       solaris-2.6-sun4u
 | 
						|
       irix-5.3
 | 
						|
       irix64-6.2
 | 
						|
       
 | 
						|
    For non-POSIX platforms, currently just returns 'sys.platform'.
 | 
						|
    """
 | 
						|
    if os.name != "posix":
 | 
						|
        # XXX what about the architecture? NT is Intel or Alpha,
 | 
						|
        # Mac OS is M68k or PPC, etc.
 | 
						|
        return sys.platform
 | 
						|
 | 
						|
    # Try to distinguish various flavours of Unix
 | 
						|
 | 
						|
    (osname, host, release, version, machine) = os.uname()
 | 
						|
    osname = string.lower(osname)
 | 
						|
    if osname[:5] == "linux":
 | 
						|
        # At least on Linux/Intel, 'machine' is the processor --
 | 
						|
        # i386, etc.
 | 
						|
        # XXX what about Alpha, SPARC, etc?
 | 
						|
        return  "%s-%s" % (osname, machine)
 | 
						|
    elif osname[:5] == "sunos":
 | 
						|
        if release[0] >= "5":           # SunOS 5 == Solaris 2
 | 
						|
            osname = "solaris"
 | 
						|
            release = "%d.%s" % (int(release[0]) - 3, release[2:])
 | 
						|
        # fall through to standard osname-release-machine representation
 | 
						|
    elif osname[:4] == "irix":              # could be "irix64"!
 | 
						|
        return "%s-%s" % (osname, release)
 | 
						|
            
 | 
						|
    return "%s-%s-%s" % (osname, release, machine)
 | 
						|
 | 
						|
# get_platform ()
 | 
						|
 | 
						|
 | 
						|
def convert_path (pathname):
 | 
						|
    """Return 'pathname' as a name that will work on the native
 | 
						|
       filesystem, i.e. split it on '/' and put it back together again
 | 
						|
       using the current directory separator.  Needed because filenames in
 | 
						|
       the setup script are always supplied in Unix style, and have to be
 | 
						|
       converted to the local convention before we can actually use them in
 | 
						|
       the filesystem.  Raises ValueError if 'pathname' is
 | 
						|
       absolute (starts with '/') or contains local directory separators
 | 
						|
       (unless the local separator is '/', of course)."""
 | 
						|
 | 
						|
    if os.sep == '/':
 | 
						|
        return pathname
 | 
						|
    if pathname[0] == '/':
 | 
						|
        raise ValueError, "path '%s' cannot be absolute" % pathname
 | 
						|
    if pathname[-1] == '/':
 | 
						|
        raise ValueError, "path '%s' cannot end with '/'" % pathname
 | 
						|
 | 
						|
    paths = string.split(pathname, '/')
 | 
						|
    return apply(os.path.join, paths)
 | 
						|
 | 
						|
# convert_path ()
 | 
						|
 | 
						|
 | 
						|
def change_root (new_root, pathname):
 | 
						|
    """Return 'pathname' with 'new_root' prepended.  If 'pathname' is
 | 
						|
    relative, this is equivalent to "os.path.join(new_root,pathname)".
 | 
						|
    Otherwise, it requires making 'pathname' relative and then joining the
 | 
						|
    two, which is tricky on DOS/Windows and Mac OS.
 | 
						|
    """
 | 
						|
    if os.name == 'posix':
 | 
						|
        if not os.path.isabs (pathname):
 | 
						|
            return os.path.join (new_root, pathname)
 | 
						|
        else:
 | 
						|
            return os.path.join (new_root, pathname[1:])
 | 
						|
 | 
						|
    elif os.name == 'nt':
 | 
						|
        (drive, path) = os.path.splitdrive (pathname)
 | 
						|
        if path[0] == '\\':
 | 
						|
            path = path[1:]
 | 
						|
        return os.path.join (new_root, path)
 | 
						|
 | 
						|
    elif os.name == 'mac':
 | 
						|
        if not os.path.isabs(pathname):
 | 
						|
            return os.path.join(new_root, pathname)
 | 
						|
        else:
 | 
						|
            # Chop off volume name from start of path
 | 
						|
            elements = string.split(pathname, ":", 1)
 | 
						|
            pathname = ":" + elements[1]
 | 
						|
            return os.path.join(new_root, pathname)
 | 
						|
 | 
						|
    else:
 | 
						|
        raise DistutilsPlatformError, \
 | 
						|
              "nothing known about platform '%s'" % os.name
 | 
						|
 | 
						|
 | 
						|
_environ_checked = 0
 | 
						|
def check_environ ():
 | 
						|
    """Ensure that 'os.environ' has all the environment variables we
 | 
						|
       guarantee that users can use in config files, command-line
 | 
						|
       options, etc.  Currently this includes:
 | 
						|
         HOME - user's home directory (Unix only)
 | 
						|
         PLAT - description of the current platform, including hardware
 | 
						|
                and OS (see 'get_platform()')
 | 
						|
    """
 | 
						|
 | 
						|
    global _environ_checked
 | 
						|
    if _environ_checked:
 | 
						|
        return
 | 
						|
 | 
						|
    if os.name == 'posix' and not os.environ.has_key('HOME'):
 | 
						|
        import pwd
 | 
						|
        os.environ['HOME'] = pwd.getpwuid (os.getuid())[5]
 | 
						|
 | 
						|
    if not os.environ.has_key('PLAT'):
 | 
						|
        os.environ['PLAT'] = get_platform ()
 | 
						|
 | 
						|
    _environ_checked = 1
 | 
						|
 | 
						|
 | 
						|
def subst_vars (str, local_vars):
 | 
						|
    """Perform shell/Perl-style variable substitution on 'string'.
 | 
						|
       Every occurrence of '$' followed by a name, or a name enclosed in
 | 
						|
       braces, is considered a variable.  Every variable is substituted by
 | 
						|
       the value found in the 'local_vars' dictionary, or in 'os.environ'
 | 
						|
       if it's not in 'local_vars'.  'os.environ' is first checked/
 | 
						|
       augmented to guarantee that it contains certain values: see
 | 
						|
       '_check_environ()'.  Raise ValueError for any variables not found in
 | 
						|
       either 'local_vars' or 'os.environ'."""
 | 
						|
 | 
						|
    check_environ ()
 | 
						|
    def _subst (match, local_vars=local_vars):
 | 
						|
        var_name = match.group(1)
 | 
						|
        if local_vars.has_key (var_name):
 | 
						|
            return str (local_vars[var_name])
 | 
						|
        else:
 | 
						|
            return os.environ[var_name]
 | 
						|
 | 
						|
    return re.sub (r'\$([a-zA-Z_][a-zA-Z_0-9]*)', _subst, str)
 | 
						|
 | 
						|
# subst_vars ()
 | 
						|
 | 
						|
 | 
						|
def grok_environment_error (exc, prefix="error: "):
 | 
						|
    """Generate a useful error message from an EnvironmentError (IOError or
 | 
						|
    OSError) exception object.  Handles Python 1.5.1 and 1.5.2 styles, and
 | 
						|
    does what it can to deal with exception objects that don't have a
 | 
						|
    filename (which happens when the error is due to a two-file operation,
 | 
						|
    such as 'rename()' or 'link()'.  Returns the error message as a string
 | 
						|
    prefixed with 'prefix'.
 | 
						|
    """
 | 
						|
    # check for Python 1.5.2-style {IO,OS}Error exception objects
 | 
						|
    if hasattr (exc, 'filename') and hasattr (exc, 'strerror'):
 | 
						|
        if exc.filename:
 | 
						|
            error = prefix + "%s: %s" % (exc.filename, exc.strerror)
 | 
						|
        else:
 | 
						|
            # two-argument functions in posix module don't
 | 
						|
            # include the filename in the exception object!
 | 
						|
            error = prefix + "%s" % exc.strerror
 | 
						|
    else:
 | 
						|
        error = prefix + str(exc[-1])
 | 
						|
 | 
						|
    return error
 | 
						|
 | 
						|
 | 
						|
# Needed by 'split_quoted()'
 | 
						|
_wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace)
 | 
						|
_squote_re = re.compile(r"'(?:[^'\\]|\\.)*'")
 | 
						|
_dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"')
 | 
						|
 | 
						|
def split_quoted (s):
 | 
						|
    """Split a string up according to Unix shell-like rules for quotes and
 | 
						|
    backslashes.  In short: words are delimited by spaces, as long as those
 | 
						|
    spaces are not escaped by a backslash, or inside a quoted string.
 | 
						|
    Single and double quotes are equivalent, and the quote characters can
 | 
						|
    be backslash-escaped.  The backslash is stripped from any two-character
 | 
						|
    escape sequence, leaving only the escaped character.  The quote
 | 
						|
    characters are stripped from any quoted string.  Returns a list of
 | 
						|
    words.
 | 
						|
    """
 | 
						|
 | 
						|
    # This is a nice algorithm for splitting up a single string, since it
 | 
						|
    # doesn't require character-by-character examination.  It was a little
 | 
						|
    # bit of a brain-bender to get it working right, though...
 | 
						|
 | 
						|
    s = string.strip(s)
 | 
						|
    words = []
 | 
						|
    pos = 0
 | 
						|
 | 
						|
    while s:
 | 
						|
        m = _wordchars_re.match(s, pos)
 | 
						|
        end = m.end()
 | 
						|
        if end == len(s):
 | 
						|
            words.append(s[:end])
 | 
						|
            break
 | 
						|
 | 
						|
        if s[end] in string.whitespace: # unescaped, unquoted whitespace: now
 | 
						|
            words.append(s[:end])       # we definitely have a word delimiter
 | 
						|
            s = string.lstrip(s[end:])
 | 
						|
            pos = 0
 | 
						|
 | 
						|
        elif s[end] == '\\':            # preserve whatever is being escaped;
 | 
						|
                                        # will become part of the current word
 | 
						|
            s = s[:end] + s[end+1:]
 | 
						|
            pos = end+1
 | 
						|
 | 
						|
        else:
 | 
						|
            if s[end] == "'":           # slurp singly-quoted string
 | 
						|
                m = _squote_re.match(s, end)
 | 
						|
            elif s[end] == '"':         # slurp doubly-quoted string
 | 
						|
                m = _dquote_re.match(s, end)
 | 
						|
            else:
 | 
						|
                raise RuntimeError, \
 | 
						|
                      "this can't happen (bad char '%c')" % s[end]
 | 
						|
 | 
						|
            if m is None:
 | 
						|
                raise ValueError, \
 | 
						|
                      "bad string (mismatched %s quotes?)" % s[end]
 | 
						|
 | 
						|
            (beg, end) = m.span()
 | 
						|
            s = s[:beg] + s[beg+1:end-1] + s[end:]
 | 
						|
            pos = m.end() - 2
 | 
						|
 | 
						|
        if pos >= len(s):
 | 
						|
            words.append(s)
 | 
						|
            break
 | 
						|
 | 
						|
    return words
 | 
						|
 | 
						|
# split_quoted ()
 | 
						|
 | 
						|
 | 
						|
def execute (func, args, msg=None, verbose=0, dry_run=0):
 | 
						|
    """Perform some action that affects the outside world (eg.  by writing
 | 
						|
    to the filesystem).  Such actions are special because they are disabled
 | 
						|
    by the 'dry_run' flag, and announce themselves if 'verbose' is true.
 | 
						|
    This method takes care of all that bureaucracy for you; all you have to
 | 
						|
    do is supply the function to call and an argument tuple for it (to
 | 
						|
    embody the "external action" being performed), and an optional message
 | 
						|
    to print.
 | 
						|
    """
 | 
						|
    # Generate a message if we weren't passed one
 | 
						|
    if msg is None:
 | 
						|
        msg = "%s%s" % (func.__name__, `args`)
 | 
						|
        if msg[-2:] == ',)':        # correct for singleton tuple 
 | 
						|
            msg = msg[0:-2] + ')'
 | 
						|
 | 
						|
    # Print it if verbosity level is high enough
 | 
						|
    if verbose:
 | 
						|
        print msg
 | 
						|
 | 
						|
    # And do it, as long as we're not in dry-run mode
 | 
						|
    if not dry_run:
 | 
						|
        apply(func, args)
 | 
						|
 | 
						|
# execute()
 | 
						|
 | 
						|
 | 
						|
def strtobool (val):
 | 
						|
    """Convert a string representation of truth to true (1) or false (0).
 | 
						|
    True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
 | 
						|
    are 'n', 'no', 'f', 'false', 'off', and '0'.  Raises ValueError if
 | 
						|
    'val' is anything else.
 | 
						|
    """
 | 
						|
    val = string.lower(val)
 | 
						|
    if val in ('y', 'yes', 't', 'true', 'on', '1'):
 | 
						|
        return 1
 | 
						|
    elif val in ('n', 'no', 'f', 'false', 'off', '0'):
 | 
						|
        return 0
 | 
						|
    else:
 | 
						|
        raise ValueError, "invalid truth value %s" % `val`
 |