<commit_before># Copyright (c) 2014-present PlatformIO <<EMAIL>>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# pylint: disable=no-self-use, unused-argument, too-many-lines
# pylint: disable=too-many-instance-attributes, too-many-public-methods
# pylint: disable=assignment-from-no-return

from __future__ import absolute_import

import hashlib
import io
import os
import re
import sys

import click
import SCons.Scanner  # pylint: disable=import-error
from SCons.Script import ARGUMENTS  # pylint: disable=import-error
from SCons.Script import COMMAND_LINE_TARGETS  # pylint: disable=import-error
from SCons.Script import DefaultEnvironment  # pylint: disable=import-error

from platformio import exception, fs, util
from platformio.builder.tools import platformio as piotool
from platformio.clients.http import HTTPClientError, InternetIsOffline
from platformio.compat import IS_WINDOWS, hashlib_encode_data, string_types
from platformio.package.exception import (
    MissingPackageManifestError,
    UnknownPackageError,
)
from platformio.package.manager.library import LibraryPackageManager
from platformio.package.manifest.parser import (
    ManifestParserError,
    ManifestParserFactory,
)
from platformio.package.meta import PackageItem
from platformio.project.options import ProjectOptions


class LibBuilderFactory(object):
    @staticmethod
    def new(env, path, verbose=int(ARGUMENTS.get("PIOVERBOSE", 0))):
        clsname = "UnknownLibBuilder"
        if os.path.isfile(os.path.join(path, "library.json")):
            clsname = "PlatformIOLibBuilder"
        else:
            used_frameworks = LibBuilderFactory.get_used_frameworks(env, path)
            common_frameworks = set(env.get("PIOFRAMEWORK", [])) & set(used_frameworks)
            if common_frameworks:
                clsname = "%sLibBuilder" % list(common_frameworks)[0].title()
            elif used_frameworks:
                clsname = "%sLibBuilder" % used_frameworks[0].title()

        obj = getattr(sys.modules[__name__], clsname)(env, path, verbose=verbose)

        # Handle PlatformIOLibBuilder.manifest.build.builder
        # pylint: disable=protected-access
        if isinstance(obj, PlatformIOLibBuilder) and obj._manifest.get("build", {}).get(
            "builder"
        ):
            obj = getattr(
                sys.modules[__name__], obj._manifest.get("build", {}).get("builder")
            )(env, path, verbose=verbose)

        assert isinstance(obj, LibBuilderBase)
        return obj

    @staticmethod
    def get_used_frameworks(env, path):
        if any(
            os.path.isfile(os.path.join(path, fname))
            for fname in ("library.properties", "keywords.txt")
        ):
            return ["arduino"]

        if os.path.isfile(os.path.join(path, "module.json")):
            return ["mbed"]

        include_re = re.compile(
            r'^#include\s+(<|")(Arduino|mbed)\.h(<|")', flags=re.MULTILINE
        )

        # check source files
        for root, _, files in os.walk(path, followlinks=True):
            if "mbed_lib.json" in files:
                return ["mbed"]
            for fname in files:
                if not fs.path_endswith_ext(
                    fname, piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT
                ):
                    continue
                with io.open(
                    os.path.join(root, fname), encoding="utf8", errors="ignore"
                ) as fp:
                    content = fp.read()
                if not content:
                    continue
                if "Arduino.h" in content and include_re.search(content):
                    return ["arduino"]
                if "mbed.h" in content and include_re.search(content):
                    return ["mbed"]
        return []


class LibBuilderBase(object):

    CLASSIC_SCANNER = SCons.Scanner.C.CScanner()
    CCONDITIONAL_SCANNER = SCons.Scanner.C.CConditionalScanner()
    # Max depth of nested includes:
    # -1 = unlimited
    # 0 - disabled nesting
    # >0 - number of allowed nested includes
    CCONDITIONAL_SCANNER_DEPTH = 99
    PARSE_SRC_BY_H_NAME = True

    _INCLUDE_DIRS_CACHE = None

    def __init__(self, env, path, manifest=None, verbose=False):
        self.env = env.Clone()
        self.envorigin = env.Clone()
        self.path = os.path.abspath(env.subst(path))
        self.verbose = verbose

        try:
            self._manifest = manifest if manifest else self.load_manifest()
        except ManifestParserError:
            click.secho(
                "Warning! Ignoring broken library manifest in " + self.path, fg="yellow"
            )
            self._manifest = {}

        self.is_dependent = False
        self.is_built = False
        self.depbuilders = []

        self._deps_are_processed = False
        self._circular_deps = []
        self._processed_files = []

        # reset source filter, could be overridden with extra script
        self.env["SRC_FILTER"] = ""

        # process extra options and append to build environment
        self.process_extra_options()

    def __repr__(self):
        return "%s(%r)" % (self.__class__, self.path)

    def __contains__(self, path):
        p1 = self.path
        p2 = path
        if IS_WINDOWS:
            p1 = p1.lower()
            p2 = p2.lower()
        if p1 == p2:
            return True
        return os.path.commonprefix((p1 + os.path.sep, p2)) == p1 + os.path.sep

    @property
    def name(self):
        return self._manifest.get("name", os.path.basename(self.path))

    @property
    def version(self):
        return self._manifest.get("version")

    @property
    def dependencies(self):
        return self._manifest.get("dependencies")

    @property
    def src_filter(self):
        return piotool.SRC_FILTER_DEFAULT + [
            "-<example%s>" % os.sep,
            "-<examples%s>" % os.sep,
            "-<test%s>" % os.sep,
            "-<tests%s>" % os.sep,
        ]

    @property
    def include_dir(self):
        for name in ("include", "Include"):
            d = os.path.join(self.path, name)
            if os.path.isdir(d):
                return d
        return None

    @property
    def src_dir(self):
        for name in ("src", "Src"):
            d = os.path.join(self.path, name)<commit_msg>Add backward compatibility with ESP-IDF build script // Resolve #4225<commit_after># Copyright (c) 2014-present PlatformIO <<EMAIL>>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# pylint: disable=no-self-use, unused-argument, too-many-lines
# pylint: disable=too-many-instance-attributes, too-many-public-methods
# pylint: disable=assignment-from-no-return

from __future__ import absolute_import

import hashlib
import io
import os
import re
import sys

import click
import SCons.Scanner  # pylint: disable=import-error
from SCons.Script import ARGUMENTS  # pylint: disable=import-error
from SCons.Script import COMMAND_LINE_TARGETS  # pylint: disable=import-error
from SCons.Script import DefaultEnvironment  # pylint: disable=import-error

from platformio import exception, fs, util
from platformio.builder.tools import platformio as piotool
from platformio.clients.http import HTTPClientError, InternetIsOffline
from platformio.compat import IS_WINDOWS, hashlib_encode_data, string_types
from platformio.package.exception import (
    MissingPackageManifestError,
    UnknownPackageError,
)
from platformio.package.manager.library import LibraryPackageManager
from platformio.package.manifest.parser import (
    ManifestParserError,
    ManifestParserFactory,
)
from platformio.package.meta import PackageItem
from platformio.project.options import ProjectOptions


class LibBuilderFactory(object):
    @staticmethod
    def new(env, path, verbose=int(ARGUMENTS.get("PIOVERBOSE", 0))):
        clsname = "UnknownLibBuilder"
        if os.path.isfile(os.path.join(path, "library.json")):
            clsname = "PlatformIOLibBuilder"
        else:
            used_frameworks = LibBuilderFactory.get_used_frameworks(env, path)
            common_frameworks = set(env.get("PIOFRAMEWORK", [])) & set(used_frameworks)
            if common_frameworks:
                clsname = "%sLibBuilder" % list(common_frameworks)[0].title()
            elif used_frameworks:
                clsname = "%sLibBuilder" % used_frameworks[0].title()

        obj = getattr(sys.modules[__name__], clsname)(env, path, verbose=verbose)

        # Handle PlatformIOLibBuilder.manifest.build.builder
        # pylint: disable=protected-access
        if isinstance(obj, PlatformIOLibBuilder) and obj._manifest.get("build", {}).get(
            "builder"
        ):
            obj = getattr(
                sys.modules[__name__], obj._manifest.get("build", {}).get("builder")
            )(env, path, verbose=verbose)

        assert isinstance(obj, LibBuilderBase)
        return obj

    @staticmethod
    def get_used_frameworks(env, path):
        if any(
            os.path.isfile(os.path.join(path, fname))
            for fname in ("library.properties", "keywords.txt")
        ):
            return ["arduino"]

        if os.path.isfile(os.path.join(path, "module.json")):
            return ["mbed"]

        include_re = re.compile(
            r'^#include\s+(<|")(Arduino|mbed)\.h(<|")', flags=re.MULTILINE
        )

        # check source files
        for root, _, files in os.walk(path, followlinks=True):
            if "mbed_lib.json" in files:
                return ["mbed"]
            for fname in files:
                if not fs.path_endswith_ext(
                    fname, piotool.SRC_BUILD_EXT + piotool.SRC_HEADER_EXT
                ):
                    continue
                with io.open(
                    os.path.join(root, fname), encoding="utf8", errors="ignore"
                ) as fp:
                    content = fp.read()
                if not content:
                    continue
                if "Arduino.h" in content and include_re.search(content):
                    return ["arduino"]
                if "mbed.h" in content and include_re.search(content):
                    return ["mbed"]
        return []


class LibBuilderBase(object):

    CLASSIC_SCANNER = SCons.Scanner.C.CScanner()
    CCONDITIONAL_SCANNER = SCons.Scanner.C.CConditionalScanner()
    # Max depth of nested includes:
    # -1 = unlimited
    # 0 - disabled nesting
    # >0 - number of allowed nested includes
    CCONDITIONAL_SCANNER_DEPTH = 99
    PARSE_SRC_BY_H_NAME = True

    _INCLUDE_DIRS_CACHE = None

    def __init__(self, env, path, manifest=None, verbose=False):
        self.env = env.Clone()
        self.envorigin = env.Clone()
        self.path = os.path.abspath(env.subst(path))
        self.verbose = verbose

        try:
            self._manifest = manifest if manifest else self.load_manifest()
        except ManifestParserError:
            click.secho(
                "Warning! Ignoring broken library manifest in " + self.path, fg="yellow"
            )
            self._manifest = {}

        self.is_dependent = False
        self.is_built = False
        self.depbuilders = []

        self._deps_are_processed = False
        self._circular_deps = []
        self._processed_files = []

        # reset source filter, could be overridden with extra script
        self.env["SRC_FILTER"] = ""

        # process extra options and append to build environment
        self.process_extra_options()

    def __repr__(self):
        return "%s(%r)" % (self.__class__, self.path)

    def __contains__(self, path):
        p1 = self.path
        p2 = path
        if IS_WINDOWS:
            p1 = p1.lower()
            p2 = p2.lower()
        if p1 == p2:
            return True
        return os.path.commonprefix((p1 + os.path.sep, p2)) == p1 + os.path.sep

    @property
    def name(self):
        return self._manifest.get("name", os.path.basename(self.path))

    @property
    def version(self):
        return self._manifest.get("version")

    @property
    def dependent(self):
        """Backward compatibility with ESP-IDF"""
        return self.is_dependent

    @property
    def dependencies(self):
        return self._manifest.get("dependencies")

    @property
    def src_filter(self):
        return piotool.SRC_FILTER_DEFAULT + [
            "-<example%s>" % os.sep,
            "-<examples%s>" % os.sep,
            "-<test%s>" % os.sep,
            "-<tests%s>" % os.sep,
        ]

    @property
    def include_dir(self):
        for name in ("include", "Include"):
            d = os.path.join(self.path, name)
            if os.path.isdir(d):
                return d
        return None

    @property
    def src_dir(self):
        for name in ("src", "Src"):
            d = os.path.join(self.path, name)
{'fraction_non_alphanumeric': 0.10324548028751906, 'fraction_numerical': 0.004356349379220213, 'mean_word_length': 2.381782469923889, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4421155', 'n_tokens_mistral': 4106, 'n_tokens_neox': 3915, 'n_words': 1004}