mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
ci: Add python types hints
This commit is contained in:
parent
05b31339f6
commit
819d5a2b61
@ -17,14 +17,14 @@ if not IDF_PATH:
|
|||||||
GITLAB_CONFIG_FILE = os.path.join(IDF_PATH, '.gitlab-ci.yml')
|
GITLAB_CONFIG_FILE = os.path.join(IDF_PATH, '.gitlab-ci.yml')
|
||||||
|
|
||||||
|
|
||||||
def check_artifacts_expire_time():
|
def check_artifacts_expire_time() -> None:
|
||||||
with open(GITLAB_CONFIG_FILE, 'r') as f:
|
with open(GITLAB_CONFIG_FILE, 'r') as f:
|
||||||
config = yaml.load(f, Loader=yaml.FullLoader)
|
config = yaml.load(f, Loader=yaml.FullLoader)
|
||||||
|
|
||||||
# load files listed in `include`
|
# load files listed in `include`
|
||||||
if 'include' in config:
|
if 'include' in config:
|
||||||
for _file in config['include']:
|
for _file in config['include']:
|
||||||
with open(os.path.join(IDF_PATH, _file)) as f:
|
with open(os.path.join(IDF_PATH or '', _file)) as f:
|
||||||
config.update(yaml.load(f, Loader=yaml.FullLoader))
|
config.update(yaml.load(f, Loader=yaml.FullLoader))
|
||||||
|
|
||||||
print('expire time for jobs:')
|
print('expire time for jobs:')
|
||||||
|
@ -8,15 +8,11 @@ import argparse
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from typing import BinaryIO, Callable, Dict, Generator, List, Optional, Tuple
|
||||||
|
|
||||||
import elftools
|
import elftools
|
||||||
from elftools.elf import elffile
|
from elftools.elf import elffile
|
||||||
|
|
||||||
try:
|
|
||||||
from typing import BinaryIO, Callable, Dict, Generator, List, Optional, Tuple
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
FUNCTION_REGEX = re.compile(
|
FUNCTION_REGEX = re.compile(
|
||||||
r'^;; Function (?P<mangle>.*)\s+\((?P<function>\S+)(,.*)?\).*$'
|
r'^;; Function (?P<mangle>.*)\s+\((?P<function>\S+)(,.*)?\).*$'
|
||||||
)
|
)
|
||||||
@ -25,29 +21,29 @@ SYMBOL_REF_REGEX = re.compile(r'^.*\(symbol_ref[^()]*\("(?P<target>.*)"\).*$')
|
|||||||
|
|
||||||
|
|
||||||
class RtlFunction(object):
|
class RtlFunction(object):
|
||||||
def __init__(self, name, rtl_filename, tu_filename):
|
def __init__(self, name: str, rtl_filename: str, tu_filename: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.rtl_filename = rtl_filename
|
self.rtl_filename = rtl_filename
|
||||||
self.tu_filename = tu_filename
|
self.tu_filename = tu_filename
|
||||||
self.calls = list() # type: List[str]
|
self.calls: List[str] = list()
|
||||||
self.refs = list() # type: List[str]
|
self.refs: List[str] = list()
|
||||||
self.sym = None
|
self.sym = None
|
||||||
|
|
||||||
|
|
||||||
class SectionAddressRange(object):
|
class SectionAddressRange(object):
|
||||||
def __init__(self, name, addr, size): # type: (str, int, int) -> None
|
def __init__(self, name: str, addr: int, size: int) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.low = addr
|
self.low = addr
|
||||||
self.high = addr + size
|
self.high = addr + size
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return '{}: 0x{:08x} - 0x{:08x}'.format(self.name, self.low, self.high)
|
return '{}: 0x{:08x} - 0x{:08x}'.format(self.name, self.low, self.high)
|
||||||
|
|
||||||
def contains_address(self, addr):
|
def contains_address(self, addr: int) -> bool:
|
||||||
return self.low <= addr < self.high
|
return self.low <= addr < self.high
|
||||||
|
|
||||||
|
|
||||||
TARGET_SECTIONS = {
|
TARGET_SECTIONS: Dict[str, List[SectionAddressRange]] = {
|
||||||
'esp32': [
|
'esp32': [
|
||||||
SectionAddressRange('.rom.text', 0x40000000, 0x70000),
|
SectionAddressRange('.rom.text', 0x40000000, 0x70000),
|
||||||
SectionAddressRange('.rom.rodata', 0x3ff96000, 0x9018)
|
SectionAddressRange('.rom.rodata', 0x3ff96000, 0x9018)
|
||||||
@ -60,20 +56,20 @@ TARGET_SECTIONS = {
|
|||||||
SectionAddressRange('.rom.text', 0x40000000, 0x568d0),
|
SectionAddressRange('.rom.text', 0x40000000, 0x568d0),
|
||||||
SectionAddressRange('.rom.rodata', 0x3ff071c0, 0x8e30)
|
SectionAddressRange('.rom.rodata', 0x3ff071c0, 0x8e30)
|
||||||
]
|
]
|
||||||
} # type: Dict[str, List[SectionAddressRange]]
|
}
|
||||||
|
|
||||||
|
|
||||||
class Symbol(object):
|
class Symbol(object):
|
||||||
def __init__(self, name, addr, local, filename, section): # type: (str, int, bool, Optional[str], Optional[str]) -> None
|
def __init__(self, name: str, addr: int, local: bool, filename: Optional[str], section: Optional[str]) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.addr = addr
|
self.addr = addr
|
||||||
self.local = local
|
self.local = local
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.section = section
|
self.section = section
|
||||||
self.refers_to = list() # type: List[Symbol]
|
self.refers_to: List[Symbol] = list()
|
||||||
self.referred_from = list() # type: List[Symbol]
|
self.referred_from: List[Symbol] = list()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return '{} @0x{:08x} [{}]{} {}'.format(
|
return '{} @0x{:08x} [{}]{} {}'.format(
|
||||||
self.name,
|
self.name,
|
||||||
self.addr,
|
self.addr,
|
||||||
@ -84,11 +80,11 @@ class Symbol(object):
|
|||||||
|
|
||||||
|
|
||||||
class Reference(object):
|
class Reference(object):
|
||||||
def __init__(self, from_sym, to_sym): # type: (Symbol, Symbol) -> None
|
def __init__(self, from_sym: Symbol, to_sym: Symbol) -> None:
|
||||||
self.from_sym = from_sym
|
self.from_sym = from_sym
|
||||||
self.to_sym = to_sym
|
self.to_sym = to_sym
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return '{} @0x{:08x} ({}) -> {} @0x{:08x} ({})'.format(
|
return '{} @0x{:08x} ({}) -> {} @0x{:08x} ({})'.format(
|
||||||
self.from_sym.name,
|
self.from_sym.name,
|
||||||
self.from_sym.addr,
|
self.from_sym.addr,
|
||||||
@ -100,13 +96,13 @@ class Reference(object):
|
|||||||
|
|
||||||
|
|
||||||
class ElfInfo(object):
|
class ElfInfo(object):
|
||||||
def __init__(self, elf_file): # type: (BinaryIO) -> None
|
def __init__(self, elf_file: BinaryIO) -> None:
|
||||||
self.elf_file = elf_file
|
self.elf_file = elf_file
|
||||||
self.elf_obj = elffile.ELFFile(self.elf_file)
|
self.elf_obj = elffile.ELFFile(self.elf_file)
|
||||||
self.section_ranges = self._load_sections()
|
self.section_ranges = self._load_sections()
|
||||||
self.symbols = self._load_symbols()
|
self.symbols = self._load_symbols()
|
||||||
|
|
||||||
def _load_symbols(self): # type: () -> List[Symbol]
|
def _load_symbols(self) -> List[Symbol]:
|
||||||
symbols = []
|
symbols = []
|
||||||
for s in self.elf_obj.iter_sections():
|
for s in self.elf_obj.iter_sections():
|
||||||
if not isinstance(s, elftools.elf.sections.SymbolTableSection):
|
if not isinstance(s, elftools.elf.sections.SymbolTableSection):
|
||||||
@ -130,7 +126,7 @@ class ElfInfo(object):
|
|||||||
)
|
)
|
||||||
return symbols
|
return symbols
|
||||||
|
|
||||||
def _load_sections(self): # type: () -> List[SectionAddressRange]
|
def _load_sections(self) -> List[SectionAddressRange]:
|
||||||
result = []
|
result = []
|
||||||
for segment in self.elf_obj.iter_segments():
|
for segment in self.elf_obj.iter_segments():
|
||||||
if segment['p_type'] == 'PT_LOAD':
|
if segment['p_type'] == 'PT_LOAD':
|
||||||
@ -149,22 +145,22 @@ class ElfInfo(object):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def symbols_by_name(self, name): # type: (str) -> List[Symbol]
|
def symbols_by_name(self, name: str) -> List['Symbol']:
|
||||||
res = []
|
res = []
|
||||||
for sym in self.symbols:
|
for sym in self.symbols:
|
||||||
if sym.name == name:
|
if sym.name == name:
|
||||||
res.append(sym)
|
res.append(sym)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def section_for_addr(self, sym_addr): # type: (int) -> Optional[str]
|
def section_for_addr(self, sym_addr: int) -> Optional[str]:
|
||||||
for sar in self.section_ranges:
|
for sar in self.section_ranges:
|
||||||
if sar.contains_address(sym_addr):
|
if sar.contains_address(sym_addr):
|
||||||
return sar.name
|
return sar.name
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def load_rtl_file(rtl_filename, tu_filename, functions): # type: (str, str, List[RtlFunction]) -> None
|
def load_rtl_file(rtl_filename: str, tu_filename: str, functions: List[RtlFunction]) -> None:
|
||||||
last_function = None # type: Optional[RtlFunction]
|
last_function: Optional[RtlFunction] = None
|
||||||
for line in open(rtl_filename):
|
for line in open(rtl_filename):
|
||||||
# Find function definition
|
# Find function definition
|
||||||
match = re.match(FUNCTION_REGEX, line)
|
match = re.match(FUNCTION_REGEX, line)
|
||||||
@ -192,7 +188,7 @@ def load_rtl_file(rtl_filename, tu_filename, functions): # type: (str, str, Lis
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
def rtl_filename_matches_sym_filename(rtl_filename, symbol_filename): # type: (str, str) -> bool
|
def rtl_filename_matches_sym_filename(rtl_filename: str, symbol_filename: str) -> bool:
|
||||||
# Symbol file names (from ELF debug info) are short source file names, without path: "cpu_start.c".
|
# Symbol file names (from ELF debug info) are short source file names, without path: "cpu_start.c".
|
||||||
# RTL file names are paths relative to the build directory, e.g.:
|
# RTL file names are paths relative to the build directory, e.g.:
|
||||||
# "build/esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/cpu_start.c.234r.expand"
|
# "build/esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/cpu_start.c.234r.expand"
|
||||||
@ -211,7 +207,7 @@ class SymbolNotFound(RuntimeError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def find_symbol_by_name(name, elfinfo, local_func_matcher): # type: (str, ElfInfo, Callable[[Symbol], bool]) -> Optional[Symbol]
|
def find_symbol_by_name(name: str, elfinfo: ElfInfo, local_func_matcher: Callable[[Symbol], bool]) -> Optional[Symbol]:
|
||||||
"""
|
"""
|
||||||
Find an ELF symbol for the given name.
|
Find an ELF symbol for the given name.
|
||||||
local_func_matcher is a callback function which checks is the candidate local symbol is suitable.
|
local_func_matcher is a callback function which checks is the candidate local symbol is suitable.
|
||||||
@ -238,7 +234,7 @@ def find_symbol_by_name(name, elfinfo, local_func_matcher): # type: (str, ElfIn
|
|||||||
return local_candidate or global_candidate
|
return local_candidate or global_candidate
|
||||||
|
|
||||||
|
|
||||||
def match_local_source_func(rtl_filename, sym): # type: (str, Symbol) -> bool
|
def match_local_source_func(rtl_filename: str, sym: Symbol) -> bool:
|
||||||
"""
|
"""
|
||||||
Helper for match_rtl_funcs_to_symbols, checks if local symbol sym is a good candidate for the
|
Helper for match_rtl_funcs_to_symbols, checks if local symbol sym is a good candidate for the
|
||||||
reference source (caller), based on the RTL file name.
|
reference source (caller), based on the RTL file name.
|
||||||
@ -247,7 +243,7 @@ def match_local_source_func(rtl_filename, sym): # type: (str, Symbol) -> bool
|
|||||||
return rtl_filename_matches_sym_filename(rtl_filename, sym.filename)
|
return rtl_filename_matches_sym_filename(rtl_filename, sym.filename)
|
||||||
|
|
||||||
|
|
||||||
def match_local_target_func(rtl_filename, sym_from, sym): # type: (str, Symbol, Symbol) -> bool
|
def match_local_target_func(rtl_filename: str, sym_from: Symbol, sym: Symbol) -> bool:
|
||||||
"""
|
"""
|
||||||
Helper for match_rtl_funcs_to_symbols, checks if local symbol sym is a good candidate for the
|
Helper for match_rtl_funcs_to_symbols, checks if local symbol sym is a good candidate for the
|
||||||
reference target (callee or referenced data), based on RTL filename of the source symbol
|
reference target (callee or referenced data), based on RTL filename of the source symbol
|
||||||
@ -263,9 +259,9 @@ def match_local_target_func(rtl_filename, sym_from, sym): # type: (str, Symbol,
|
|||||||
return rtl_filename_matches_sym_filename(rtl_filename, sym.filename)
|
return rtl_filename_matches_sym_filename(rtl_filename, sym.filename)
|
||||||
|
|
||||||
|
|
||||||
def match_rtl_funcs_to_symbols(rtl_functions, elfinfo): # type: (List[RtlFunction], ElfInfo) -> Tuple[List[Symbol], List[Reference]]
|
def match_rtl_funcs_to_symbols(rtl_functions: List[RtlFunction], elfinfo: ElfInfo) -> Tuple[List[Symbol], List[Reference]]:
|
||||||
symbols = [] # type: List[Symbol]
|
symbols: List[Symbol] = []
|
||||||
refs = [] # type: List[Reference]
|
refs: List[Reference] = []
|
||||||
|
|
||||||
# General idea:
|
# General idea:
|
||||||
# - iterate over RTL functions.
|
# - iterate over RTL functions.
|
||||||
@ -308,17 +304,17 @@ def match_rtl_funcs_to_symbols(rtl_functions, elfinfo): # type: (List[RtlFuncti
|
|||||||
return symbols, refs
|
return symbols, refs
|
||||||
|
|
||||||
|
|
||||||
def get_symbols_and_refs(rtl_list, elf_file): # type: (List[str], BinaryIO) -> Tuple[List[Symbol], List[Reference]]
|
def get_symbols_and_refs(rtl_list: List[str], elf_file: BinaryIO) -> Tuple[List[Symbol], List[Reference]]:
|
||||||
elfinfo = ElfInfo(elf_file)
|
elfinfo = ElfInfo(elf_file)
|
||||||
|
|
||||||
rtl_functions = [] # type: List[RtlFunction]
|
rtl_functions: List[RtlFunction] = []
|
||||||
for file_name in rtl_list:
|
for file_name in rtl_list:
|
||||||
load_rtl_file(file_name, file_name, rtl_functions)
|
load_rtl_file(file_name, file_name, rtl_functions)
|
||||||
|
|
||||||
return match_rtl_funcs_to_symbols(rtl_functions, elfinfo)
|
return match_rtl_funcs_to_symbols(rtl_functions, elfinfo)
|
||||||
|
|
||||||
|
|
||||||
def list_refs_from_to_sections(refs, from_sections, to_sections): # type: (List[Reference], List[str], List[str]) -> int
|
def list_refs_from_to_sections(refs: List[Reference], from_sections: List[str], to_sections: List[str]) -> int:
|
||||||
found = 0
|
found = 0
|
||||||
for ref in refs:
|
for ref in refs:
|
||||||
if (not from_sections or ref.from_sym.section in from_sections) and \
|
if (not from_sections or ref.from_sym.section in from_sections) and \
|
||||||
@ -328,7 +324,7 @@ def list_refs_from_to_sections(refs, from_sections, to_sections): # type: (List
|
|||||||
return found
|
return found
|
||||||
|
|
||||||
|
|
||||||
def find_files_recursive(root_path, ext): # type: (str, str) -> Generator[str, None, None]
|
def find_files_recursive(root_path: str, ext: str) -> Generator[str, None, None]:
|
||||||
for root, _, files in os.walk(root_path):
|
for root, _, files in os.walk(root_path):
|
||||||
for basename in files:
|
for basename in files:
|
||||||
if basename.endswith(ext):
|
if basename.endswith(ext):
|
||||||
@ -336,7 +332,7 @@ def find_files_recursive(root_path, ext): # type: (str, str) -> Generator[str,
|
|||||||
yield filename
|
yield filename
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -379,7 +375,7 @@ def main():
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.rtl_list:
|
if args.rtl_list:
|
||||||
with open(args.rtl_list, 'r') as rtl_list_file:
|
with open(args.rtl_list, 'r') as rtl_list_file:
|
||||||
rtl_list = [line.strip for line in rtl_list_file]
|
rtl_list = [line.strip() for line in rtl_list_file]
|
||||||
else:
|
else:
|
||||||
if not args.rtl_dir:
|
if not args.rtl_dir:
|
||||||
raise RuntimeError('Either --rtl-list or --rtl-dir must be specified')
|
raise RuntimeError('Either --rtl-list or --rtl-dir must be specified')
|
||||||
|
@ -10,6 +10,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
from idf_ci_utils import IDF_PATH
|
from idf_ci_utils import IDF_PATH
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ CODEOWNERS_PATH = os.path.join(IDF_PATH, '.gitlab', 'CODEOWNERS')
|
|||||||
CODEOWNER_GROUP_PREFIX = '@esp-idf-codeowners/'
|
CODEOWNER_GROUP_PREFIX = '@esp-idf-codeowners/'
|
||||||
|
|
||||||
|
|
||||||
def get_all_files():
|
def get_all_files() -> List[str]:
|
||||||
"""
|
"""
|
||||||
Get list of all file paths in the repository.
|
Get list of all file paths in the repository.
|
||||||
"""
|
"""
|
||||||
@ -25,7 +26,7 @@ def get_all_files():
|
|||||||
return subprocess.check_output(['git', 'ls-files'], cwd=IDF_PATH).decode('utf-8').strip().split('\n')
|
return subprocess.check_output(['git', 'ls-files'], cwd=IDF_PATH).decode('utf-8').strip().split('\n')
|
||||||
|
|
||||||
|
|
||||||
def pattern_to_regex(pattern):
|
def pattern_to_regex(pattern: str) -> str:
|
||||||
"""
|
"""
|
||||||
Convert the CODEOWNERS path pattern into a regular expression string.
|
Convert the CODEOWNERS path pattern into a regular expression string.
|
||||||
"""
|
"""
|
||||||
@ -59,14 +60,14 @@ def pattern_to_regex(pattern):
|
|||||||
return re_pattern
|
return re_pattern
|
||||||
|
|
||||||
|
|
||||||
def files_by_regex(all_files, regex):
|
def files_by_regex(all_files: List, regex: re.Pattern) -> List:
|
||||||
"""
|
"""
|
||||||
Return all files in the repository matching the given regular expresion.
|
Return all files in the repository matching the given regular expresion.
|
||||||
"""
|
"""
|
||||||
return [file for file in all_files if regex.search('/' + file)]
|
return [file for file in all_files if regex.search('/' + file)]
|
||||||
|
|
||||||
|
|
||||||
def files_by_pattern(all_files, pattern=None):
|
def files_by_pattern(all_files: list, pattern: Optional[str]=None) -> List:
|
||||||
"""
|
"""
|
||||||
Return all the files in the repository matching the given CODEOWNERS pattern.
|
Return all the files in the repository matching the given CODEOWNERS pattern.
|
||||||
"""
|
"""
|
||||||
@ -76,7 +77,7 @@ def files_by_pattern(all_files, pattern=None):
|
|||||||
return files_by_regex(all_files, re.compile(pattern_to_regex(pattern)))
|
return files_by_regex(all_files, re.compile(pattern_to_regex(pattern)))
|
||||||
|
|
||||||
|
|
||||||
def action_identify(args):
|
def action_identify(args: argparse.Namespace) -> None:
|
||||||
best_match = []
|
best_match = []
|
||||||
all_files = get_all_files()
|
all_files = get_all_files()
|
||||||
with open(CODEOWNERS_PATH) as f:
|
with open(CODEOWNERS_PATH) as f:
|
||||||
@ -94,7 +95,7 @@ def action_identify(args):
|
|||||||
print(owner)
|
print(owner)
|
||||||
|
|
||||||
|
|
||||||
def action_test_pattern(args):
|
def action_test_pattern(args: argparse.Namespace) -> None:
|
||||||
re_pattern = pattern_to_regex(args.pattern)
|
re_pattern = pattern_to_regex(args.pattern)
|
||||||
|
|
||||||
if args.regex:
|
if args.regex:
|
||||||
@ -106,10 +107,10 @@ def action_test_pattern(args):
|
|||||||
print(f)
|
print(f)
|
||||||
|
|
||||||
|
|
||||||
def action_ci_check(args):
|
def action_ci_check(args: argparse.Namespace) -> None:
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
def add_error(msg):
|
def add_error(msg: str) -> None:
|
||||||
errors.append('{}:{}: {}'.format(CODEOWNERS_PATH, line_no, msg))
|
errors.append('{}:{}: {}'.format(CODEOWNERS_PATH, line_no, msg))
|
||||||
|
|
||||||
all_files = get_all_files()
|
all_files = get_all_files()
|
||||||
@ -158,7 +159,7 @@ def action_ci_check(args):
|
|||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
|
|
||||||
def in_order(prev, current):
|
def in_order(prev: str, current: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Return True if the ordering is correct for these two lines ('prev' should be before 'current').
|
Return True if the ordering is correct for these two lines ('prev' should be before 'current').
|
||||||
|
|
||||||
@ -172,10 +173,10 @@ def in_order(prev, current):
|
|||||||
if not prev:
|
if not prev:
|
||||||
return True # first element in file
|
return True # first element in file
|
||||||
|
|
||||||
def is_separator(c):
|
def is_separator(c: str) -> bool:
|
||||||
return c in '-_/' # ignore differences between separators for ordering purposes
|
return c in '-_/' # ignore differences between separators for ordering purposes
|
||||||
|
|
||||||
def is_wildcard(c):
|
def is_wildcard(c: str) -> bool:
|
||||||
return c in '?*'
|
return c in '?*'
|
||||||
|
|
||||||
# looping until we see a different character
|
# looping until we see a different character
|
||||||
@ -192,7 +193,7 @@ def in_order(prev, current):
|
|||||||
return len(current) >= len(prev)
|
return len(current) >= len(prev)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
sys.argv[0], description='Internal helper script for working with the CODEOWNERS file.'
|
sys.argv[0], description='Internal helper script for working with the CODEOWNERS file.'
|
||||||
)
|
)
|
||||||
|
@ -2028,7 +2028,6 @@ tools/ble/lib_ble_client.py
|
|||||||
tools/ble/lib_gap.py
|
tools/ble/lib_gap.py
|
||||||
tools/ble/lib_gatt.py
|
tools/ble/lib_gatt.py
|
||||||
tools/catch/catch.hpp
|
tools/catch/catch.hpp
|
||||||
tools/esp_app_trace/test/sysview/blink.c
|
|
||||||
tools/find_build_apps/__init__.py
|
tools/find_build_apps/__init__.py
|
||||||
tools/find_build_apps/cmake.py
|
tools/find_build_apps/cmake.py
|
||||||
tools/find_build_apps/common.py
|
tools/find_build_apps/common.py
|
||||||
|
@ -9,6 +9,7 @@ import argparse
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from io import open
|
from io import open
|
||||||
|
from typing import Set, Tuple
|
||||||
|
|
||||||
from check_kconfigs import valid_directory
|
from check_kconfigs import valid_directory
|
||||||
from idf_ci_utils import get_submodule_dirs
|
from idf_ci_utils import get_submodule_dirs
|
||||||
@ -19,11 +20,11 @@ FILES_TO_CHECK = ('sdkconfig.ci', 'sdkconfig.defaults')
|
|||||||
# ignored directories (makes sense only when run on IDF_PATH)
|
# ignored directories (makes sense only when run on IDF_PATH)
|
||||||
# Note: IGNORE_DIRS is a tuple in order to be able to use it directly with the startswith() built-in function which
|
# Note: IGNORE_DIRS is a tuple in order to be able to use it directly with the startswith() built-in function which
|
||||||
# accepts tuples but no lists.
|
# accepts tuples but no lists.
|
||||||
IGNORE_DIRS = (
|
IGNORE_DIRS: Tuple = (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_path(path, sep=None):
|
def _parse_path(path: os.PathLike[str], sep: str=None) -> Set:
|
||||||
ret = set()
|
ret = set()
|
||||||
with open(path, 'r', encoding='utf-8') as f:
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
@ -33,13 +34,13 @@ def _parse_path(path, sep=None):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def _valid_directory(path):
|
def _valid_directory(path: os.PathLike[str]) -> os.PathLike[str]:
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
raise argparse.ArgumentTypeError('{} is not a valid directory!'.format(path))
|
raise argparse.ArgumentTypeError('{} is not a valid directory!'.format(path))
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def check() -> int:
|
||||||
parser = argparse.ArgumentParser(description='Kconfig options checker')
|
parser = argparse.ArgumentParser(description='Kconfig options checker')
|
||||||
parser.add_argument('files', nargs='*',
|
parser.add_argument('files', nargs='*',
|
||||||
help='Kconfig files')
|
help='Kconfig files')
|
||||||
@ -102,5 +103,9 @@ def main():
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
sys.exit(check())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.exit(main())
|
main()
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Iterable, List
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from idf_ci_utils import is_executable
|
from idf_ci_utils import is_executable
|
||||||
@ -15,7 +16,7 @@ except ImportError:
|
|||||||
from idf_ci_utils import is_executable
|
from idf_ci_utils import is_executable
|
||||||
|
|
||||||
|
|
||||||
def _strip_each_item(iterable):
|
def _strip_each_item(iterable: Iterable) -> List:
|
||||||
res = []
|
res = []
|
||||||
for item in iterable:
|
for item in iterable:
|
||||||
if item:
|
if item:
|
||||||
@ -28,7 +29,7 @@ EXECUTABLE_LIST_FN = os.path.join(IDF_PATH, 'tools/ci/executable-list.txt')
|
|||||||
known_executables = _strip_each_item(open(EXECUTABLE_LIST_FN).readlines())
|
known_executables = _strip_each_item(open(EXECUTABLE_LIST_FN).readlines())
|
||||||
|
|
||||||
|
|
||||||
def check_executable_list():
|
def check_executable_list() -> int:
|
||||||
ret = 0
|
ret = 0
|
||||||
for index, fn in enumerate(known_executables):
|
for index, fn in enumerate(known_executables):
|
||||||
if not os.path.exists(os.path.join(IDF_PATH, fn)):
|
if not os.path.exists(os.path.join(IDF_PATH, fn)):
|
||||||
@ -37,7 +38,7 @@ def check_executable_list():
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def check_executables(files):
|
def check_executables(files: List) -> int:
|
||||||
ret = 0
|
ret = 0
|
||||||
for fn in files:
|
for fn in files:
|
||||||
fn_executable = is_executable(fn)
|
fn_executable = is_executable(fn)
|
||||||
@ -51,7 +52,7 @@ def check_executables(files):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def check() -> int:
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('--action', choices=['executables', 'list'], required=True,
|
parser.add_argument('--action', choices=['executables', 'list'], required=True,
|
||||||
help='if "executables", pass all your executables to see if it\'s in the list.'
|
help='if "executables", pass all your executables to see if it\'s in the list.'
|
||||||
@ -70,4 +71,4 @@ def main():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.exit(main())
|
sys.exit(check())
|
||||||
|
@ -18,6 +18,7 @@ import subprocess
|
|||||||
import tempfile
|
import tempfile
|
||||||
from io import open
|
from io import open
|
||||||
from threading import Event, Thread
|
from threading import Event, Thread
|
||||||
|
from typing import List, Optional, Set, Tuple, Union
|
||||||
|
|
||||||
|
|
||||||
class HeaderFailed(Exception):
|
class HeaderFailed(Exception):
|
||||||
@ -26,28 +27,28 @@ class HeaderFailed(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class HeaderFailedSdkconfig(HeaderFailed):
|
class HeaderFailedSdkconfig(HeaderFailed):
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return 'Sdkconfig Error'
|
return 'Sdkconfig Error'
|
||||||
|
|
||||||
|
|
||||||
class HeaderFailedBuildError(HeaderFailed):
|
class HeaderFailedBuildError(HeaderFailed):
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return 'Header Build Error'
|
return 'Header Build Error'
|
||||||
|
|
||||||
|
|
||||||
class HeaderFailedCppGuardMissing(HeaderFailed):
|
class HeaderFailedCppGuardMissing(HeaderFailed):
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return 'Header Missing C++ Guard'
|
return 'Header Missing C++ Guard'
|
||||||
|
|
||||||
|
|
||||||
class HeaderFailedContainsCode(HeaderFailed):
|
class HeaderFailedContainsCode(HeaderFailed):
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return 'Header Produced non-zero object'
|
return 'Header Produced non-zero object'
|
||||||
|
|
||||||
|
|
||||||
# Creates a temp file and returns both output as a string and a file name
|
# Creates a temp file and returns both output as a string and a file name
|
||||||
#
|
#
|
||||||
def exec_cmd_to_temp_file(what, suffix=''):
|
def exec_cmd_to_temp_file(what: List, suffix: str='') -> Tuple[int, str, str, str, str]:
|
||||||
out_file = tempfile.NamedTemporaryFile(suffix=suffix, delete=False)
|
out_file = tempfile.NamedTemporaryFile(suffix=suffix, delete=False)
|
||||||
rc, out, err, cmd = exec_cmd(what, out_file)
|
rc, out, err, cmd = exec_cmd(what, out_file)
|
||||||
with open(out_file.name, 'r', encoding='utf-8') as f:
|
with open(out_file.name, 'r', encoding='utf-8') as f:
|
||||||
@ -55,12 +56,12 @@ def exec_cmd_to_temp_file(what, suffix=''):
|
|||||||
return rc, out, err, out_file.name, cmd
|
return rc, out, err, out_file.name, cmd
|
||||||
|
|
||||||
|
|
||||||
def exec_cmd(what, out_file=subprocess.PIPE):
|
def exec_cmd(what: List, out_file: Union[tempfile._TemporaryFileWrapper[bytes], int]=subprocess.PIPE) -> Tuple[int, str, str, str]:
|
||||||
p = subprocess.Popen(what, stdin=subprocess.PIPE, stdout=out_file, stderr=subprocess.PIPE)
|
p = subprocess.Popen(what, stdin=subprocess.PIPE, stdout=out_file, stderr=subprocess.PIPE)
|
||||||
output, err = p.communicate()
|
output_b, err_b = p.communicate()
|
||||||
rc = p.returncode
|
rc = p.returncode
|
||||||
output = output.decode('utf-8') if output is not None else None
|
output: str = output_b.decode('utf-8') if output is not None else ''
|
||||||
err = err.decode('utf-8') if err is not None else None
|
err: str = err_b.decode('utf-8') if err is not None else ''
|
||||||
return rc, output, err, ' '.join(what)
|
return rc, output, err, ' '.join(what)
|
||||||
|
|
||||||
|
|
||||||
@ -74,11 +75,11 @@ class PublicHeaderChecker:
|
|||||||
PREPROC_OUT_DIFFERENT_WITH_EXT_C_HDR_OK = 6 # -> Both preprocessors produce different, non-zero output with extern "C" (header seems OK)
|
PREPROC_OUT_DIFFERENT_WITH_EXT_C_HDR_OK = 6 # -> Both preprocessors produce different, non-zero output with extern "C" (header seems OK)
|
||||||
PREPROC_OUT_DIFFERENT_NO_EXT_C_HDR_FAILED = 7 # -> Both preprocessors produce different, non-zero output without extern "C" (header fails)
|
PREPROC_OUT_DIFFERENT_NO_EXT_C_HDR_FAILED = 7 # -> Both preprocessors produce different, non-zero output without extern "C" (header fails)
|
||||||
|
|
||||||
def log(self, message, debug=False):
|
def log(self, message: str, debug: bool=False) -> None:
|
||||||
if self.verbose or debug:
|
if self.verbose or debug:
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
def __init__(self, verbose=False, jobs=1, prefix=None):
|
def __init__(self, verbose: bool=False, jobs: int=1, prefix: Optional[str]=None) -> None:
|
||||||
self.gcc = '{}gcc'.format(prefix)
|
self.gcc = '{}gcc'.format(prefix)
|
||||||
self.gpp = '{}g++'.format(prefix)
|
self.gpp = '{}g++'.format(prefix)
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
@ -89,26 +90,26 @@ class PublicHeaderChecker:
|
|||||||
self.error_orphan_kconfig = re.compile(r'#error CONFIG_VARS_USED_WHILE_SDKCONFIG_NOT_INCLUDED')
|
self.error_orphan_kconfig = re.compile(r'#error CONFIG_VARS_USED_WHILE_SDKCONFIG_NOT_INCLUDED')
|
||||||
self.kconfig_macro = re.compile(r'\bCONFIG_[A-Z0-9_]+')
|
self.kconfig_macro = re.compile(r'\bCONFIG_[A-Z0-9_]+')
|
||||||
self.assembly_nocode = r'^\s*(\.file|\.text|\.ident|\.option|\.attribute).*$'
|
self.assembly_nocode = r'^\s*(\.file|\.text|\.ident|\.option|\.attribute).*$'
|
||||||
self.check_threads = []
|
self.check_threads: List[Thread] = []
|
||||||
|
|
||||||
self.job_queue = queue.Queue()
|
self.job_queue: queue.Queue = queue.Queue()
|
||||||
self.failed_queue = queue.Queue()
|
self.failed_queue: queue.Queue = queue.Queue()
|
||||||
self.terminate = Event()
|
self.terminate = Event()
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self) -> 'PublicHeaderChecker':
|
||||||
for i in range(self.jobs):
|
for i in range(self.jobs):
|
||||||
t = Thread(target=self.check_headers, args=(i, ))
|
t = Thread(target=self.check_headers, args=(i, ))
|
||||||
self.check_threads.append(t)
|
self.check_threads.append(t)
|
||||||
t.start()
|
t.start()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def __exit__(self, exc_type: str, exc_value: str, traceback: str) -> None:
|
||||||
self.terminate.set()
|
self.terminate.set()
|
||||||
for t in self.check_threads:
|
for t in self.check_threads:
|
||||||
t.join()
|
t.join()
|
||||||
|
|
||||||
# thread function process incoming header file from a queue
|
# thread function process incoming header file from a queue
|
||||||
def check_headers(self, num):
|
def check_headers(self, num: int) -> None:
|
||||||
while not self.terminate.is_set():
|
while not self.terminate.is_set():
|
||||||
if not self.job_queue.empty():
|
if not self.job_queue.empty():
|
||||||
task = self.job_queue.get()
|
task = self.job_queue.get()
|
||||||
@ -125,10 +126,10 @@ class PublicHeaderChecker:
|
|||||||
self.terminate.set()
|
self.terminate.set()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def get_failed(self):
|
def get_failed(self) -> List:
|
||||||
return list(self.failed_queue.queue)
|
return list(self.failed_queue.queue)
|
||||||
|
|
||||||
def join(self):
|
def join(self) -> None:
|
||||||
for t in self.check_threads:
|
for t in self.check_threads:
|
||||||
while t.is_alive() and not self.terminate.is_set():
|
while t.is_alive() and not self.terminate.is_set():
|
||||||
t.join(1) # joins with timeout to respond to keyboard interrupt
|
t.join(1) # joins with timeout to respond to keyboard interrupt
|
||||||
@ -147,7 +148,7 @@ class PublicHeaderChecker:
|
|||||||
# - Fail the test if the preprocessor outputs are the same (but with some code)
|
# - Fail the test if the preprocessor outputs are the same (but with some code)
|
||||||
# - If outputs different, pass the test
|
# - If outputs different, pass the test
|
||||||
# 4) If header passed the steps 1) and 3) test that it produced zero assembly code
|
# 4) If header passed the steps 1) and 3) test that it produced zero assembly code
|
||||||
def check_one_header(self, header, num):
|
def check_one_header(self, header: str, num: int) -> None:
|
||||||
res = self.preprocess_one_header(header, num)
|
res = self.preprocess_one_header(header, num)
|
||||||
if res == self.COMPILE_ERR_REF_CONFIG_HDR_FAILED:
|
if res == self.COMPILE_ERR_REF_CONFIG_HDR_FAILED:
|
||||||
raise HeaderFailedSdkconfig()
|
raise HeaderFailedSdkconfig()
|
||||||
@ -173,7 +174,7 @@ class PublicHeaderChecker:
|
|||||||
if temp_header:
|
if temp_header:
|
||||||
os.unlink(temp_header)
|
os.unlink(temp_header)
|
||||||
|
|
||||||
def compile_one_header(self, header):
|
def compile_one_header(self, header: str) -> None:
|
||||||
rc, out, err, cmd = exec_cmd([self.gcc, '-S', '-o-', '-include', header, self.main_c] + self.include_dir_flags)
|
rc, out, err, cmd = exec_cmd([self.gcc, '-S', '-o-', '-include', header, self.main_c] + self.include_dir_flags)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
if not re.sub(self.assembly_nocode, '', out, flags=re.M).isspace():
|
if not re.sub(self.assembly_nocode, '', out, flags=re.M).isspace():
|
||||||
@ -184,7 +185,7 @@ class PublicHeaderChecker:
|
|||||||
self.log('\nCompilation command failed:\n{}\n'.format(cmd), True)
|
self.log('\nCompilation command failed:\n{}\n'.format(cmd), True)
|
||||||
raise HeaderFailedBuildError()
|
raise HeaderFailedBuildError()
|
||||||
|
|
||||||
def preprocess_one_header(self, header, num, ignore_sdkconfig_issue=False):
|
def preprocess_one_header(self, header: str, num: int, ignore_sdkconfig_issue: bool=False) -> int:
|
||||||
all_compilation_flags = ['-w', '-P', '-E', '-DESP_PLATFORM', '-include', header, self.main_c] + self.include_dir_flags
|
all_compilation_flags = ['-w', '-P', '-E', '-DESP_PLATFORM', '-include', header, self.main_c] + self.include_dir_flags
|
||||||
if not ignore_sdkconfig_issue:
|
if not ignore_sdkconfig_issue:
|
||||||
# just strip commnets to check for CONFIG_... macros
|
# just strip commnets to check for CONFIG_... macros
|
||||||
@ -232,8 +233,10 @@ class PublicHeaderChecker:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# Get compilation data from an example to list all public header files
|
# Get compilation data from an example to list all public header files
|
||||||
def list_public_headers(self, ignore_dirs, ignore_files, only_dir=None):
|
def list_public_headers(self, ignore_dirs: List, ignore_files: Union[List, Set], only_dir: str=None) -> None:
|
||||||
idf_path = os.getenv('IDF_PATH')
|
idf_path = os.getenv('IDF_PATH')
|
||||||
|
if idf_path is None:
|
||||||
|
raise RuntimeError("Environment variable 'IDF_PATH' wasn't set.")
|
||||||
project_dir = os.path.join(idf_path, 'examples', 'get-started', 'blink')
|
project_dir = os.path.join(idf_path, 'examples', 'get-started', 'blink')
|
||||||
build_dir = tempfile.mkdtemp()
|
build_dir = tempfile.mkdtemp()
|
||||||
sdkconfig = os.path.join(build_dir, 'sdkconfig')
|
sdkconfig = os.path.join(build_dir, 'sdkconfig')
|
||||||
@ -283,22 +286,22 @@ class PublicHeaderChecker:
|
|||||||
self.include_dir_flags = include_dir_flags
|
self.include_dir_flags = include_dir_flags
|
||||||
ignore_files = set(ignore_files)
|
ignore_files = set(ignore_files)
|
||||||
# processes public include files, removing ignored files
|
# processes public include files, removing ignored files
|
||||||
for f in all_include_files:
|
for file_name in all_include_files:
|
||||||
rel_path_file = os.path.relpath(f, idf_path)
|
rel_path_file = os.path.relpath(file_name, idf_path)
|
||||||
if any([os.path.commonprefix([d, rel_path_file]) == d for d in ignore_dirs]):
|
if any([os.path.commonprefix([d, rel_path_file]) == d for d in ignore_dirs]):
|
||||||
self.log('{} - file ignored (inside ignore dir)'.format(f))
|
self.log('{} - file ignored (inside ignore dir)'.format(file_name))
|
||||||
continue
|
continue
|
||||||
if rel_path_file in ignore_files:
|
if rel_path_file in ignore_files:
|
||||||
self.log('{} - file ignored'.format(f))
|
self.log('{} - file ignored'.format(file_name))
|
||||||
continue
|
continue
|
||||||
files_to_check.append(f)
|
files_to_check.append(file_name)
|
||||||
# removes duplicates and places headers to a work queue
|
# removes duplicates and places headers to a work queue
|
||||||
for f in set(files_to_check):
|
for file_name in set(files_to_check):
|
||||||
self.job_queue.put(f)
|
self.job_queue.put(file_name)
|
||||||
self.job_queue.put(None) # to indicate the last job
|
self.job_queue.put(None) # to indicate the last job
|
||||||
|
|
||||||
|
|
||||||
def check_all_headers():
|
def check_all_headers() -> None:
|
||||||
parser = argparse.ArgumentParser('Public header checker file', formatter_class=argparse.RawDescriptionHelpFormatter, epilog='''\
|
parser = argparse.ArgumentParser('Public header checker file', formatter_class=argparse.RawDescriptionHelpFormatter, epilog='''\
|
||||||
Tips for fixing failures reported by this script
|
Tips for fixing failures reported by this script
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
@ -16,6 +16,7 @@ import urllib.error
|
|||||||
import urllib.request
|
import urllib.request
|
||||||
from collections import defaultdict, namedtuple
|
from collections import defaultdict, namedtuple
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import List
|
||||||
|
|
||||||
EXCLUDE_DOCS_LIST = ['examples/peripherals/secure_element/atecc608_ecdsa/components/esp-cryptoauthlib/cryptoauthlib/**']
|
EXCLUDE_DOCS_LIST = ['examples/peripherals/secure_element/atecc608_ecdsa/components/esp-cryptoauthlib/cryptoauthlib/**']
|
||||||
|
|
||||||
@ -26,28 +27,28 @@ Link = namedtuple('Link', ['file', 'url'])
|
|||||||
|
|
||||||
|
|
||||||
class ReadmeLinkError(Exception):
|
class ReadmeLinkError(Exception):
|
||||||
def __init__(self, file, url):
|
def __init__(self, file: str, url: str) -> None:
|
||||||
self.file = file
|
self.file = file
|
||||||
self.url = url
|
self.url = url
|
||||||
|
|
||||||
|
|
||||||
class RelativeLinkError(ReadmeLinkError):
|
class RelativeLinkError(ReadmeLinkError):
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return 'Relative link error, file - {} not found, linked from {}'.format(self.url, self.file)
|
return 'Relative link error, file - {} not found, linked from {}'.format(self.url, self.file)
|
||||||
|
|
||||||
|
|
||||||
class UrlLinkError(ReadmeLinkError):
|
class UrlLinkError(ReadmeLinkError):
|
||||||
def __init__(self, file, url, error_code):
|
def __init__(self, file: str, url: str, error_code: str):
|
||||||
self.error_code = error_code
|
self.error_code = error_code
|
||||||
super().__init__(file, url)
|
super().__init__(file, url)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
files = [str(f) for f in self.file]
|
files = [str(f) for f in self.file]
|
||||||
return 'URL error, url - {} in files - {} is not accessible, request returned {}'.format(self.url, ', '.join(files), self.error_code)
|
return 'URL error, url - {} in files - {} is not accessible, request returned {}'.format(self.url, ', '.join(files), self.error_code)
|
||||||
|
|
||||||
|
|
||||||
# we do not want a failed test just due to bad network conditions, for non 404 errors we simply print a warning
|
# we do not want a failed test just due to bad network conditions, for non 404 errors we simply print a warning
|
||||||
def check_url(url, files, timeout):
|
def check_url(url: str, files: str, timeout: float) -> None:
|
||||||
try:
|
try:
|
||||||
with urllib.request.urlopen(url, timeout=timeout):
|
with urllib.request.urlopen(url, timeout=timeout):
|
||||||
return
|
return
|
||||||
@ -60,7 +61,7 @@ def check_url(url, files, timeout):
|
|||||||
print('Unable to access {}, err = {}'.format(url, str(e)))
|
print('Unable to access {}, err = {}'.format(url, str(e)))
|
||||||
|
|
||||||
|
|
||||||
def check_web_links(web_links):
|
def check_web_links(web_links: defaultdict) -> List:
|
||||||
|
|
||||||
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
|
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
|
||||||
errors = []
|
errors = []
|
||||||
@ -74,7 +75,7 @@ def check_web_links(web_links):
|
|||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
def check_file_links(file_links):
|
def check_file_links(file_links: List) -> List:
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
for link in file_links:
|
for link in file_links:
|
||||||
@ -87,10 +88,13 @@ def check_file_links(file_links):
|
|||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
def get_md_links(folder):
|
def get_md_links(folder: str) -> List:
|
||||||
MD_LINK_RE = r'\[.+?\]\((.+?)(#.+)?\)'
|
MD_LINK_RE = r'\[.+?\]\((.+?)(#.+)?\)'
|
||||||
|
|
||||||
idf_path = Path(os.getenv('IDF_PATH'))
|
idf_path_str = os.getenv('IDF_PATH')
|
||||||
|
if idf_path_str is None:
|
||||||
|
raise RuntimeError("Environment variable 'IDF_PATH' wasn't set.")
|
||||||
|
idf_path = Path(idf_path_str)
|
||||||
links = []
|
links = []
|
||||||
|
|
||||||
for path in (idf_path / folder).rglob('*.md'):
|
for path in (idf_path / folder).rglob('*.md'):
|
||||||
@ -110,7 +114,7 @@ def get_md_links(folder):
|
|||||||
return links
|
return links
|
||||||
|
|
||||||
|
|
||||||
def check_readme_links(args):
|
def check_readme_links(args: argparse.Namespace) -> int:
|
||||||
|
|
||||||
links = get_md_links('examples')
|
links = get_md_links('examples')
|
||||||
print('Found {} links'.format(len(links)))
|
print('Found {} links'.format(len(links)))
|
||||||
|
@ -12,7 +12,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from typing import List
|
from typing import Any, Dict, List, Optional, Set, Union
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from idf_ci_utils import IDF_PATH
|
from idf_ci_utils import IDF_PATH
|
||||||
@ -20,20 +20,20 @@ from idf_ci_utils import IDF_PATH
|
|||||||
ROOT_YML_FP = os.path.join(IDF_PATH, '.gitlab-ci.yml')
|
ROOT_YML_FP = os.path.join(IDF_PATH, '.gitlab-ci.yml')
|
||||||
|
|
||||||
|
|
||||||
def load_yaml(file_path):
|
def load_yaml(file_path: str) -> Any:
|
||||||
return yaml.load(open(file_path), Loader=yaml.FullLoader)
|
return yaml.load(open(file_path), Loader=yaml.FullLoader)
|
||||||
|
|
||||||
|
|
||||||
class YMLConfig:
|
class YMLConfig:
|
||||||
def __init__(self, root_yml_file_path):
|
def __init__(self, root_yml_file_path: str) -> None:
|
||||||
self._config = None
|
self._config: Optional[Dict] = None
|
||||||
self._all_extends = None
|
self._all_extends: Optional[Set] = None
|
||||||
|
|
||||||
self.root_yml = load_yaml(root_yml_file_path)
|
self.root_yml = load_yaml(root_yml_file_path)
|
||||||
assert self.root_yml
|
assert self.root_yml
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _list(str_or_list):
|
def _list(str_or_list: Union[str, List]) -> List:
|
||||||
if isinstance(str_or_list, str):
|
if isinstance(str_or_list, str):
|
||||||
return [str_or_list]
|
return [str_or_list]
|
||||||
if isinstance(str_or_list, list):
|
if isinstance(str_or_list, list):
|
||||||
@ -43,7 +43,7 @@ class YMLConfig:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def config(self):
|
def config(self) -> Dict:
|
||||||
if self._config:
|
if self._config:
|
||||||
return self._config
|
return self._config
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ class YMLConfig:
|
|||||||
return self._config
|
return self._config
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def all_extends(self):
|
def all_extends(self) -> Set:
|
||||||
if self._all_extends:
|
if self._all_extends:
|
||||||
return self._all_extends
|
return self._all_extends
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class YMLConfig:
|
|||||||
self._all_extends = res
|
self._all_extends = res
|
||||||
return self._all_extends
|
return self._all_extends
|
||||||
|
|
||||||
def exists(self, key):
|
def exists(self, key: str) -> bool:
|
||||||
if key in self.all_extends:
|
if key in self.all_extends:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -76,7 +76,7 @@ class YMLConfig:
|
|||||||
YML_CONFIG = YMLConfig(ROOT_YML_FP)
|
YML_CONFIG = YMLConfig(ROOT_YML_FP)
|
||||||
|
|
||||||
|
|
||||||
def validate_needed_rules(rules_yml):
|
def validate_needed_rules(rules_yml: os.PathLike[str]) -> int:
|
||||||
res = 0
|
res = 0
|
||||||
needed_rules = deepcopy(YML_CONFIG.all_extends)
|
needed_rules = deepcopy(YML_CONFIG.all_extends)
|
||||||
with open(rules_yml) as fr:
|
with open(rules_yml) as fr:
|
||||||
@ -114,7 +114,7 @@ def parse_submodule_paths(
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def validate_submodule_patterns():
|
def validate_submodule_patterns() -> int:
|
||||||
submodule_paths = sorted(['.gitmodules'] + parse_submodule_paths())
|
submodule_paths = sorted(['.gitmodules'] + parse_submodule_paths())
|
||||||
submodule_paths_in_patterns = sorted(
|
submodule_paths_in_patterns = sorted(
|
||||||
YML_CONFIG.config.get('.patterns-submodule', [])
|
YML_CONFIG.config.get('.patterns-submodule', [])
|
||||||
|
@ -7,19 +7,20 @@ import argparse
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Set, Tuple
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from idf_ci_utils import IDF_PATH, get_git_files
|
from idf_ci_utils import IDF_PATH, get_git_files
|
||||||
|
|
||||||
|
|
||||||
def check(pattern_yml, exclude_list):
|
def check(pattern_yml: str, exclude_list: str) -> Tuple[Set, Set]:
|
||||||
rules_dict = yaml.load(open(pattern_yml), Loader=yaml.FullLoader)
|
rules_dict = yaml.load(open(pattern_yml), Loader=yaml.FullLoader)
|
||||||
rules_patterns_set = set()
|
rules_patterns_set = set()
|
||||||
for k, v in rules_dict.items():
|
for k, v in rules_dict.items():
|
||||||
if k.startswith('.pattern') and k != '.patterns-python-files' and isinstance(v, list):
|
if k.startswith('.pattern') and k != '.patterns-python-files' and isinstance(v, list):
|
||||||
rules_patterns_set.update(v)
|
rules_patterns_set.update(v)
|
||||||
|
|
||||||
rules_files_set = set()
|
rules_files_set: Set = set()
|
||||||
idf_path = Path(IDF_PATH)
|
idf_path = Path(IDF_PATH)
|
||||||
for pat in rules_patterns_set:
|
for pat in rules_patterns_set:
|
||||||
rules_files_set.update(idf_path.glob(pat))
|
rules_files_set.update(idf_path.glob(pat))
|
||||||
@ -30,7 +31,7 @@ def check(pattern_yml, exclude_list):
|
|||||||
if pat:
|
if pat:
|
||||||
exclude_patterns_set.add(pat)
|
exclude_patterns_set.add(pat)
|
||||||
|
|
||||||
exclude_files_set = set()
|
exclude_files_set: Set = set()
|
||||||
for pat in exclude_patterns_set:
|
for pat in exclude_patterns_set:
|
||||||
exclude_files_set.update(idf_path.glob(pat))
|
exclude_files_set.update(idf_path.glob(pat))
|
||||||
|
|
||||||
|
@ -10,27 +10,28 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from typing import List
|
||||||
|
|
||||||
IDF_GIT_DESCRIBE_PATTERN = re.compile(r'^v(\d)\.(\d)')
|
IDF_GIT_DESCRIBE_PATTERN = re.compile(r'^v(\d)\.(\d)')
|
||||||
RETRY_COUNT = 3
|
RETRY_COUNT = 3
|
||||||
|
|
||||||
|
|
||||||
def get_customized_project_revision(proj_name):
|
def get_customized_project_revision(proj_name: str) -> str:
|
||||||
"""
|
"""
|
||||||
get customized project revision defined in bot message
|
get customized project revision defined in bot message
|
||||||
"""
|
"""
|
||||||
revision = ''
|
revision = ''
|
||||||
customized_project_revisions = os.getenv('BOT_CUSTOMIZED_REVISION')
|
customized_project_revisions_file = os.getenv('BOT_CUSTOMIZED_REVISION')
|
||||||
if customized_project_revisions:
|
if customized_project_revisions_file:
|
||||||
customized_project_revisions = json.loads(customized_project_revisions)
|
customized_project_revisions = json.loads(customized_project_revisions_file)
|
||||||
try:
|
try:
|
||||||
revision = customized_project_revisions[proj_name.lower()]
|
revision = customized_project_revisions[proj_name.lower()]
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
pass
|
pass
|
||||||
return revision
|
return revision
|
||||||
|
|
||||||
|
|
||||||
def target_branch_candidates(proj_name):
|
def target_branch_candidates(proj_name: str) -> List:
|
||||||
"""
|
"""
|
||||||
:return: a list of target branch candidates, from highest priority to lowest priority.
|
:return: a list of target branch candidates, from highest priority to lowest priority.
|
||||||
"""
|
"""
|
||||||
|
@ -11,6 +11,7 @@ import re
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
from typing import Any, List
|
||||||
|
|
||||||
import gitlab_api
|
import gitlab_api
|
||||||
|
|
||||||
@ -28,27 +29,26 @@ class SubModule(object):
|
|||||||
|
|
||||||
GIT_LS_TREE_OUTPUT_PATTERN = re.compile(r'\d+\s+commit\s+([0-9a-f]+)\s+')
|
GIT_LS_TREE_OUTPUT_PATTERN = re.compile(r'\d+\s+commit\s+([0-9a-f]+)\s+')
|
||||||
|
|
||||||
def __init__(self, gitlab_inst, path, url):
|
def __init__(self, gitlab_inst: gitlab_api.Gitlab, path: str, url: str) -> None:
|
||||||
self.path = path
|
self.path = path
|
||||||
self.url = url
|
self.url = url
|
||||||
self.gitlab_inst = gitlab_inst
|
self.gitlab_inst = gitlab_inst
|
||||||
self.project_id = self._get_project_id(url)
|
self.project_id = self._get_project_id(url)
|
||||||
self.commit_id = self._get_commit_id(path)
|
self.commit_id = self._get_commit_id(path)
|
||||||
|
|
||||||
def _get_commit_id(self, path):
|
def _get_commit_id(self, path: str) -> str:
|
||||||
output = subprocess.check_output(['git', 'ls-tree', 'HEAD', path])
|
output = subprocess.check_output(['git', 'ls-tree', 'HEAD', path]).decode()
|
||||||
output = output.decode()
|
|
||||||
# example output: 160000 commit d88a262fbdf35e5abb372280eb08008749c3faa0 components/esp_wifi/lib
|
# example output: 160000 commit d88a262fbdf35e5abb372280eb08008749c3faa0 components/esp_wifi/lib
|
||||||
match = self.GIT_LS_TREE_OUTPUT_PATTERN.search(output)
|
match = self.GIT_LS_TREE_OUTPUT_PATTERN.search(output)
|
||||||
return match.group(1)
|
return match.group(1) if match is not None else ''
|
||||||
|
|
||||||
def _get_project_id(self, url):
|
def _get_project_id(self, url: str) -> Any:
|
||||||
base_name = os.path.basename(url)
|
base_name = os.path.basename(url)
|
||||||
project_id = self.gitlab_inst.get_project_id(os.path.splitext(base_name)[0], # remove .git
|
project_id = self.gitlab_inst.get_project_id(os.path.splitext(base_name)[0], # remove .git
|
||||||
namespace='espressif')
|
namespace='espressif')
|
||||||
return project_id
|
return project_id
|
||||||
|
|
||||||
def download_archive(self):
|
def download_archive(self) -> None:
|
||||||
print('Update submodule: {}: {}'.format(self.path, self.commit_id))
|
print('Update submodule: {}: {}'.format(self.path, self.commit_id))
|
||||||
path_name = self.gitlab_inst.download_archive(self.commit_id, SUBMODULE_ARCHIVE_TEMP_FOLDER,
|
path_name = self.gitlab_inst.download_archive(self.commit_id, SUBMODULE_ARCHIVE_TEMP_FOLDER,
|
||||||
self.project_id, SUBMODULE_ARCHIVE_CACHE_DIR)
|
self.project_id, SUBMODULE_ARCHIVE_CACHE_DIR)
|
||||||
@ -58,33 +58,34 @@ class SubModule(object):
|
|||||||
shutil.move(renamed_path, os.path.dirname(self.path))
|
shutil.move(renamed_path, os.path.dirname(self.path))
|
||||||
|
|
||||||
|
|
||||||
def update_submodule(git_module_file, submodules_to_update):
|
def update_submodule(git_module_file: str, submodules_to_update: List) -> None:
|
||||||
gitlab_inst = gitlab_api.Gitlab()
|
gitlab_inst = gitlab_api.Gitlab()
|
||||||
submodules = []
|
submodules = []
|
||||||
with open(git_module_file, 'r') as f:
|
with open(git_module_file, 'r') as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
match = SUBMODULE_PATTERN.search(data)
|
match = SUBMODULE_PATTERN.search(data)
|
||||||
while True:
|
if match is not None:
|
||||||
next_match = SUBMODULE_PATTERN.search(data, pos=match.end())
|
while True:
|
||||||
if next_match:
|
next_match = SUBMODULE_PATTERN.search(data, pos=match.end())
|
||||||
end_pos = next_match.start()
|
if next_match:
|
||||||
else:
|
end_pos = next_match.start()
|
||||||
end_pos = len(data)
|
else:
|
||||||
path_match = PATH_PATTERN.search(data, pos=match.end(), endpos=end_pos)
|
end_pos = len(data)
|
||||||
url_match = URL_PATTERN.search(data, pos=match.end(), endpos=end_pos)
|
path_match = PATH_PATTERN.search(data, pos=match.end(), endpos=end_pos)
|
||||||
path = path_match.group(1)
|
url_match = URL_PATTERN.search(data, pos=match.end(), endpos=end_pos)
|
||||||
url = url_match.group(1)
|
path = path_match.group(1) if path_match is not None else ''
|
||||||
|
url = url_match.group(1) if url_match is not None else ''
|
||||||
|
|
||||||
filter_result = True
|
filter_result = True
|
||||||
if submodules_to_update:
|
if submodules_to_update:
|
||||||
if path not in submodules_to_update:
|
if path not in submodules_to_update:
|
||||||
filter_result = False
|
filter_result = False
|
||||||
if filter_result:
|
if filter_result:
|
||||||
submodules.append(SubModule(gitlab_inst, path, url))
|
submodules.append(SubModule(gitlab_inst, path, url))
|
||||||
|
|
||||||
match = next_match
|
match = next_match
|
||||||
if not match:
|
if not match:
|
||||||
break
|
break
|
||||||
|
|
||||||
shutil.rmtree(SUBMODULE_ARCHIVE_TEMP_FOLDER, ignore_errors=True)
|
shutil.rmtree(SUBMODULE_ARCHIVE_TEMP_FOLDER, ignore_errors=True)
|
||||||
|
|
||||||
|
@ -14,11 +14,12 @@ import stat
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tarfile
|
import tarfile
|
||||||
|
from typing import Any, List, Tuple
|
||||||
|
|
||||||
import packaging.version
|
import packaging.version
|
||||||
|
|
||||||
|
|
||||||
def env(variable, default=None):
|
def env(variable: str, default: str=None) -> str:
|
||||||
""" Shortcut to return the expanded version of an environment variable """
|
""" Shortcut to return the expanded version of an environment variable """
|
||||||
return os.path.expandvars(os.environ.get(variable, default) if default else os.environ[variable])
|
return os.path.expandvars(os.environ.get(variable, default) if default else os.environ[variable])
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ sys.path.append(os.path.join(env('IDF_PATH'), 'docs'))
|
|||||||
from sanitize_version import sanitize_version # noqa
|
from sanitize_version import sanitize_version # noqa
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
# if you get KeyErrors on the following lines, it's probably because you're not running in Gitlab CI
|
# if you get KeyErrors on the following lines, it's probably because you're not running in Gitlab CI
|
||||||
git_ver = env('GIT_VER') # output of git describe --always
|
git_ver = env('GIT_VER') # output of git describe --always
|
||||||
ci_ver = env('CI_COMMIT_REF_NAME', git_ver) # branch or tag we're building for (used for 'release' & URL)
|
ci_ver = env('CI_COMMIT_REF_NAME', git_ver) # branch or tag we're building for (used for 'release' & URL)
|
||||||
@ -87,8 +88,8 @@ def main():
|
|||||||
deploy('stable', tarball_path, docs_path, docs_server)
|
deploy('stable', tarball_path, docs_path, docs_server)
|
||||||
|
|
||||||
|
|
||||||
def deploy(version, tarball_path, docs_path, docs_server):
|
def deploy(version: str, tarball_path: str, docs_path: str, docs_server: str) -> None:
|
||||||
def run_ssh(commands):
|
def run_ssh(commands: List) -> None:
|
||||||
""" Log into docs_server and run a sequence of commands using ssh """
|
""" Log into docs_server and run a sequence of commands using ssh """
|
||||||
print('Running ssh: {}'.format(commands))
|
print('Running ssh: {}'.format(commands))
|
||||||
subprocess.run(['ssh', '-o', 'BatchMode=yes', docs_server, '-x', ' && '.join(commands)], check=True)
|
subprocess.run(['ssh', '-o', 'BatchMode=yes', docs_server, '-x', ' && '.join(commands)], check=True)
|
||||||
@ -110,7 +111,7 @@ def deploy(version, tarball_path, docs_path, docs_server):
|
|||||||
# another thing made much more complex by the directory structure putting language before version...
|
# another thing made much more complex by the directory structure putting language before version...
|
||||||
|
|
||||||
|
|
||||||
def build_doc_tarball(version, git_ver, build_dir):
|
def build_doc_tarball(version: str, git_ver: str, build_dir: str) -> Tuple[str, List]:
|
||||||
""" Make a tar.gz archive of the docs, in the directory structure used to deploy as
|
""" Make a tar.gz archive of the docs, in the directory structure used to deploy as
|
||||||
the given version """
|
the given version """
|
||||||
version_paths = []
|
version_paths = []
|
||||||
@ -126,7 +127,8 @@ def build_doc_tarball(version, git_ver, build_dir):
|
|||||||
# add symlink for stable and latest and adds them to PDF blob
|
# add symlink for stable and latest and adds them to PDF blob
|
||||||
symlinks = create_and_add_symlinks(version, git_ver, pdfs)
|
symlinks = create_and_add_symlinks(version, git_ver, pdfs)
|
||||||
|
|
||||||
def not_sources_dir(ti):
|
def not_sources_dir(ti: Any) -> Any:
|
||||||
|
print(type(ti))
|
||||||
""" Filter the _sources directories out of the tarballs """
|
""" Filter the _sources directories out of the tarballs """
|
||||||
if ti.name.endswith('/_sources'):
|
if ti.name.endswith('/_sources'):
|
||||||
return None
|
return None
|
||||||
@ -171,7 +173,7 @@ def build_doc_tarball(version, git_ver, build_dir):
|
|||||||
return (os.path.abspath(tarball_path), version_paths)
|
return (os.path.abspath(tarball_path), version_paths)
|
||||||
|
|
||||||
|
|
||||||
def create_and_add_symlinks(version, git_ver, pdfs):
|
def create_and_add_symlinks(version: str, git_ver: str, pdfs: List) -> List:
|
||||||
""" Create symbolic links for PDFs for 'latest' and 'stable' releases """
|
""" Create symbolic links for PDFs for 'latest' and 'stable' releases """
|
||||||
|
|
||||||
symlinks = []
|
symlinks = []
|
||||||
@ -187,7 +189,7 @@ def create_and_add_symlinks(version, git_ver, pdfs):
|
|||||||
return symlinks
|
return symlinks
|
||||||
|
|
||||||
|
|
||||||
def is_stable_version(version):
|
def is_stable_version(version: str) -> bool:
|
||||||
""" Heuristic for whether this is the latest stable release """
|
""" Heuristic for whether this is the latest stable release """
|
||||||
if not version.startswith('v'):
|
if not version.startswith('v'):
|
||||||
return False # branch name
|
return False # branch name
|
||||||
@ -197,11 +199,11 @@ def is_stable_version(version):
|
|||||||
git_out = subprocess.check_output(['git', 'tag', '-l']).decode('utf-8')
|
git_out = subprocess.check_output(['git', 'tag', '-l']).decode('utf-8')
|
||||||
|
|
||||||
versions = [v.strip() for v in git_out.split('\n')]
|
versions = [v.strip() for v in git_out.split('\n')]
|
||||||
versions = [v for v in versions if re.match(r'^v[\d\.]+$', v)] # include vX.Y.Z only
|
versions = [v for v in versions if re.match(r'^v[\d\.]+$', v.strip())] # include vX.Y.Z only
|
||||||
|
|
||||||
versions = [packaging.version.parse(v) for v in versions]
|
versions_pack = [packaging.version.parse(v) for v in versions]
|
||||||
|
|
||||||
max_version = max(versions)
|
max_version = max(versions_pack)
|
||||||
|
|
||||||
if max_version.public != version[1:]:
|
if max_version.public != version[1:]:
|
||||||
print('Stable version is v{}. This version is {}.'.format(max_version.public, version))
|
print('Stable version is v{}. This version is {}.'.format(max_version.public, version))
|
||||||
|
@ -9,7 +9,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
# Sanitize environment variables
|
# Sanitize environment variables
|
||||||
vars_to_remove = []
|
vars_to_remove = []
|
||||||
for var_name in os.environ.keys():
|
for var_name in os.environ.keys():
|
||||||
|
@ -141,21 +141,7 @@ examples/wifi/iperf/iperf_test.py
|
|||||||
tools/ble/lib_ble_client.py
|
tools/ble/lib_ble_client.py
|
||||||
tools/ble/lib_gap.py
|
tools/ble/lib_gap.py
|
||||||
tools/ble/lib_gatt.py
|
tools/ble/lib_gatt.py
|
||||||
tools/ci/check_artifacts_expire_time.py
|
|
||||||
tools/ci/check_callgraph.py
|
|
||||||
tools/ci/check_codeowners.py
|
|
||||||
tools/ci/check_deprecated_kconfigs.py
|
|
||||||
tools/ci/check_executables.py
|
|
||||||
tools/ci/check_kconfigs.py
|
tools/ci/check_kconfigs.py
|
||||||
tools/ci/check_public_headers.py
|
|
||||||
tools/ci/check_readme_links.py
|
|
||||||
tools/ci/check_rules_yml.py
|
|
||||||
tools/ci/check_tools_files_patterns.py
|
|
||||||
tools/ci/checkout_project_ref.py
|
|
||||||
tools/ci/ci_fetch_submodule.py
|
|
||||||
tools/ci/deploy_docs.py
|
|
||||||
tools/ci/envsubst.py
|
|
||||||
tools/ci/normalize_clangtidy_path.py
|
|
||||||
tools/ci/python_packages/idf_http_server_test/adder.py
|
tools/ci/python_packages/idf_http_server_test/adder.py
|
||||||
tools/ci/python_packages/idf_http_server_test/client.py
|
tools/ci/python_packages/idf_http_server_test/client.py
|
||||||
tools/ci/python_packages/idf_http_server_test/test.py
|
tools/ci/python_packages/idf_http_server_test/test.py
|
||||||
|
Loading…
Reference in New Issue
Block a user