Example #1
0
def gvar_names(name_filter = lambda x : True, categories = None):
    """Return list of GVar names

    :Parameters:
        name_filter : callable
            callable object (e.g. lambda) of type ``name_filter(name) ->
            boolean`` used to filter-out unwanted variables; only these
            variables are processed, for which name_filter returns ``True``
        categories : string
            return only variable names for given categories, it may be
            ``'programs'`` for variables representing programs (``CC``, ``CXX``
            and such), ``'flags'`` for variables representing program flags
            (``CFLAGS``, ``CCFLAGS`` etc.) or ``None`` (default) to not filter
            by categories.
    :Returns:
        the list of standard GNU directory variable names
    """
    if is_Sequence(name_filter):
        seq = name_filter
        name_filter = lambda x : x in seq
    if categories and not is_Sequence(categories):
        categories = [ categories ]
    if categories:
        lst = []
        if 'programs' in categories:
            lst.extend(__prog_var_tuples)
        if 'flags' in categories:
            lst.extend(__flag_var_tuples)
    else:
        lst = __prog_var_tuples + __flag_var_tuples
    return filter(name_filter, zip(*lst)[0])
Example #2
0
def _action(target, source, env):

    # prepare the line separator
    linesep = env['LINESEPARATOR']
    if linesep is None:
        linesep = LINESEP  # os.linesep
    elif is_String(linesep):
        pass
    elif isinstance(linesep, Value):
        linesep = linesep.get_text_contents()
    else:
        raise SCons.Errors.UserError(
            'unexpected type/class for LINESEPARATOR: %s' % repr(linesep),
            None)

    if 'b' in TEXTFILE_FILE_WRITE_MODE:
        linesep = to_bytes(linesep)

    # create a dictionary to use for the substitutions
    if 'SUBST_DICT' not in env:
        subs = None  # no substitutions
    else:
        subst_dict = env['SUBST_DICT']
        if is_Dict(subst_dict):
            subst_dict = list(subst_dict.items())
        elif is_Sequence(subst_dict):
            pass
        else:
            raise SCons.Errors.UserError('SUBST_DICT must be dict or sequence')
        subs = []
        for (k, value) in subst_dict:
            if callable(value):
                value = value()
            if is_String(value):
                value = env.subst(value)
            else:
                value = str(value)
            subs.append((k, value))

    # write the file
    try:
        if SCons.Util.PY3:
            target_file = open(target[0].get_path(),
                               TEXTFILE_FILE_WRITE_MODE,
                               newline='',
                               encoding="utf8")
        else:
            target_file = open(target[0].get_path(), TEXTFILE_FILE_WRITE_MODE)
    except (OSError, IOError):
        raise SCons.Errors.UserError("Can't write target file %s" % target[0])

    # separate lines by 'linesep' only if linesep is not empty
    lsep = None
    for line in source:
        if lsep:
            target_file.write(lsep)

        target_file.write(_do_subst(line, subs))
        lsep = linesep
    target_file.close()
Example #3
0
 def sub_match(match, val=val, matchlist=matchlist):
     a = match.group(1)
     if a in matchlist:
         a = val
     if is_Sequence(a):
         return ' '.join(map(str, a))
     else:
         return str(a)
Example #4
0
def _convert_list_R(newlist, sources):
    for elem in sources:
        if is_Sequence(elem):
            _convert_list_R(newlist, elem)
        elif isinstance(elem, Node):
            newlist.append(elem)
        else:
            newlist.append(Value(elem))
Example #5
0
def scons_subst_once(strSubst, env, key):
    """Perform single (non-recursive) substitution of a single
    construction variable keyword.

    This is used when setting a variable when copying or overriding values
    in an Environment.  We want to capture (expand) the old value before
    we override it, so people can do things like:

        env2 = env.Clone(CCFLAGS = '$CCFLAGS -g')

    We do this with some straightforward, brute-force code here...
    """
    if isinstance(strSubst, str) and strSubst.find('$') < 0:
        return strSubst

    matchlist = ['$' + key, '${' + key + '}']
    val = env.get(key, '')

    def sub_match(match, val=val, matchlist=matchlist):
        a = match.group(1)
        if a in matchlist:
            a = val
        if is_Sequence(a):
            return ' '.join(map(str, a))
        else:
            return str(a)

    if is_Sequence(strSubst):
        result = []
        for arg in strSubst:
            if is_String(arg):
                if arg in matchlist:
                    arg = val
                    if is_Sequence(arg):
                        result.extend(arg)
                    else:
                        result.append(arg)
                else:
                    result.append(_dollar_exps.sub(sub_match, arg))
            else:
                result.append(arg)
        return result
    elif is_String(strSubst):
        return _dollar_exps.sub(sub_match, strSubst)
    else:
        return strSubst
Example #6
0
 def sub_match(match, val=val, matchlist=matchlist):
     a = match.group(1)
     if a in matchlist:
         a = val
     if is_Sequence(a):
         return ' '.join(map(str, a))
     else:
         return str(a)
Example #7
0
def scons_subst_once(strSubst, env, key):
    """Perform single (non-recursive) substitution of a single
    construction variable keyword.

    This is used when setting a variable when copying or overriding values
    in an Environment.  We want to capture (expand) the old value before
    we override it, so people can do things like:

        env2 = env.Clone(CCFLAGS = '$CCFLAGS -g')

    We do this with some straightforward, brute-force code here...
    """
    if type(strSubst) == types.StringType and string.find(strSubst, "$") < 0:
        return strSubst

    matchlist = ["$" + key, "${" + key + "}"]
    val = env.get(key, "")

    def sub_match(match, val=val, matchlist=matchlist):
        a = match.group(1)
        if a in matchlist:
            a = val
        if is_Sequence(a):
            return string.join(map(str, a))
        else:
            return str(a)

    if is_Sequence(strSubst):
        result = []
        for arg in strSubst:
            if is_String(arg):
                if arg in matchlist:
                    arg = val
                    if is_Sequence(arg):
                        result.extend(arg)
                    else:
                        result.append(arg)
                else:
                    result.append(_dollar_exps.sub(sub_match, arg))
            else:
                result.append(arg)
        return result
    elif is_String(strSubst):
        return _dollar_exps.sub(sub_match, strSubst)
    else:
        return strSubst
Example #8
0
def _convert_list_R(newlist, sources):
    for elem in sources:
        if is_Sequence(elem):
            _convert_list_R(newlist, elem)
        elif isinstance(elem, Node):
            newlist.append(elem)
        else:
            newlist.append(Value(elem))
Example #9
0
def _action(target, source, env):

    # prepare the line separator
    linesep = env['LINESEPARATOR']
    if linesep is None:
        linesep = LINESEP # os.linesep
    elif is_String(linesep):
        pass
    elif isinstance(linesep, Value):
        linesep = linesep.get_text_contents()
    else:
        raise SCons.Errors.UserError('unexpected type/class for LINESEPARATOR: %s'
                                     % repr(linesep), None)

    if 'b' in TEXTFILE_FILE_WRITE_MODE:
        linesep = to_bytes(linesep)

    # create a dictionary to use for the substitutions
    if 'SUBST_DICT' not in env:
        subs = None    # no substitutions
    else:
        subst_dict = env['SUBST_DICT']
        if is_Dict(subst_dict):
            subst_dict = list(subst_dict.items())
        elif is_Sequence(subst_dict):
            pass
        else:
            raise SCons.Errors.UserError('SUBST_DICT must be dict or sequence')
        subs = []
        for (k, value) in subst_dict:
            if callable(value):
                value = value()
            if is_String(value):
                value = env.subst(value)
            else:
                value = str(value)
            subs.append((k, value))

    # write the file
    try:
        if SCons.Util.PY3:
            target_file = open(target[0].get_path(), TEXTFILE_FILE_WRITE_MODE, newline='')
        else:
            target_file = open(target[0].get_path(), TEXTFILE_FILE_WRITE_MODE)
    except (OSError, IOError):
        raise SCons.Errors.UserError("Can't write target file %s" % target[0])

    # separate lines by 'linesep' only if linesep is not empty
    lsep = None
    for line in source:
        if lsep:
            target_file.write(lsep)

        target_file.write(_do_subst(line, subs))
        lsep = linesep
    target_file.close()
Example #10
0
 def _gen_nodelist(self):
     mylist = self.list
     if mylist is None:
         mylist = []
     elif not is_Sequence(mylist):
         mylist = [mylist]
     # The map(self.func) call is what actually turns
     # a list into appropriate proxies.
     self.nodelist = SCons.Util.NodeList(list(map(self.func, mylist)))
     self._create_nodelist = self._return_nodelist
     return self.nodelist
Example #11
0
 def _gen_nodelist(self):
     mylist = self.list
     if mylist is None:
         mylist = []
     elif not is_Sequence(mylist):
         mylist = [mylist]
     # The map(self.func) call is what actually turns
     # a list into appropriate proxies.
     self.nodelist = SCons.Util.NodeList(list(map(self.func, mylist)))
     self._create_nodelist = self._return_nodelist
     return self.nodelist
Example #12
0
def declare_gvars(defaults = {}, name_filter=lambda x : True,
                  env_key_transform=default_env_key_transform,
                  var_key_transform=default_var_key_transform):
    """Return the variables representing particular programs as
    ``GVar`` variable declarations `_GVarDecls` (see `SConsGnu.GVars`).

    :Parameters:
        defaults : dict
            User-specified default values for the GVars being declared. You'll
            usually put your SCons Environment object env here.
        name_filter : callable
            callable object (e.g. lambda) of type ``name_filter(name) ->
            boolean`` used to filter-out unwanted variables; only these
            variables are processed, for which name_filter returns ``True``
        env_key_transform : callable
            function or lambda used to transform canonical ``GVar`` names to
            keys used for corresponding construction variables in a SCons
            environment (default: `default_env_key_transform`)
        var_key_transform : callable
            function of lambda used to trasform canonical ``GVar`` names to
            keys used for corresponding SCons command-line variables
            ``variable=value`` (default: `default_var_key_transform`)
    :Returns:
        a dictionary-like object of type `SConsGnu.GVar._GVarDecls`
    """
    from SCons.Variables.PathVariable import PathVariable
    from SConsGnu.GVars import GVarDeclsU, _undef
    def _prog_callback(name, desc, default = _undef):
        try:
            default = defaults[name]
        except KeyError:
            pass
        decl = { 'env_key'  : env_key_transform(name),
                 'var_key'  : var_key_transform(name),
                 'default'  : default,
                 'help'     : desc }
        return name, decl
    def _flag_callback(name, desc, default = _undef):
        try:
            default = defaults[name]
        except KeyError:
            pass
        decl = { 'env_key'  : env_key_transform(name),
                 'var_key'  : var_key_transform(name),
                 'default'  : default,
                 'converter': _flag_converter,
                 'help'     : desc }
        return name, decl

    if is_Sequence(name_filter):
        seq = name_filter
        name_filter = lambda x : x in seq
    return GVarDeclsU( __map_prog_var_tuples(_prog_callback, name_filter)
                     + __map_flag_var_tuples(_flag_callback, name_filter) )
Example #13
0
def _action(target, source, env):
    # prepare the line separator
    linesep = env['LINESEPARATOR']
    if linesep is None:
        linesep = os.linesep
    elif is_String(linesep):
        pass
    elif isinstance(linesep, Value):
        linesep = linesep.get_text_contents()
    else:
        raise SCons.Errors.UserError(
                           'unexpected type/class for LINESEPARATOR: %s'
                                         % repr(linesep), None)

    # create a dictionary to use for the substitutions
    if 'SUBST_DICT' not in env:
        subs = None    # no substitutions
    else:
        d = env['SUBST_DICT']
        if is_Dict(d):
            d = list(d.items())
        elif is_Sequence(d):
            pass
        else:
            raise SCons.Errors.UserError('SUBST_DICT must be dict or sequence')
        subs = []
        for (k,v) in d:
            if callable(v):
                v = v()
            if is_String(v):
                v = env.subst(v)
            else:
                v = str(v)
            subs.append((k,v))

    # write the file
    try:
        fd = open(target[0].get_path(), "wb")
    except (OSError, IOError, e):
        raise SCons.Errors.UserError("Can't write target file %s" % target[0])
    # separate lines by 'linesep' only if linesep is not empty
    lsep = None
    for s in source:
        if lsep: fd.write(lsep)
        fd.write(_do_subst(s, subs))
        lsep = linesep
    fd.close()
Example #14
0
def _action(target, source, env):
    # prepare the line separator
    linesep = env['LINESEPARATOR']
    if linesep is None:
        linesep = os.linesep
    elif is_String(linesep):
        pass
    elif isinstance(linesep, Value):
        linesep = linesep.get_text_contents()
    else:
        raise SCons.Errors.UserError(
            'unexpected type/class for LINESEPARATOR: %s' % repr(linesep),
            None)

    # create a dictionary to use for the substitutions
    if 'SUBST_DICT' not in env:
        subs = None  # no substitutions
    else:
        d = env['SUBST_DICT']
        if is_Dict(d):
            d = list(d.items())
        elif is_Sequence(d):
            pass
        else:
            raise SCons.Errors.UserError('SUBST_DICT must be dict or sequence')
        subs = []
        for (k, v) in d:
            if callable(v):
                v = v()
            if is_String(v):
                v = env.subst(v)
            else:
                v = str(v)
            subs.append((k, v))

    # write the file
    try:
        fd = open(target[0].get_path(), "wb")
    except (OSError, IOError) as e:
        raise SCons.Errors.UserError("Can't write target file %s" % target[0])
    # separate lines by 'linesep' only if linesep is not empty
    lsep = None
    for s in source:
        if lsep: fd.write(lsep)
        fd.write(_do_subst(s, subs))
        lsep = linesep
    fd.close()
Example #15
0
def gvar_names(name_filter = lambda x : False):
    """Return list of standard GNU directory variable names

    By default this function returns empty list, you should provide custom
    **name_filter** to get any results. To retrieve all defined variables,
    use ``name_filter = lambda x : True``.

    :Parameters:
        name_filter : callable
            callable object (e.g. lambda) of type ``name_filter(name) ->
            boolean`` used to filter-out unwanted variables; only these
            variables are processed, for which name_filter returns ``True``
    :Returns:
        the list of standard GNU directory variable names
    """
    if is_Sequence(name_filter):
        seq = name_filter
        name_filter = lambda x : x in seq
    return filter(name_filter, zip(*__std_var_triples)[0])
def ProcessFlags(env, flags):  # pylint: disable=too-many-branches
    if not flags:
        return
    if isinstance(flags, list):
        flags = " ".join(flags)
    parsed_flags = env.ParseFlags(str(flags))
    for flag in parsed_flags.pop("CPPDEFINES"):
        if not is_Sequence(flag):
            env.Append(CPPDEFINES=flag)
            continue
        _key, _value = flag[:2]
        if '\"' in _value:
            _value = _value.replace('\"', '\\\"')
        elif _value.isdigit():
            _value = int(_value)
        elif _value.replace(".", "", 1).isdigit():
            _value = float(_value)
        env.Append(CPPDEFINES=(_key, _value))
    env.Append(**parsed_flags)

    # fix relative CPPPATH & LIBPATH
    for k in ("CPPPATH", "LIBPATH"):
        for i, p in enumerate(env.get(k, [])):
            if isdir(p):
                env[k][i] = realpath(p)
    # fix relative path for "-include"
    for i, f in enumerate(env.get("CCFLAGS", [])):
        if isinstance(f, tuple) and f[0] == "-include":
            env['CCFLAGS'][i] = (f[0], env.File(realpath(f[1].get_path())))

    # Cancel any previous definition of name, either built in or
    # provided with a -D option // Issue #191
    undefines = [
        u for u in env.get("CCFLAGS", [])
        if isinstance(u, basestring) and u.startswith("-U")
    ]
    if undefines:
        for undef in undefines:
            env['CCFLAGS'].remove(undef)
        env.Append(_CPPDEFFLAGS=" %s" % " ".join(undefines))
Example #17
0
def ProcessFlags(env, flags):  # pylint: disable=too-many-branches
    if not flags:
        return
    if isinstance(flags, list):
        flags = " ".join(flags)
    parsed_flags = env.ParseFlags(str(flags))
    for flag in parsed_flags.pop("CPPDEFINES"):
        if not is_Sequence(flag):
            env.Append(CPPDEFINES=flag)
            continue
        _key, _value = flag[:2]
        if '\"' in _value:
            _value = _value.replace('\"', '\\\"')
        elif _value.isdigit():
            _value = int(_value)
        elif _value.replace(".", "", 1).isdigit():
            _value = float(_value)
        env.Append(CPPDEFINES=(_key, _value))
    env.Append(**parsed_flags)

    # fix relative CPPPATH & LIBPATH
    for k in ("CPPPATH", "LIBPATH"):
        for i, p in enumerate(env.get(k, [])):
            if isdir(p):
                env[k][i] = realpath(p)
    # fix relative path for "-include"
    for i, f in enumerate(env.get("CCFLAGS", [])):
        if isinstance(f, tuple) and f[0] == "-include":
            env['CCFLAGS'][i] = (f[0], env.File(realpath(f[1].get_path())))

    # Cancel any previous definition of name, either built in or
    # provided with a -D option // Issue #191
    undefines = [
        u for u in env.get("CCFLAGS", [])
        if isinstance(u, basestring) and u.startswith("-U")
    ]
    if undefines:
        for undef in undefines:
            env['CCFLAGS'].remove(undef)
        env.Append(_CPPDEFFLAGS=" %s" % " ".join(undefines))
Example #18
0
def _action(target, source, env):
    # prepare the line separator
    linesep = env["LINESEPARATOR"]
    if linesep is None:
        linesep = os.linesep
    elif is_String(linesep):
        pass
    elif isinstance(linesep, Value):
        linesep = linesep.get_text_contents()
    else:
        raise SCons.Errors.UserError("unexpected type/class for LINESEPARATOR: %s" % repr(linesep), None)

    # create a dictionary to use for the substitutions
    if "SUBST_DICT" not in env:
        subs = None  # no substitutions
    else:
        d = env["SUBST_DICT"]
        if is_Dict(d):
            d = list(d.items())
        elif is_Sequence(d):
            pass
        else:
            raise SCons.Errors.UserError("SUBST_DICT must be dict or sequence")
        subs = []
        for (k, v) in d:
            if callable(v):
                v = v()
            if is_String(v):
                v = env.subst(v)
            else:
                v = str(v)
            subs.append((k, v))

    # write the file
    try:
        fd = open(target[0].get_path(), "wb")
    except (OSError, IOError), e:
        raise SCons.Errors.UserError("Can't write target file %s" % target[0])
Example #19
0
        def expand(self, s, lvars):
            """Expand a single "token" as necessary, returning an
            appropriate string containing the expansion.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """
            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    return s
                if s0 != '$':
                    return s
                if s1 == '$':
                    return '$'
                elif s1 in '()':
                    return s
                else:
                    key = s[1:]
                    if key[0] == '{' or '.' in key:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception as e:
                            if e.__class__ in AllowableExceptions:
                                return ''
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif not NameError in AllowableExceptions:
                            raise_exception(NameError(key), lvars['TARGETS'], s)
                        else:
                            return ''

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    #
                    # This could potentially be optimized by only
                    # copying lvars when s contains more expansions,
                    # but lvars is usually supposed to be pretty
                    # small, and deeply nested variable expansions
                    # are probably more the exception than the norm,
                    # so it should be tolerable for now.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    return self.substitute(s, lv)
            elif is_Sequence(s):
                def func(l, conv=self.conv, substitute=self.substitute, lvars=lvars):
                    return conv(substitute(l, lvars))
                return list(map(func, s))
            elif callable(s):
                try:
                    s = s(target=lvars['TARGETS'],
                         source=lvars['SOURCES'],
                         env=self.env,
                         for_signature=(self.mode != SUBST_CMD))
                except TypeError:
                    # This probably indicates that it's a callable
                    # object that doesn't match our calling arguments
                    # (like an Action).
                    if self.mode == SUBST_RAW:
                        return s
                    s = self.conv(s)
                return self.substitute(s, lvars)
            elif s is None:
                return ''
            else:
                return s
Example #20
0
        def expand(self, s, lvars):
            """Expand a single "token" as necessary, returning an
            appropriate string containing the expansion.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """
            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    return s
                if s0 != '$':
                    return s
                if s1 == '$':
                    return '$'
                elif s1 in '()':
                    return s
                else:
                    key = s[1:]
                    if key[0] == '{' or '.' in key:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception as e:
                            if e.__class__ in AllowableExceptions:
                                return ''
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif not NameError in AllowableExceptions:
                            raise_exception(NameError(key), lvars['TARGETS'],
                                            s)
                        else:
                            return ''

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    #
                    # This could potentially be optimized by only
                    # copying lvars when s contains more expansions,
                    # but lvars is usually supposed to be pretty
                    # small, and deeply nested variable expansions
                    # are probably more the exception than the norm,
                    # so it should be tolerable for now.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    return self.substitute(s, lv)
            elif is_Sequence(s):

                def func(l,
                         conv=self.conv,
                         substitute=self.substitute,
                         lvars=lvars):
                    return conv(substitute(l, lvars))

                return list(map(func, s))
            elif callable(s):
                try:
                    s = s(target=lvars['TARGETS'],
                          source=lvars['SOURCES'],
                          env=self.env,
                          for_signature=(self.mode != SUBST_CMD))
                except TypeError:
                    # This probably indicates that it's a callable
                    # object that doesn't match our calling arguments
                    # (like an Action).
                    if self.mode == SUBST_RAW:
                        return s
                    s = self.conv(s)
                return self.substitute(s, lvars)
            elif s is None:
                return ''
            else:
                return s
Example #21
0
def scons_subst_list(strSubst,
                     env,
                     mode=SUBST_RAW,
                     target=None,
                     source=None,
                     gvars={},
                     lvars={},
                     conv=None):
    """Substitute construction variables in a string (or list or other
    object) and separate the arguments into a command list.

    The companion scons_subst() function (above) handles basic
    substitutions within strings, so see that function instead
    if that's what you're looking for.
    """
    class ListSubber(collections.UserList):
        """A class to construct the results of a scons_subst_list() call.

        Like StringSubber, this class binds a specific construction
        environment, mode, target and source with two methods
        (substitute() and expand()) that handle the expansion.

        In addition, however, this class is used to track the state of
        the result(s) we're gathering so we can do the appropriate thing
        whenever we have to append another word to the result--start a new
        line, start a new word, append to the current word, etc.  We do
        this by setting the "append" attribute to the right method so
        that our wrapper methods only need ever call ListSubber.append(),
        and the rest of the object takes care of doing the right thing
        internally.
        """
        def __init__(self, env, mode, conv, gvars):
            collections.UserList.__init__(self, [])
            self.env = env
            self.mode = mode
            self.conv = conv
            self.gvars = gvars

            if self.mode == SUBST_RAW:
                self.add_strip = lambda x: self.append(x)
            else:
                self.add_strip = lambda x: None
            self.in_strip = None
            self.next_line()

        def expand(self, s, lvars, within_list):
            """Expand a single "token" as necessary, appending the
            expansion to the current result.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """

            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    self.append(s)
                    return
                if s0 != '$':
                    self.append(s)
                    return
                if s1 == '$':
                    self.append('$')
                elif s1 == '(':
                    self.open_strip('$(')
                elif s1 == ')':
                    self.close_strip('$)')
                else:
                    key = s[1:]
                    if key[0] == '{' or key.find('.') >= 0:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception, e:
                            if e.__class__ in AllowableExceptions:
                                return
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif not NameError in AllowableExceptions:
                            raise_exception(NameError(), lvars['TARGETS'], s)
                        else:
                            return

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    self.substitute(s, lv, 0)
                    self.this_word()
            elif is_Sequence(s):
                for a in s:
                    self.substitute(a, lvars, 1)
                    self.next_word()
Example #22
0
def scons_subst(strSubst,
                env,
                mode=SUBST_RAW,
                target=None,
                source=None,
                gvars={},
                lvars={},
                conv=None):
    """Expand a string or list containing construction variable
    substitutions.

    This is the work-horse function for substitutions in file names
    and the like.  The companion scons_subst_list() function (below)
    handles separating command lines into lists of arguments, so see
    that function if that's what you're looking for.
    """
    if isinstance(strSubst, str) and strSubst.find('$') < 0:
        return strSubst

    class StringSubber(object):
        """A class to construct the results of a scons_subst() call.

        This binds a specific construction environment, mode, target and
        source with two methods (substitute() and expand()) that handle
        the expansion.
        """
        def __init__(self, env, mode, conv, gvars):
            self.env = env
            self.mode = mode
            self.conv = conv
            self.gvars = gvars

        def expand(self, s, lvars):
            """Expand a single "token" as necessary, returning an
            appropriate string containing the expansion.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """
            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    return s
                if s0 != '$':
                    return s
                if s1 == '$':
                    # In this case keep the double $'s which we'll later
                    # swap for a single dollar sign as we need to retain
                    # this information to properly avoid matching "$("" when
                    # the actual text was "$$(""  (or "$)"" when "$$)"" )
                    return '$$'
                elif s1 in '()':
                    return s
                else:
                    key = s[1:]
                    if key[0] == '{' or '.' in key:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception as e:
                            if e.__class__ in AllowableExceptions:
                                return ''
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif NameError not in AllowableExceptions:
                            raise_exception(NameError(key), lvars['TARGETS'],
                                            s)
                        else:
                            return ''

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    #
                    # This could potentially be optimized by only
                    # copying lvars when s contains more expansions,
                    # but lvars is usually supposed to be pretty
                    # small, and deeply nested variable expansions
                    # are probably more the exception than the norm,
                    # so it should be tolerable for now.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    return self.substitute(s, lv)
            elif is_Sequence(s):

                def func(l,
                         conv=self.conv,
                         substitute=self.substitute,
                         lvars=lvars):
                    return conv(substitute(l, lvars))

                return list(map(func, s))
            elif callable(s):
                try:
                    s = s(target=lvars['TARGETS'],
                          source=lvars['SOURCES'],
                          env=self.env,
                          for_signature=(self.mode != SUBST_CMD))
                except TypeError:
                    # This probably indicates that it's a callable
                    # object that doesn't match our calling arguments
                    # (like an Action).
                    if self.mode == SUBST_RAW:
                        return s
                    s = self.conv(s)
                return self.substitute(s, lvars)
            elif s is None:
                return ''
            else:
                return s

        def substitute(self, args, lvars):
            """Substitute expansions in an argument or list of arguments.

            This serves as a wrapper for splitting up a string into
            separate tokens.
            """
            if is_String(args) and not isinstance(args, CmdStringHolder):
                args = str(args)  # In case it's a UserString.
                try:

                    def sub_match(match):
                        return self.conv(self.expand(match.group(1), lvars))

                    result = _dollar_exps.sub(sub_match, args)
                except TypeError:
                    # If the internal conversion routine doesn't return
                    # strings (it could be overridden to return Nodes, for
                    # example), then the 1.5.2 re module will throw this
                    # exception.  Back off to a slower, general-purpose
                    # algorithm that works for all data types.
                    args = _separate_args.findall(args)
                    result = []
                    for a in args:
                        result.append(self.conv(self.expand(a, lvars)))
                    if len(result) == 1:
                        result = result[0]
                    else:
                        result = ''.join(map(str, result))
                return result
            else:
                return self.expand(args, lvars)

    if conv is None:
        conv = _strconv[mode]

    # Doing this every time is a bit of a waste, since the Executor
    # has typically already populated the OverrideEnvironment with
    # $TARGET/$SOURCE variables.  We're keeping this (for now), though,
    # because it supports existing behavior that allows us to call
    # an Action directly with an arbitrary target+source pair, which
    # we use in Tool/tex.py to handle calling $BIBTEX when necessary.
    # If we dropped that behavior (or found another way to cover it),
    # we could get rid of this call completely and just rely on the
    # Executor setting the variables.
    if 'TARGET' not in lvars:
        d = subst_dict(target, source)
        if d:
            lvars = lvars.copy()
            lvars.update(d)

    # We're (most likely) going to eval() things.  If Python doesn't
    # find a __builtins__ value in the global dictionary used for eval(),
    # it copies the current global values for you.  Avoid this by
    # setting it explicitly and then deleting, so we don't pollute the
    # construction environment Dictionary(ies) that are typically used
    # for expansion.
    gvars['__builtins__'] = __builtins__

    ss = StringSubber(env, mode, conv, gvars)
    result = ss.substitute(strSubst, lvars)

    try:
        del gvars['__builtins__']
    except KeyError:
        pass

    res = result
    if is_String(result):
        # Remove $(-$) pairs and any stuff in between,
        # if that's appropriate.
        remove = _regex_remove[mode]
        if remove:
            if mode == SUBST_SIG:
                result = _list_remove[mode](remove.split(result))
                if result is None:
                    raise SCons.Errors.UserError("Unbalanced $(/$) in: " + res)
                result = ' '.join(result)
            else:
                result = remove.sub('', result)
        if mode != SUBST_RAW:
            # Compress strings of white space characters into
            # a single space.
            result = _space_sep.sub(' ', result).strip()

        # Now replace escaped $'s currently "$$"
        # This is needed because we now retain $$ instead of
        # replacing them during substition to avoid
        # improperly trying to escape "$$(" as being "$("
        result = result.replace('$$', '$')
    elif is_Sequence(result):
        remove = _list_remove[mode]
        if remove:
            result = remove(result)
            if result is None:
                raise SCons.Errors.UserError("Unbalanced $(/$) in: " +
                                             str(res))

    return result
Example #23
0
        def expand(self, s, lvars, within_list):
            """Expand a single "token" as necessary, appending the
            expansion to the current result.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """

            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    self.append(s)
                    return
                if s0 != '$':
                    self.append(s)
                    return
                if s1 == '$':
                    self.append('$')
                elif s1 == '(':
                    self.open_strip('$(')
                elif s1 == ')':
                    self.close_strip('$)')
                else:
                    key = s[1:]
                    if key[0] == '{' or key.find('.') >= 0:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception as e:
                            if e.__class__ in AllowableExceptions:
                                return
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif NameError not in AllowableExceptions:
                            raise_exception(NameError(), lvars['TARGETS'], s)
                        else:
                            return

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    self.substitute(s, lv, 0)
                    self.this_word()
            elif is_Sequence(s):
                for a in s:
                    self.substitute(a, lvars, 1)
                    self.next_word()
            elif callable(s):
                try:
                    s = s(target=lvars['TARGETS'],
                          source=lvars['SOURCES'],
                          env=self.env,
                          for_signature=(self.mode != SUBST_CMD))
                except TypeError:
                    # This probably indicates that it's a callable
                    # object that doesn't match our calling arguments
                    # (like an Action).
                    if self.mode == SUBST_RAW:
                        self.append(s)
                        return
                    s = self.conv(s)
                self.substitute(s, lvars, within_list)
            elif s is None:
                self.this_word()
            else:
                self.append(s)
Example #24
0
def scons_subst(strSubst,
                env,
                mode=SUBST_RAW,
                target=None,
                source=None,
                gvars={},
                lvars={},
                conv=None):
    """Expand a string or list containing construction variable
    substitutions.

    This is the work-horse function for substitutions in file names
    and the like.  The companion scons_subst_list() function (below)
    handles separating command lines into lists of arguments, so see
    that function if that's what you're looking for.
    """
    if isinstance(strSubst, str) and strSubst.find('$') < 0:
        return strSubst

    class StringSubber(object):
        """A class to construct the results of a scons_subst() call.

        This binds a specific construction environment, mode, target and
        source with two methods (substitute() and expand()) that handle
        the expansion.
        """
        def __init__(self, env, mode, conv, gvars):
            self.env = env
            self.mode = mode
            self.conv = conv
            self.gvars = gvars

        def expand(self, s, lvars):
            """Expand a single "token" as necessary, returning an
            appropriate string containing the expansion.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """
            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    return s
                if s0 != '$':
                    return s
                if s1 == '$':
                    return '$'
                elif s1 in '()':
                    return s
                else:
                    key = s[1:]
                    if key[0] == '{' or key.find('.') >= 0:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception, e:
                            if e.__class__ in AllowableExceptions:
                                return ''
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif not NameError in AllowableExceptions:
                            raise_exception(NameError(key), lvars['TARGETS'],
                                            s)
                        else:
                            return ''

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    #
                    # This could potentially be optimized by only
                    # copying lvars when s contains more expansions,
                    # but lvars is usually supposed to be pretty
                    # small, and deeply nested variable expansions
                    # are probably more the exception than the norm,
                    # so it should be tolerable for now.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    return self.substitute(s, lv)
            elif is_Sequence(s):

                def func(l,
                         conv=self.conv,
                         substitute=self.substitute,
                         lvars=lvars):
                    return conv(substitute(l, lvars))

                return list(map(func, s))
Example #25
0
    def expand(self, s, lvars):
        """Expand a single "token" as necessary, returning an
        appropriate string containing the expansion.

        This handles expanding different types of things (strings,
        lists, callables) appropriately.  It calls the wrapper
        substitute() method to re-expand things as necessary, so that
        the results of expansions of side-by-side strings still get
        re-evaluated separately, not smushed together.
        """
        if is_String(s):
            try:
                s0, s1 = s[:2]
            except (IndexError, ValueError):
                return s
            if s0 != '$':
                return s
            if s1 == '$':
                # In this case keep the double $'s which we'll later
                # swap for a single dollar sign as we need to retain
                # this information to properly avoid matching "$("" when
                # the actual text was "$$(""  (or "$)"" when "$$)"" )
                return '$$'
            elif s1 in '()':
                return s
            else:
                key = s[1:]
                if key[0] == '{' or '.' in key:
                    if key[0] == '{':
                        key = key[1:-1]

                # Store for error messages if we fail to expand the
                # value
                old_s = s
                s = None
                if key in lvars:
                    s = lvars[key]
                elif key in self.gvars:
                    s = self.gvars[key]
                else:
                    try:
                        s = eval(key, self.gvars, lvars)
                    except KeyboardInterrupt:
                        raise
                    except Exception as e:
                        if e.__class__ in AllowableExceptions:
                            return ''
                        raise_exception(e, lvars['TARGETS'], old_s)

                if s is None and NameError not in AllowableExceptions:
                    raise_exception(NameError(key), lvars['TARGETS'], old_s)
                elif s is None:
                    return ''

                # Before re-expanding the result, handle
                # recursive expansion by copying the local
                # variable dictionary and overwriting a null
                # string for the value of the variable name
                # we just expanded.
                #
                # This could potentially be optimized by only
                # copying lvars when s contains more expansions,
                # but lvars is usually supposed to be pretty
                # small, and deeply nested variable expansions
                # are probably more the exception than the norm,
                # so it should be tolerable for now.
                lv = lvars.copy()
                var = key.split('.')[0]
                lv[var] = ''
                return self.substitute(s, lv)
        elif is_Sequence(s):

            def func(l,
                     conv=self.conv,
                     substitute=self.substitute,
                     lvars=lvars):
                return conv(substitute(l, lvars))

            return list(map(func, s))
        elif callable(s):
            # SCons has the unusual Null class where any __getattr__ call returns it's self,
            # which does not work the signature module, and the Null class returns an empty
            # string if called on, so we make an exception in this condition for Null class
            if (isinstance(s, SCons.Util.Null)
                    or set(signature(s).parameters.keys()) == set(
                        ['target', 'source', 'env', 'for_signature'])):
                s = s(target=lvars['TARGETS'],
                      source=lvars['SOURCES'],
                      env=self.env,
                      for_signature=(self.mode != SUBST_CMD))
            else:
                # This probably indicates that it's a callable
                # object that doesn't match our calling arguments
                # (like an Action).
                if self.mode == SUBST_RAW:
                    return s
                s = self.conv(s)
            return self.substitute(s, lvars)
        elif s is None:
            return ''
        else:
            return s
Example #26
0
    try:
        del gvars['__builtins__']
    except KeyError:
        pass

    if is_String(result):
        # Remove $(-$) pairs and any stuff in between,
        # if that's appropriate.
        remove = _regex_remove[mode]
        if remove:
            result = remove.sub('', result)
        if mode != SUBST_RAW:
            # Compress strings of white space characters into
            # a single space.
            result = _space_sep.sub(' ', result).strip()
    elif is_Sequence(result):
        remove = _list_remove[mode]
        if remove:
            result = remove(result)

    return result


def scons_subst_list(strSubst,
                     env,
                     mode=SUBST_RAW,
                     target=None,
                     source=None,
                     gvars={},
                     lvars={},
                     conv=None):
Example #27
0
def scons_subst(strSubst,
                env,
                mode=SUBST_RAW,
                target=None,
                source=None,
                gvars={},
                lvars={},
                conv=None):
    """Expand a string or list containing construction variable
    substitutions.

    This is the work-horse function for substitutions in file names
    and the like.  The companion scons_subst_list() function (below)
    handles separating command lines into lists of arguments, so see
    that function if that's what you're looking for.
    """
    if (isinstance(strSubst, str) and '$' not in strSubst) or isinstance(
            strSubst, CmdStringHolder):
        return strSubst

    if conv is None:
        conv = _strconv[mode]

    # Doing this every time is a bit of a waste, since the Executor
    # has typically already populated the OverrideEnvironment with
    # $TARGET/$SOURCE variables.  We're keeping this (for now), though,
    # because it supports existing behavior that allows us to call
    # an Action directly with an arbitrary target+source pair, which
    # we use in Tool/tex.py to handle calling $BIBTEX when necessary.
    # If we dropped that behavior (or found another way to cover it),
    # we could get rid of this call completely and just rely on the
    # Executor setting the variables.
    if 'TARGET' not in lvars:
        d = subst_dict(target, source)
        if d:
            lvars = lvars.copy()
            lvars.update(d)

    # We're (most likely) going to eval() things.  If Python doesn't
    # find a __builtins__ value in the global dictionary used for eval(),
    # it copies the current global values for you.  Avoid this by
    # setting it explicitly and then deleting, so we don't pollute the
    # construction environment Dictionary(ies) that are typically used
    # for expansion.
    gvars['__builtins__'] = __builtins__

    ss = StringSubber(env, mode, conv, gvars)
    result = ss.substitute(strSubst, lvars)

    try:
        del gvars['__builtins__']
    except KeyError:
        pass

    res = result
    if is_String(result):
        # Remove $(-$) pairs and any stuff in between,
        # if that's appropriate.
        remove = _regex_remove[mode]
        if remove:
            if mode == SUBST_SIG:
                result = _list_remove[mode](remove.split(result))
                if result is None:
                    raise SCons.Errors.UserError("Unbalanced $(/$) in: " + res)
                result = ' '.join(result)
            else:
                result = remove.sub('', result)
        if mode != SUBST_RAW:
            # Compress strings of white space characters into
            # a single space.
            result = _space_sep.sub(' ', result).strip()

        # Now replace escaped $'s currently "$$"
        # This is needed because we now retain $$ instead of
        # replacing them during substition to avoid
        # improperly trying to escape "$$(" as being "$("
        result = result.replace('$$', '$')
    elif is_Sequence(result):
        remove = _list_remove[mode]
        if remove:
            result = remove(result)
            if result is None:
                raise SCons.Errors.UserError("Unbalanced $(/$) in: " +
                                             str(res))

    return result
Example #28
0
    def expand(self, s, lvars, within_list):
        """Expand a single "token" as necessary, appending the
        expansion to the current result.

        This handles expanding different types of things (strings,
        lists, callables) appropriately.  It calls the wrapper
        substitute() method to re-expand things as necessary, so that
        the results of expansions of side-by-side strings still get
        re-evaluated separately, not smushed together.
        """

        if is_String(s):
            try:
                s0, s1 = s[:2]
            except (IndexError, ValueError):
                self.append(s)
                return
            if s0 != '$':
                self.append(s)
                return
            if s1 == '$':
                self.append('$')
            elif s1 == '(':
                self.open_strip('$(')
            elif s1 == ')':
                self.close_strip('$)')
            else:
                key = s[1:]
                if key[0] == '{' or key.find('.') >= 0:
                    if key[0] == '{':
                        key = key[1:-1]

                # Store for error messages if we fail to expand the
                # value
                old_s = s
                s = None
                if key in lvars:
                    s = lvars[key]
                elif key in self.gvars:
                    s = self.gvars[key]
                else:
                    try:
                        s = eval(key, self.gvars, lvars)
                    except KeyboardInterrupt:
                        raise
                    except Exception as e:
                        if e.__class__ in AllowableExceptions:
                            return
                        raise_exception(e, lvars['TARGETS'], old_s)

                if s is None and NameError not in AllowableExceptions:
                    raise_exception(NameError(), lvars['TARGETS'], old_s)
                elif s is None:
                    return

                # If the string is already full expanded there's no
                # need to continue recursion.
                if self.expanded(s):
                    self.append(s)
                    return

                # Before re-expanding the result, handle
                # recursive expansion by copying the local
                # variable dictionary and overwriting a null
                # string for the value of the variable name
                # we just expanded.
                lv = lvars.copy()
                var = key.split('.')[0]
                lv[var] = ''
                self.substitute(s, lv, 0)
                self.this_word()
        elif is_Sequence(s):
            for a in s:
                self.substitute(a, lvars, 1)
                self.next_word()
        elif callable(s):
            # SCons has the unusual Null class where any __getattr__ call returns it's self,
            # which does not work the signature module, and the Null class returns an empty
            # string if called on, so we make an exception in this condition for Null class
            if (isinstance(s, SCons.Util.Null)
                    or set(signature(s).parameters.keys()) == set(
                        ['target', 'source', 'env', 'for_signature'])):
                s = s(target=lvars['TARGETS'],
                      source=lvars['SOURCES'],
                      env=self.env,
                      for_signature=(self.mode != SUBST_CMD))
            else:
                # This probably indicates that it's a callable
                # object that doesn't match our calling arguments
                # (like an Action).
                if self.mode == SUBST_RAW:
                    self.append(s)
                    return
                s = self.conv(s)
            self.substitute(s, lvars, within_list)
        elif s is None:
            self.this_word()
        else:
            self.append(s)
Example #29
0
def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
    """Substitute construction variables in a string (or list or other
    object) and separate the arguments into a command list.

    The companion scons_subst() function (above) handles basic
    substitutions within strings, so see that function instead
    if that's what you're looking for.
    """
#    try:
#        Subst_List_Strings[strSubst] = Subst_List_Strings[strSubst] + 1
#    except KeyError:
#        Subst_List_Strings[strSubst] = 1
#    import SCons.Debug
#    SCons.Debug.caller_trace(1)
    class ListSubber(collections.UserList):
        """A class to construct the results of a scons_subst_list() call.

        Like StringSubber, this class binds a specific construction
        environment, mode, target and source with two methods
        (substitute() and expand()) that handle the expansion.

        In addition, however, this class is used to track the state of
        the result(s) we're gathering so we can do the appropriate thing
        whenever we have to append another word to the result--start a new
        line, start a new word, append to the current word, etc.  We do
        this by setting the "append" attribute to the right method so
        that our wrapper methods only need ever call ListSubber.append(),
        and the rest of the object takes care of doing the right thing
        internally.
        """
        def __init__(self, env, mode, conv, gvars):
            collections.UserList.__init__(self, [])
            self.env = env
            self.mode = mode
            self.conv = conv
            self.gvars = gvars

            if self.mode == SUBST_RAW:
                self.add_strip = lambda x: self.append(x)
            else:
                self.add_strip = lambda x: None
            self.in_strip = None
            self.next_line()

        def expand(self, s, lvars, within_list):
            """Expand a single "token" as necessary, appending the
            expansion to the current result.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """

            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    self.append(s)
                    return
                if s0 != '$':
                    self.append(s)
                    return
                if s1 == '$':
                    self.append('$')
                elif s1 == '(':
                    self.open_strip('$(')
                elif s1 == ')':
                    self.close_strip('$)')
                else:
                    key = s[1:]
                    if key[0] == '{' or key.find('.') >= 0:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception, e:
                            if e.__class__ in AllowableExceptions:
                                return
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif not NameError in AllowableExceptions:
                            raise_exception(NameError(), lvars['TARGETS'], s)
                        else:
                            return

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    self.substitute(s, lv, 0)
                    self.this_word()
            elif is_Sequence(s):
                for a in s:
                    self.substitute(a, lvars, 1)
                    self.next_word()
Example #30
0
def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
    """Expand a string or list containing construction variable
    substitutions.

    This is the work-horse function for substitutions in file names
    and the like.  The companion scons_subst_list() function (below)
    handles separating command lines into lists of arguments, so see
    that function if that's what you're looking for.
    """
    if isinstance(strSubst, str) and strSubst.find('$') < 0:
        return strSubst

    class StringSubber(object):
        """A class to construct the results of a scons_subst() call.

        This binds a specific construction environment, mode, target and
        source with two methods (substitute() and expand()) that handle
        the expansion.
        """
        def __init__(self, env, mode, conv, gvars):
            self.env = env
            self.mode = mode
            self.conv = conv
            self.gvars = gvars

        def expand(self, s, lvars):
            """Expand a single "token" as necessary, returning an
            appropriate string containing the expansion.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """
            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    return s
                if s0 != '$':
                    return s
                if s1 == '$':
                    return '$'
                elif s1 in '()':
                    return s
                else:
                    key = s[1:]
                    if key[0] == '{' or key.find('.') >= 0:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception, e:
                            if e.__class__ in AllowableExceptions:
                                return ''
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif not NameError in AllowableExceptions:
                            raise_exception(NameError(key), lvars['TARGETS'], s)
                        else:
                            return ''

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    #
                    # This could potentially be optimized by only
                    # copying lvars when s contains more expansions,
                    # but lvars is usually supposed to be pretty
                    # small, and deeply nested variable expansions
                    # are probably more the exception than the norm,
                    # so it should be tolerable for now.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    return self.substitute(s, lv)
            elif is_Sequence(s):
                def func(l, conv=self.conv, substitute=self.substitute, lvars=lvars):
                    return conv(substitute(l, lvars))
                return list(map(func, s))
Example #31
0
def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
    """Expand a string or list containing construction variable
    substitutions.

    This is the work-horse function for substitutions in file names
    and the like.  The companion scons_subst_list() function (below)
    handles separating command lines into lists of arguments, so see
    that function if that's what you're looking for.
    """
    if isinstance(strSubst, str) and strSubst.find('$') < 0:
        return strSubst

    class StringSubber(object):
        """A class to construct the results of a scons_subst() call.

        This binds a specific construction environment, mode, target and
        source with two methods (substitute() and expand()) that handle
        the expansion.
        """
        def __init__(self, env, mode, conv, gvars):
            self.env = env
            self.mode = mode
            self.conv = conv
            self.gvars = gvars

        def expand(self, s, lvars):
            """Expand a single "token" as necessary, returning an
            appropriate string containing the expansion.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """
            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    return s
                if s0 != '$':
                    return s
                if s1 == '$':
                    return '$'
                elif s1 in '()':
                    return s
                else:
                    key = s[1:]
                    if key[0] == '{' or '.' in key:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception as e:
                            if e.__class__ in AllowableExceptions:
                                return ''
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif not NameError in AllowableExceptions:
                            raise_exception(NameError(key), lvars['TARGETS'], s)
                        else:
                            return ''

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    #
                    # This could potentially be optimized by only
                    # copying lvars when s contains more expansions,
                    # but lvars is usually supposed to be pretty
                    # small, and deeply nested variable expansions
                    # are probably more the exception than the norm,
                    # so it should be tolerable for now.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    return self.substitute(s, lv)
            elif is_Sequence(s):
                def func(l, conv=self.conv, substitute=self.substitute, lvars=lvars):
                    return conv(substitute(l, lvars))
                return list(map(func, s))
            elif callable(s):
                try:
                    s = s(target=lvars['TARGETS'],
                         source=lvars['SOURCES'],
                         env=self.env,
                         for_signature=(self.mode != SUBST_CMD))
                except TypeError:
                    # This probably indicates that it's a callable
                    # object that doesn't match our calling arguments
                    # (like an Action).
                    if self.mode == SUBST_RAW:
                        return s
                    s = self.conv(s)
                return self.substitute(s, lvars)
            elif s is None:
                return ''
            else:
                return s

        def substitute(self, args, lvars):
            """Substitute expansions in an argument or list of arguments.

            This serves as a wrapper for splitting up a string into
            separate tokens.
            """
            if is_String(args) and not isinstance(args, CmdStringHolder):
                args = str(args)        # In case it's a UserString.
                try:
                    def sub_match(match):
                        return self.conv(self.expand(match.group(1), lvars))
                    result = _dollar_exps.sub(sub_match, args)
                except TypeError:
                    # If the internal conversion routine doesn't return
                    # strings (it could be overridden to return Nodes, for
                    # example), then the 1.5.2 re module will throw this
                    # exception.  Back off to a slower, general-purpose
                    # algorithm that works for all data types.
                    args = _separate_args.findall(args)
                    result = []
                    for a in args:
                        result.append(self.conv(self.expand(a, lvars)))
                    if len(result) == 1:
                        result = result[0]
                    else:
                        result = ''.join(map(str, result))
                return result
            else:
                return self.expand(args, lvars)

    if conv is None:
        conv = _strconv[mode]

    # Doing this every time is a bit of a waste, since the Executor
    # has typically already populated the OverrideEnvironment with
    # $TARGET/$SOURCE variables.  We're keeping this (for now), though,
    # because it supports existing behavior that allows us to call
    # an Action directly with an arbitrary target+source pair, which
    # we use in Tool/tex.py to handle calling $BIBTEX when necessary.
    # If we dropped that behavior (or found another way to cover it),
    # we could get rid of this call completely and just rely on the
    # Executor setting the variables.
    if 'TARGET' not in lvars:
        d = subst_dict(target, source)
        if d:
            lvars = lvars.copy()
            lvars.update(d)

    # We're (most likely) going to eval() things.  If Python doesn't
    # find a __builtins__ value in the global dictionary used for eval(),
    # it copies the current global values for you.  Avoid this by
    # setting it explicitly and then deleting, so we don't pollute the
    # construction environment Dictionary(ies) that are typically used
    # for expansion.
    gvars['__builtins__'] = __builtins__

    ss = StringSubber(env, mode, conv, gvars)
    result = ss.substitute(strSubst, lvars)

    try:
        del gvars['__builtins__']
    except KeyError:
        pass

    res = result
    if is_String(result):
        # Remove $(-$) pairs and any stuff in between,
        # if that's appropriate.
        remove = _regex_remove[mode]
        if remove:
            if mode == SUBST_SIG:
                result = _list_remove[mode](remove.split(result))
                if result is None:
                    raise SCons.Errors.UserError("Unbalanced $(/$) in: " + res)
                result = ' '.join(result)
            else:
                result = remove.sub('', result)
        if mode != SUBST_RAW:
            # Compress strings of white space characters into
            # a single space.
            result = _space_sep.sub(' ', result).strip()
    elif is_Sequence(result):
        remove = _list_remove[mode]
        if remove:
            result = remove(result)
            if result is None:
                raise SCons.Errors.UserError("Unbalanced $(/$) in: " + str(res))

    return result
Example #32
0
    try:
        del gvars['__builtins__']
    except KeyError:
        pass

    if is_String(result):
        # Remove $(-$) pairs and any stuff in between,
        # if that's appropriate.
        remove = _regex_remove[mode]
        if remove:
            result = remove.sub('', result)
        if mode != SUBST_RAW:
            # Compress strings of white space characters into
            # a single space.
            result = _space_sep.sub(' ', result).strip()
    elif is_Sequence(result):
        remove = _list_remove[mode]
        if remove:
            result = remove(result)

    return result

#Subst_List_Strings = {}

def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
    """Substitute construction variables in a string (or list or other
    object) and separate the arguments into a command list.

    The companion scons_subst() function (above) handles basic
    substitutions within strings, so see that function instead
    if that's what you're looking for.
Example #33
0
        def expand(self, s, lvars, within_list):
            """Expand a single "token" as necessary, appending the
            expansion to the current result.

            This handles expanding different types of things (strings,
            lists, callables) appropriately.  It calls the wrapper
            substitute() method to re-expand things as necessary, so that
            the results of expansions of side-by-side strings still get
            re-evaluated separately, not smushed together.
            """

            if is_String(s):
                try:
                    s0, s1 = s[:2]
                except (IndexError, ValueError):
                    self.append(s)
                    return
                if s0 != '$':
                    self.append(s)
                    return
                if s1 == '$':
                    self.append('$')
                elif s1 == '(':
                    self.open_strip('$(')
                elif s1 == ')':
                    self.close_strip('$)')
                else:
                    key = s[1:]
                    if key[0] == '{' or key.find('.') >= 0:
                        if key[0] == '{':
                            key = key[1:-1]
                        try:
                            s = eval(key, self.gvars, lvars)
                        except KeyboardInterrupt:
                            raise
                        except Exception as e:
                            if e.__class__ in AllowableExceptions:
                                return
                            raise_exception(e, lvars['TARGETS'], s)
                    else:
                        if key in lvars:
                            s = lvars[key]
                        elif key in self.gvars:
                            s = self.gvars[key]
                        elif not NameError in AllowableExceptions:
                            raise_exception(NameError(), lvars['TARGETS'], s)
                        else:
                            return

                    # Before re-expanding the result, handle
                    # recursive expansion by copying the local
                    # variable dictionary and overwriting a null
                    # string for the value of the variable name
                    # we just expanded.
                    lv = lvars.copy()
                    var = key.split('.')[0]
                    lv[var] = ''
                    self.substitute(s, lv, 0)
                    self.this_word()
            elif is_Sequence(s):
                for a in s:
                    self.substitute(a, lvars, 1)
                    self.next_word()
            elif callable(s):
                try:
                    s = s(target=lvars['TARGETS'],
                         source=lvars['SOURCES'],
                         env=self.env,
                         for_signature=(self.mode != SUBST_CMD))
                except TypeError:
                    # This probably indicates that it's a callable
                    # object that doesn't match our calling arguments
                    # (like an Action).
                    if self.mode == SUBST_RAW:
                        self.append(s)
                        return
                    s = self.conv(s)
                self.substitute(s, lvars, within_list)
            elif s is None:
                self.this_word()
            else:
                self.append(s)