Recursively expands the text variables, vs. the os.path \
            method which only works at one level.  The cache value should be \
            left blank as it is used to protect against recursion.
            
            :param      text    | <str>
                        environ | <dict> || None
                        cache   | <dict> { <str>: <str>, .. }
                        
            :return     <str>

def expandvars(self, text, environ=None, cache=None):
        """
            Recursively expands the text variables, vs. the os.path \
            method which only works at one level.  The cache value should be \
            left blank as it is used to protect against recursion.
            
            :param      text    | <str>
                        environ | <dict> || None
                        cache   | <dict> { <str>: <str>, .. }
                        
            :return     <str>
        """
        if not environ:
            environ = os.environ

        # make sure we have data
        if not text:
            return ''

        # check for circular dependencies
        cache = cache or {}

        # return the cleaned variable
        output = nstr(text)
        keys = re.findall('\$(\w+)|\${(\w+)\}|\%(\w+)\%', text)

        for first, second, third in keys:
            repl = ''
            key = ''
            if first:
                repl = '$%s' % first
                key = first
            elif second:
                repl = '${%s}' % second
                key = second
            elif third:
                repl = '%%%s%%' % third
                key = third
            else:
                continue

            value = environ.get(key)
            if value:
                if key not in cache:
                    cache[key] = value
                    value = self.expandvars(value, environ, cache)
                else:
                    err = '%s environ variable causes an infinite loop.' % key
                    logger.warning(err)
                    value = cache[key]
            else:
                value = repl

            output = output.replace(repl, value)

        return os.path.expanduser(output)