예제 #1
0
def load(name, *symbols, **aliases):
    """Load and import symbols into current calling BUILD file
    Args:
        name: str, file name to be loaded.
        symbols: str*, symbol names to be imported.
        aliases: alias_name='real_name'*, symbol name to be imported as alias.
    """
    src_loc = _current_source_location()
    if not symbols and not aliases:
        console.diagnose(
            src_loc, 'error',
            'The symbols to be imported must be explicitly declared')

    extension_globals = _load_extension(name)

    def error(symbol):
        console.diagnose(src_loc, 'error',
                         '"%s" is not defined in "%s"' % (symbol, name))

    # Only import declared symbols into current file
    for symbol in symbols:
        if symbol not in extension_globals:
            error(symbol)
            continue
        __current_globals[symbol] = extension_globals[symbol]

    for alias, real_name in aliases.items():
        if real_name not in extension_globals:
            error(real_name)
            continue
        __current_globals[alias] = extension_globals[real_name]
예제 #2
0
def _load_extension(name):
    """Load symbols from file or obtain from loaded cache."""
    full_path = _expand_include_path(name)
    if full_path in __loaded_extension_info:
        return __loaded_extension_info[full_path]

    if not os.path.isfile(full_path):
        console.diagnose(_current_source_location(), 'error',
                         'File "%s" does not exist' % name)
        return {}

    # The symbols in the current context should be invisible to the extension,
    # make an isolated symbol set to implement this approach.
    origin_globals = build_rules.get_all()
    extension_globals = origin_globals.copy()
    exec_file(full_path, extension_globals, None)
    # Extract new symbols
    result = {}
    for symbol, value in extension_globals.items():
        if symbol.startswith('_'):
            continue
        if symbol in origin_globals and value is origin_globals[symbol]:
            continue
        if isinstance(value, types.ModuleType):
            continue
        result[symbol] = value
    __loaded_extension_info[full_path] = result
    return result
예제 #3
0
def include(name):
    """Include another file into current BUILD file"""
    full_path = _expand_include_path(name)
    if not os.path.isfile(full_path):
        console.diagnose(_current_source_location(), 'error', 'File "%s" does not exist' % name)
        return
    exec_file(full_path, __current_globals, None)
예제 #4
0
 def _check_direct_headers(self, full_src, direct_hdrs, suppressd_hdrs,
                           missing_dep_hdrs, undeclared_hdrs, check_msg):
     """Verify directly included header files is in deps."""
     msg = []
     for hdr in direct_hdrs:
         if hdr in self.declared_hdrs:
             console.diagnose(self.source_location, 'debug', '"%s" is a declared header' % (hdr))
             continue
         libs = self.find_libs_by_header(hdr)
         if not libs:
             libs = self.find_targets_by_private_hdr(hdr)
             if libs and self.key not in libs:
                 msg.append('    "%s" is a private header file of %s' % (
                         hdr, self._or_joined_libs(libs)))
                 continue
             console.diagnose(self.source_location, 'debug', '"%s" is an undeclared header' % hdr)
             undeclared_hdrs.add(hdr)
             # We need also check suppressd_hdrs because target maybe not loaded in partial build
             if hdr not in suppressd_hdrs and not self.is_allowed_undeclared_hdr(hdr):
                 msg.append('    %s' % self._header_undeclared_message(hdr))
             continue
         deps = set(self.deps + [self.key])  # Don't forget target itself
         if not (libs & deps):  # pylint: disable=superfluous-parens
             # NOTE:
             # We just don't report a suppressd hdr, but still need to record it as a failure.
             # Because a passed src will not be verified again, even if we remove it from the
             # suppress list.
             # Same reason in the _check_generated_headers.
             missing_dep_hdrs.add(hdr)
             if hdr not in suppressd_hdrs:
                 msg.append('    For %s' % self._hdr_declaration_message(hdr, libs))
     if msg:
         check_msg.append('  In file included from "%s",' % full_src)
         check_msg += msg
예제 #5
0
    def includes_iterator():
        results = []
        for pattern in include:
            if not pattern:
                console.diagnose(source_loc, 'error', '"glob": Empty pattern is not allowed')
                continue
            for path in source_dir.glob(pattern):
                if path.is_file() and not path.name.startswith('.'):
                    results.append(path.relative_to(source_dir))

        return results
예제 #6
0
 def wrapper(*args, **kwargs):
     src_loc = util.calling_source_location(
         1)  # Skip the `wrapper` function
     error = '"%s" is forbidden in blade, please use the builtin `blade` module' % name
     console.diagnose(src_loc, 'error', error)
예제 #7
0
 def wrapper(message):
     console.diagnose(util.calling_source_location(1), severity,
                      message)
예제 #8
0
def glob(include, exclude=None, excludes=None, allow_empty=False):
    """This function can be called in BUILD to specify a set of files using patterns.
    Args:
        include:List[str], file patterns to be matched.
        exclude:Optional[List[str]], file patterns to be removed from the result.
        allow_empty:bool: Whether a empty result is a error.

    Patterns may contain shell-like wildcards, such as * , ? , or [charset].
    Additionally, the path element '**' matches any subpath.
    """
    from blade import build_manager  # pylint: disable=import-outside-toplevel
    source_dir = Path(build_manager.instance.get_current_source_path())
    source_loc = _current_source_location()
    include = var_to_list(include)
    severity = config.get_item('global_config', 'glob_error_severity')
    if excludes:
        console.diagnose(source_loc, severity,
                         '"excludes" is deprecated, use "exclude" instead')
    exclude = var_to_list(exclude) + var_to_list(excludes)

    def includes_iterator():
        results = []
        for pattern in include:
            if not pattern:
                console.diagnose(source_loc, 'error',
                                 '"glob": Empty pattern is not allowed')
                continue
            for path in source_dir.glob(pattern):
                if path.is_file() and not path.name.startswith('.'):
                    results.append(path.relative_to(source_dir))

        return results

    def is_special(pattern):
        return '*' in pattern or '?' in pattern or '[' in pattern

    non_special_excludes = set()
    match_excludes = set()
    for pattern in exclude:
        if is_special(pattern):
            match_excludes.add(pattern)
        else:
            non_special_excludes.add(pattern)

    def exclusion(path):
        if str(path) in non_special_excludes:
            return True
        for pattern in match_excludes:
            ret = path.match(pattern)
            if ret:
                return True
        return False

    result = sorted({str(p) for p in includes_iterator() if not exclusion(p)})
    if not result and not allow_empty:
        args = repr(include)
        if exclude:
            args += ', exclude=%s' % repr(exclude)
        console.diagnose(
            source_loc, severity,
            '"glob(%s)" got an empty result. If it is the expected behavior, '
            'specify "allow_empty=True" to eliminate this message' % args)

    return result
예제 #9
0
 def error(symbol):
     console.diagnose(src_loc, 'error',
                      '"%s" is not defined in "%s"' % (symbol, name))
예제 #10
0
    def check(self):
        """
        Check whether included header files is declared in "deps" correctly.

        Returns:
            Whether nothing is wrong.
        """
        missing_details = {}  # {src: list(hdrs)}
        undeclared_hdrs = set()
        all_direct_hdrs = set()
        all_generated_hdrs = set()

        direct_check_msg = []
        generated_check_msg = []

        def check_file(src, full_src, is_header):
            if util.path_under_dir(full_src, self.build_dir):  # Don't check generated files.
                return
            path = self._find_inclusion_file(src, is_header)
            if not path:
                console.warning('No inclusion file found for %s' % full_src)
                return
            direct_hdrs, stacks = _parse_inclusion_stacks(path, self.build_dir)
            all_direct_hdrs.update(direct_hdrs)
            missing_dep_hdrs = set()
            self._check_direct_headers(
                    full_src, direct_hdrs, self.suppress.get(src, []),
                    missing_dep_hdrs, undeclared_hdrs, direct_check_msg)

            for stack in stacks:
                all_generated_hdrs.add(stack[-1])
            # But direct headers can not cover all, so it is still useful
            self._check_generated_headers(
                    full_src, stacks, direct_hdrs,
                    self.suppress.get(src, []),
                    missing_dep_hdrs, generated_check_msg)

            if missing_dep_hdrs:
                missing_details[src] = list(missing_dep_hdrs)

        for src, full_src in self.expanded_srcs:
            check_file(src, full_src, is_header=False)

        for hdr, full_hdr in self.expanded_hdrs:
            check_file(hdr, full_hdr, is_header=True)

        severity = self.severity
        if direct_check_msg:
            console.diagnose(self.source_location, severity,
                '%s: Missing dependency declaration:\n%s' % (self.name, '\n'.join(direct_check_msg)))
        if generated_check_msg:
            console.diagnose(self.source_location, severity,
                '%s: Missing indirect dependency declaration:\n%s' % (self.name, '\n'.join(generated_check_msg)))

        ok = (severity != 'error' or not direct_check_msg and not generated_check_msg)

        details = {}
        if missing_details:
            details['missing_dep'] = missing_details
        if undeclared_hdrs:
            details['undeclared'] = sorted(undeclared_hdrs)
        details['direct_hdrs'] = all_direct_hdrs
        details['generated_hdrs'] = all_generated_hdrs
        return ok, details