1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-01 19:02:18 +01:00

Updates for 1.13 (#546)

* Update CI matcher

* Check Executable bit

* Quicklint

* Updates

* Allow pm1.0 and pm10.0 for PMS5003ST

Fixes https://github.com/esphome/feature-requests/issues/225

* PowerSupplyRequester

* Lint

* Include debug data in generated main.cpp

* Updates

* Auto-select bit_depth

* Updates
This commit is contained in:
Otto Winter
2019-05-12 23:04:36 +02:00
committed by GitHub
parent 797aadaf26
commit f811b1157c
41 changed files with 438 additions and 418 deletions

View File

@@ -1,93 +1,9 @@
#!/usr/bin/env python
import codecs
import json
import os
import re
import sys
import os.path
root_path = os.path.abspath(os.path.normpath(os.path.join(__file__, '..', '..')))
basepath = os.path.join(root_path, 'esphome')
temp_header_file = os.path.join(root_path, '.temp-clang-tidy.cpp')
def walk_files(path):
for root, _, files in os.walk(path):
for name in files:
yield os.path.join(root, name)
def shlex_quote(s):
if not s:
return u"''"
if re.search(r'[^\w@%+=:,./-]', s) is None:
return s
return u"'" + s.replace(u"'", u"'\"'\"'") + u"'"
def build_all_include():
# Build a cpp file that includes all header files in this repo.
# Otherwise header-only integrations would not be tested by clang-tidy
headers = []
for path in walk_files(basepath):
filetypes = ('.h',)
ext = os.path.splitext(path)[1]
if ext in filetypes:
path = os.path.relpath(path, root_path)
include_p = path.replace(os.path.sep, '/')
headers.append('#include "{}"'.format(include_p))
headers.sort()
headers.append('')
content = '\n'.join(headers)
with codecs.open(temp_header_file, 'w', encoding='utf-8') as f:
f.write(content)
def build_compile_commands():
gcc_flags_json = os.path.join(root_path, '.gcc-flags.json')
if not os.path.isfile(gcc_flags_json):
print("Could not find {} file which is required for clang-tidy.")
print('Please run "pio init --ide atom" in the root esphome folder to generate that file.')
sys.exit(1)
with codecs.open(gcc_flags_json, 'r', encoding='utf-8') as f:
gcc_flags = json.load(f)
exec_path = gcc_flags['execPath']
include_paths = gcc_flags['gccIncludePaths'].split(',')
includes = ['-I{}'.format(p) for p in include_paths]
cpp_flags = gcc_flags['gccDefaultCppFlags'].split(' ')
defines = [flag for flag in cpp_flags if flag.startswith('-D')]
command = [exec_path]
command.extend(includes)
command.extend(defines)
command.append('-std=gnu++11')
command.append('-Wall')
command.append('-Wno-delete-non-virtual-dtor')
command.append('-Wno-unused-variable')
command.append('-Wunreachable-code')
source_files = []
for path in walk_files(basepath):
filetypes = ('.cpp',)
ext = os.path.splitext(path)[1]
if ext in filetypes:
source_files.append(os.path.abspath(path))
source_files.append(temp_header_file)
source_files.sort()
compile_commands = [{
'directory': root_path,
'command': ' '.join(shlex_quote(x) for x in (command + ['-o', p + '.o', '-c', p])),
'file': p
} for p in source_files]
compile_commands_json = os.path.join(root_path, 'compile_commands.json')
if os.path.isfile(compile_commands_json):
with codecs.open(compile_commands_json, 'r', encoding='utf-8') as f:
try:
if json.load(f) == compile_commands:
return
except:
pass
with codecs.open(compile_commands_json, 'w', encoding='utf-8') as f:
json.dump(compile_commands, f, indent=2)
sys.path.append(os.path.dirname(__file__))
from helpers import build_all_include, build_compile_commands
def main():

View File

@@ -4,7 +4,6 @@ from __future__ import print_function
import codecs
import collections
import fnmatch
import functools
import os.path
import subprocess
import sys
@@ -155,6 +154,28 @@ def lint_pragma_once(content):
return None
@lint_content_find_check('ESP_LOG', include=['*.h', '*.tcc'], exclude=[
'esphome/components/binary_sensor/binary_sensor.h',
'esphome/components/cover/cover.h',
'esphome/components/display/display_buffer.h',
'esphome/components/i2c/i2c.h',
'esphome/components/mqtt/mqtt_component.h',
'esphome/components/output/binary_output.h',
'esphome/components/output/float_output.h',
'esphome/components/sensor/sensor.h',
'esphome/components/stepper/stepper.h',
'esphome/components/switch/switch.h',
'esphome/components/text_sensor/text_sensor.h',
'esphome/core/component.h',
'esphome/core/esphal.h',
'esphome/core/log.h',
'tests/custom.h',
])
def lint_log_in_header():
return ('Found reference to ESP_LOG in header file. Using ESP_LOG* in header files '
'is currently not possible - please move the definition to a source file (.cpp)')
errors = collections.defaultdict(list)

View File

@@ -2,16 +2,19 @@
from __future__ import print_function
import argparse
import multiprocessing
import os
import re
import subprocess
import sys
import argparse
import click
import threading
import click
sys.path.append(os.path.dirname(__file__))
from helpers import basepath, get_output, walk_files, filter_changed
is_py2 = sys.version[0] == '2'
if is_py2:
@@ -50,44 +53,6 @@ def progress_bar_show(value):
return value
def walk_files(path):
for root, _, files in os.walk(path):
for name in files:
yield os.path.join(root, name)
def get_output(*args):
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = proc.communicate()
return output.decode('utf-8')
def splitlines_no_ends(string):
return [s.strip() for s in string.splitlines()]
def filter_changed(files):
for remote in ('upstream', 'origin'):
command = ['git', 'merge-base', '{}/dev'.format(remote), 'HEAD']
try:
merge_base = splitlines_no_ends(get_output(*command))[0]
break
except:
pass
else:
return files
command = ['git', 'diff', merge_base, '--name-only']
changed = splitlines_no_ends(get_output(*command))
changed = {os.path.relpath(f, os.getcwd()) for f in changed}
print("Changed Files:")
files = [p for p in files if p in changed]
for p in files:
print(" {}".format(p))
if not files:
print(" No changed files")
return files
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-j', '--jobs', type=int,

View File

@@ -2,8 +2,6 @@
from __future__ import print_function
import codecs
import json
import multiprocessing
import os
import re
@@ -18,6 +16,10 @@ import argparse
import click
import threading
sys.path.append(os.path.dirname(__file__))
from helpers import basepath, shlex_quote, get_output, build_compile_commands, \
build_all_include, temp_header_file, walk_files, filter_changed
is_py2 = sys.version[0] == '2'
if is_py2:
@@ -25,11 +27,6 @@ if is_py2:
else:
import queue as queue
root_path = os.path.abspath(os.path.normpath(os.path.join(__file__, '..', '..')))
basepath = os.path.join(root_path, 'esphome')
rel_basepath = os.path.relpath(basepath, os.getcwd())
temp_header_file = os.path.join(root_path, '.temp-clang-tidy.cpp')
def run_tidy(args, tmpdir, queue, lock, failed_files):
while True:
@@ -67,119 +64,6 @@ def run_tidy(args, tmpdir, queue, lock, failed_files):
def progress_bar_show(value):
if value is None:
return ''
return value
def walk_files(path):
for root, _, files in os.walk(path):
for name in files:
yield os.path.join(root, name)
def get_output(*args):
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = proc.communicate()
return output.decode('utf-8')
def splitlines_no_ends(string):
return [s.strip() for s in string.splitlines()]
def filter_changed(files):
for remote in ('upstream', 'origin'):
command = ['git', 'merge-base', '{}/dev'.format(remote), 'HEAD']
try:
merge_base = splitlines_no_ends(get_output(*command))[0]
break
except:
pass
else:
return files
command = ['git', 'diff', merge_base, '--name-only']
changed = splitlines_no_ends(get_output(*command))
changed = {os.path.relpath(f, os.getcwd()) for f in changed}
print("Changed Files:")
files = [p for p in files if p in changed]
for p in files:
print(" {}".format(p))
if not files:
print(" No changed files")
return files
def shlex_quote(s):
if not s:
return u"''"
if re.search(r'[^\w@%+=:,./-]', s) is None:
return s
return u"'" + s.replace(u"'", u"'\"'\"'") + u"'"
def build_compile_commands():
gcc_flags_json = os.path.join(root_path, '.gcc-flags.json')
if not os.path.isfile(gcc_flags_json):
print("Could not find {} file which is required for clang-tidy.")
print('Please run "pio init --ide atom" in the root esphome folder to generate that file.')
sys.exit(1)
with codecs.open(gcc_flags_json, 'r', encoding='utf-8') as f:
gcc_flags = json.load(f)
exec_path = gcc_flags['execPath']
include_paths = gcc_flags['gccIncludePaths'].split(',')
includes = ['-I{}'.format(p) for p in include_paths]
cpp_flags = gcc_flags['gccDefaultCppFlags'].split(' ')
defines = [flag for flag in cpp_flags if flag.startswith('-D')]
command = [exec_path]
command.extend(includes)
command.extend(defines)
command.append('-std=gnu++11')
command.append('-Wall')
command.append('-Wno-delete-non-virtual-dtor')
command.append('-Wno-unused-variable')
command.append('-Wunreachable-code')
source_files = []
for path in walk_files(basepath):
filetypes = ('.cpp',)
ext = os.path.splitext(path)[1]
if ext in filetypes:
source_files.append(os.path.abspath(path))
source_files.append(temp_header_file)
source_files.sort()
compile_commands = [{
'directory': root_path,
'command': ' '.join(shlex_quote(x) for x in (command + ['-o', p + '.o', '-c', p])),
'file': p
} for p in source_files]
compile_commands_json = os.path.join(root_path, 'compile_commands.json')
if os.path.isfile(compile_commands_json):
with codecs.open(compile_commands_json, 'r', encoding='utf-8') as f:
try:
if json.load(f) == compile_commands:
return
except:
pass
with codecs.open(compile_commands_json, 'w', encoding='utf-8') as f:
json.dump(compile_commands, f, indent=2)
def build_all_include():
# Build a cpp file that includes all header files in this repo.
# Otherwise header-only integrations would not be tested by clang-tidy
headers = []
for path in walk_files(basepath):
filetypes = ('.h',)
ext = os.path.splitext(path)[1]
if ext in filetypes:
path = os.path.relpath(path, root_path)
include_p = path.replace(os.path.sep, '/')
headers.append('#include "{}"'.format(include_p))
headers.sort()
headers.append('')
content = '\n'.join(headers)
with codecs.open(temp_header_file, 'w', encoding='utf-8') as f:
f.write(content)
def main():
@@ -212,6 +96,7 @@ def main():
""")
return 1
build_all_include()
build_compile_commands()
files = []
@@ -231,7 +116,6 @@ def main():
files.sort()
if args.all_headers:
build_all_include()
files.insert(0, temp_header_file)
tmpdir = None

128
script/helpers.py Normal file
View File

@@ -0,0 +1,128 @@
import codecs
import json
import os.path
import re
import subprocess
import sys
root_path = os.path.abspath(os.path.normpath(os.path.join(__file__, '..', '..')))
basepath = os.path.join(root_path, 'esphome')
temp_header_file = os.path.join(root_path, '.temp-clang-tidy.cpp')
def shlex_quote(s):
if not s:
return u"''"
if re.search(r'[^\w@%+=:,./-]', s) is None:
return s
return u"'" + s.replace(u"'", u"'\"'\"'") + u"'"
def build_all_include():
# Build a cpp file that includes all header files in this repo.
# Otherwise header-only integrations would not be tested by clang-tidy
headers = []
for path in walk_files(basepath):
filetypes = ('.h',)
ext = os.path.splitext(path)[1]
if ext in filetypes:
path = os.path.relpath(path, root_path)
include_p = path.replace(os.path.sep, '/')
headers.append('#include "{}"'.format(include_p))
headers.sort()
headers.append('')
content = '\n'.join(headers)
with codecs.open(temp_header_file, 'w', encoding='utf-8') as f:
f.write(content)
def build_compile_commands():
gcc_flags_json = os.path.join(root_path, '.gcc-flags.json')
if not os.path.isfile(gcc_flags_json):
print("Could not find {} file which is required for clang-tidy.")
print('Please run "pio init --ide atom" in the root esphome folder to generate that file.')
sys.exit(1)
with codecs.open(gcc_flags_json, 'r', encoding='utf-8') as f:
gcc_flags = json.load(f)
exec_path = gcc_flags['execPath']
include_paths = gcc_flags['gccIncludePaths'].split(',')
includes = ['-I{}'.format(p) for p in include_paths]
cpp_flags = gcc_flags['gccDefaultCppFlags'].split(' ')
defines = [flag for flag in cpp_flags if flag.startswith('-D')]
command = [exec_path]
command.extend(includes)
command.extend(defines)
command.append('-std=gnu++11')
command.append('-Wall')
command.append('-Wno-delete-non-virtual-dtor')
command.append('-Wno-unused-variable')
command.append('-Wunreachable-code')
source_files = []
for path in walk_files(basepath):
filetypes = ('.cpp',)
ext = os.path.splitext(path)[1]
if ext in filetypes:
source_files.append(os.path.abspath(path))
source_files.append(temp_header_file)
source_files.sort()
compile_commands = [{
'directory': root_path,
'command': ' '.join(shlex_quote(x) for x in (command + ['-o', p + '.o', '-c', p])),
'file': p
} for p in source_files]
compile_commands_json = os.path.join(root_path, 'compile_commands.json')
if os.path.isfile(compile_commands_json):
with codecs.open(compile_commands_json, 'r', encoding='utf-8') as f:
try:
if json.load(f) == compile_commands:
return
except:
pass
with codecs.open(compile_commands_json, 'w', encoding='utf-8') as f:
json.dump(compile_commands, f, indent=2)
def walk_files(path):
for root, _, files in os.walk(path):
for name in files:
yield os.path.join(root, name)
def get_output(*args):
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = proc.communicate()
return output.decode('utf-8')
def splitlines_no_ends(string):
return [s.strip() for s in string.splitlines()]
def changed_files():
for remote in ('upstream', 'origin'):
command = ['git', 'merge-base', '{}/dev'.format(remote), 'HEAD']
try:
merge_base = splitlines_no_ends(get_output(*command))[0]
break
except:
pass
else:
raise ValueError("Git not configured")
command = ['git', 'diff', merge_base, '--name-only']
changed = splitlines_no_ends(get_output(*command))
changed = [os.path.relpath(f, os.getcwd()) for f in changed]
changed.sort()
return changed
def filter_changed(files):
changed = changed_files()
files = [f for f in files if f in changed]
print("Changed files:")
if not files:
print(" No changed files!")
for c in files:
print(" {}".format(c))
return files

View File

@@ -12,5 +12,5 @@ fi
set -x
script/clang-tidy.py -c --fix --all-headers
script/clang-format.py -c -i
script/clang-tidy -c --fix --all-headers
script/clang-format -c -i

View File

@@ -1,10 +1,74 @@
#!/usr/bin/env bash
#!/usr/bin/env python
set -e
from __future__ import print_function
cd "$(dirname "$0")/.."
set -x
import argparse
import collections
import os
import re
import sys
script/ci-custom.py
flake8 esphome
pylint esphome
sys.path.append(os.path.dirname(__file__))
from helpers import basepath, get_output, walk_files, filter_changed
def main():
parser = argparse.ArgumentParser()
parser.add_argument('files', nargs='*', default=[],
help='files to be processed (regex on path)')
parser.add_argument('-c', '--changed', action='store_true',
help='Only run on changed files')
args = parser.parse_args()
files = []
for path in walk_files(basepath):
filetypes = ('.py',)
ext = os.path.splitext(path)[1]
if ext in filetypes:
path = os.path.relpath(path, os.getcwd())
files.append(path)
# Match against re
file_name_re = re.compile('|'.join(args.files))
files = [p for p in files if file_name_re.search(p)]
if args.changed:
files = filter_changed(files)
files.sort()
errors = collections.defaultdict(list)
cmd = ['flake8'] + files
print("Running flake8...")
log = get_output(*cmd)
for line in log.splitlines():
line = line.split(':')
if len(line) < 4:
continue
file_ = line[0]
linno = line[1]
msg = (u':'.join(line[3:])).strip()
errors[file_].append(u'{}:{} - {}'.format(file_, linno, msg))
cmd = ['pylint', '-f', 'parseable', '--persistent=n'] + files
print("Running pylint...")
log = get_output(*cmd)
for line in log.splitlines():
line = line.split(':')
if len(line) < 3:
continue
file_ = line[0]
linno = line[1]
msg = (u':'.join(line[3:])).strip()
errors[file_].append(u'{}:{} - {}'.format(file_, linno, msg))
for f, errs in sorted(errors.items()):
print("\033[0;32m************* File \033[1;32m{}\033[0m".format(f))
for err in errs:
print(err)
print()
sys.exit(len(errors))
if __name__ == '__main__':
main()

11
script/quicklint Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")/.."
set -x
script/ci-custom.py
script/lint-python -c
script/lint-cpp