diff --git a/.gitignore b/.gitignore index a8e10db21..92ff9346a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ examples/**/build tools/unit-test-app/sdkconfig tools/unit-test-app/sdkconfig.old tools/unit-test-app/build + +# Python +venv diff --git a/README.md b/README.md index fd3345ec0..b5ed937a3 100644 --- a/README.md +++ b/README.md @@ -170,3 +170,50 @@ git pull ``` The ``git pull`` command is fetching and merging changes from ESP8266_RTOS_SDK repository on GitHub. + +# Developers + +*This section is for developers of ESP8266_RTOS_SDK itself* + +## Code style + +We use [astyle](http://astyle.sourceforge.net/) to format the code. +The formatting settings can be seen in +[tools/format.sh](tools/format.sh). + +## The code-style tool + +`tools/code-style` is a tool to expand tabs and run clang-format on the +entire repository. + +Usage: `tools/code-style [-e] [-c]` + +* `-t` shows all the files that will be tagged. +* `-e` runs untabbing (replace tab characters with 4 spaces) +* `-a` runs astyle. +* `-n` enabled dry-run mode. In this mode no files will be changed, + but it will let you know which files that would have been changed. + +It uses `tools/astyle` to find files in the repository. The +tool reads `tools/code-style.ini` (see the current version +[here](tools/code-style.ini)) and tags each file it finds with attributes +explaining what should be done with the file. + +The tools are written in bash and Python. + +## Installing dependencies for Python + +`tag-files` requires the following packages: + +* pathspec +* configparser (build-in in python3) + +If these are not available through your OSes package manager you can +use virtualenv to install them locally: + + virtualenv venv + venv/bin/pip install -r tools/requirements.txt + +After that you can add `venv/bin` to path and run `tools/tag-files` like this: + + PATH=$(pwd)/venv/bin:$PATH diff --git a/tools/code-style b/tools/code-style new file mode 100755 index 000000000..93fbb05a2 --- /dev/null +++ b/tools/code-style @@ -0,0 +1,92 @@ +#!/bin/bash + +set -e -o pipefail +cd $(dirname $0)/.. + +function fix() { + local f=$1; shift + orig=$(md5sum "$f" | cut -f 1 -d ' ') + "$@" < "$f" > "$f".tmp + new=$(md5sum "$f.tmp" | cut -f 1 -d ' ') + + if [[ $orig != $new ]] + then + echo Fixed "$f" + + if [[ $dry_run -ne 0 ]] + then + mv "$f.tmp" "$f" + fi + fi + + rm -f "$f.tmp" +} + +function usage() { + echo "$0: usage: [OPTION]" >/dev/stderr + echo " -n: dry run" >/dev/stderr + echo " -t: show all files and tags" >/dev/stderr + echo " -e: run tab expansion" >/dev/stderr + echo " -a: run astyle" >/dev/stderr + exit 1 +} + +dry_run=0 +run_tag=0 +run_expand_tabs=0 +run_astyle=0 + +while getopts "ntaeh?" opt; do + case $opt in + n) + dry_run=1 + ;; + t) + run_tag=1 + ;; + e) + run_expand_tabs=1 + ;; + a) + run_astyle=1 + ;; + h|?) + usage + ;; + esac +done + +tf=(tools/tag-files --config tools/code-style.ini) + +if [[ $run_tag -ne 0 ]] +then + "${tf[@]}" +fi + +if [[ $run_expand_tabs -ne 0 ]] +then + echo "Replacing tabs with spaces..." + "${tf[@]}" |\ + grep expand-tabs=yes |\ + while IFS=$'\t' read f params + do + fix "$f" sed 's,\t, ,g' + done + + echo "To undo run" + echo "tools/tag-files | grep -v ignore=True | grep no_expand_tab=False | cut -f 1 -d $'\t' | xargs git checkout" +fi + +if [[ $run_astyle -ne 0 ]] +then + echo "Running astyle..." + "${tf[@]}" |\ + grep astyle=yes |\ + while IFS=$'\t' read f params + do + fix "$f" tools/format.sh -n + done + + echo "To undo run" + echo "tools/tag-files | grep -v ignore=True | grep clang_format=True | cut -f 1 -d $'\t' | xargs git checkout" +fi diff --git a/tools/code-style.ini b/tools/code-style.ini new file mode 100644 index 000000000..73048a304 --- /dev/null +++ b/tools/code-style.ini @@ -0,0 +1,45 @@ +# Configuration for tag-files. The 'tree' set controls which files that +# are tagged, the other sets control are tags applied to files found in the +# 'tree' set. + +[tree:include] +* + +# These will never be printed +[tree:exclude] +.git +venv +tools/cmake/third_party +tools/kconfig +tools/kconfig_new +*.bin +*.o +*.a +*.key +*.rar +sdkconfig +sdkconfig.old + +# Third party code +components/cjson +components/esp8266/include/xtensa +components/esptool_py +components/freertos/freertos +components/freertos/include +components/lwip +components/newlib/newlib/include +components/spiffs +components/mqtt/paho +components/ssl/axtls +components/ssl/mbedtls +components/ssl/wolfssl + +[expand-tabs:exclude] +*.mk +Makefile* +makefile* + +[astyle:include] +*.h +*.c +*.cpp diff --git a/tools/format.sh b/tools/format.sh new file mode 100755 index 000000000..6c7585917 --- /dev/null +++ b/tools/format.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Runs astyle with the full set of formatting options +exec astyle \ + --style=otbs \ + --indent=spaces=4 \ + --convert-tabs \ + --align-pointer=name \ + --align-reference=name \ + --keep-one-line-statements \ + --pad-header \ + --pad-oper \ + "$@" diff --git a/tools/requirements.txt b/tools/requirements.txt new file mode 100644 index 000000000..50192ca7b --- /dev/null +++ b/tools/requirements.txt @@ -0,0 +1,2 @@ +pathspec +configparser diff --git a/tools/tag-files b/tools/tag-files new file mode 100755 index 000000000..ee04f33c5 --- /dev/null +++ b/tools/tag-files @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 +# Written by Trygve Laugstøl <trygvis@inamo.no> + +from __future__ import print_function +from pathspec import PathSpec +import argparse +import configparser +import os +import sys + +def err_print(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + +parser = argparse.ArgumentParser(description="Tag files") +parser.add_argument("--basedir", action="store", help="Where to start scanning") +parser.add_argument("--config", action="store", help="Config file to use. Default: tag-files.ini") + +args = parser.parse_args() +if help in args: + sys.exit(0) + +basedir = args.basedir if args.basedir else os.getcwd() +ini_file = args.config if args.config else "tag-files.ini" + +err_print("basedir={}".format(basedir)) +err_print("ini_file={}".format(ini_file)) + +config = configparser.ConfigParser(allow_no_value=True) +config.optionxform = str +try: + with open(ini_file, "r") as f: + config.read_file(f) +except IOError as e: + err_print("Could not open ini file: {}".format(ini_file)) + sys.exit(1) + +keys = set(k[:k.rindex(":")] for k in config if + (k.endswith(":include") or k.endswith(":exclude")) + and not k.startswith("tree:")) + +def load(key): + include = list(config[key + ":include"]) if key + ":include" in config else ["*"] + exclude = list(config[key + ":exclude"]) if key + ":exclude" in config else [] + + # print("{}: includes={}, excludes={}".format(key, len(includes), len(excludes))) + + return [PathSpec.from_lines('gitwildmatch', include), + PathSpec.from_lines('gitwildmatch', exclude)] + +checks = {k: load(k) for k in keys} + +tree = load("tree") + +tree = set(tree[0].match_tree(basedir)) -\ + set(tree[1].match_tree(basedir)) + +try: + for f in sorted(tree): + print(f, end="") + for k, v in checks.items(): + include = v[0].match_file(f) and not v[1].match_file(f) + i = "yes" if include else "no" + print("\t{}={}".format(k, i), end="") + print() +except IOError as e: + # This will happen if stdout is closed. Not a problem we care about fixing. + pass