aboutsummaryrefslogtreecommitdiff
path: root/contrib/devtools
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/devtools')
-rw-r--r--contrib/devtools/README.md34
-rwxr-xr-xcontrib/devtools/check-doc.py48
-rwxr-xr-xcontrib/devtools/check-rpc-mappings.py158
-rwxr-xr-xcontrib/devtools/circular-dependencies.py79
-rwxr-xr-xcontrib/devtools/clang-format-diff.py2
-rwxr-xr-xcontrib/devtools/commit-script-check.sh46
-rwxr-xr-xcontrib/devtools/copyright_header.py10
-rwxr-xr-xcontrib/devtools/gen-manpages.sh3
-rwxr-xr-xcontrib/devtools/git-subtree-check.sh94
-rwxr-xr-xcontrib/devtools/github-merge.py2
-rwxr-xr-xcontrib/devtools/lint-all.sh22
-rwxr-xr-xcontrib/devtools/lint-include-guards.sh29
-rwxr-xr-xcontrib/devtools/lint-includes.sh32
-rwxr-xr-xcontrib/devtools/lint-logs.sh25
-rwxr-xr-xcontrib/devtools/lint-python-shebang.sh11
-rwxr-xr-xcontrib/devtools/lint-python.sh74
-rwxr-xr-xcontrib/devtools/lint-shell.sh27
-rwxr-xr-xcontrib/devtools/lint-tests.sh34
-rwxr-xr-xcontrib/devtools/lint-whitespace.sh112
-rwxr-xr-xcontrib/devtools/security-check.py2
-rwxr-xr-xcontrib/devtools/test-security-check.py34
-rwxr-xr-xcontrib/devtools/update-translations.py10
22 files changed, 131 insertions, 757 deletions
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index 15ee8a3959..a0b6225345 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -2,12 +2,6 @@ Contents
========
This directory contains tools for developers working on this repository.
-check-doc.py
-============
-
-Check if all command line args are documented. The return value indicates the
-number of undocumented args.
-
clang-format-diff.py
===================
@@ -93,23 +87,6 @@ example:
BUILDDIR=$PWD/build contrib/devtools/gen-manpages.sh
```
-git-subtree-check.sh
-====================
-
-Run this script from the root of the repository to verify that a subtree matches the contents of
-the commit it claims to have been updated to.
-
-To use, make sure that you have fetched the upstream repository branch in which the subtree is
-maintained:
-* for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master)
-* for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork)
-* for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master)
-* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master)
-
-Usage: `git-subtree-check.sh DIR (COMMIT)`
-
-`COMMIT` may be omitted, in which case `HEAD` is used.
-
github-merge.py
===============
@@ -194,3 +171,14 @@ It will do the following automatically:
- add missing translations to the build system (TODO)
See doc/translation-process.md for more information.
+
+circular-dependencies.py
+========================
+
+Run this script from the root of the source tree (`src/`) to find circular dependencies in the source code.
+This looks only at which files include other files, treating the `.cpp` and `.h` file as one unit.
+
+Example usage:
+
+ cd .../src
+ ../contrib/devtools/circular-dependencies.py {*,*/*,*/*/*}.{h,cpp}
diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py
deleted file mode 100755
index 0c2e1a24be..0000000000
--- a/contrib/devtools/check-doc.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2015-2017 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-'''
-This checks if all command line args are documented.
-Return value is 0 to indicate no error.
-
-Author: @MarcoFalke
-'''
-
-from subprocess import check_output
-import re
-import sys
-
-FOLDER_GREP = 'src'
-FOLDER_TEST = 'src/test/'
-REGEX_ARG = '(?:ForceSet|SoftSet|Get|Is)(?:Bool)?Args?(?:Set)?\("(-[^"]+)"'
-REGEX_DOC = 'HelpMessageOpt\("(-[^"=]+?)(?:=|")'
-CMD_ROOT_DIR = '`git rev-parse --show-toplevel`/{}'.format(FOLDER_GREP)
-CMD_GREP_ARGS = r"git grep --perl-regexp '{}' -- {} ':(exclude){}'".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST)
-CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR)
-# list unsupported, deprecated and duplicate args as they need no documentation
-SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-dbcrashratio', '-forcecompactdb', '-usehd'])
-
-
-def main():
- used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True)
- docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True)
-
- args_used = set(re.findall(re.compile(REGEX_ARG), used))
- args_docd = set(re.findall(re.compile(REGEX_DOC), docd)).union(SET_DOC_OPTIONAL)
- args_need_doc = args_used.difference(args_docd)
- args_unknown = args_docd.difference(args_used)
-
- print("Args used : {}".format(len(args_used)))
- print("Args documented : {}".format(len(args_docd)))
- print("Args undocumented: {}".format(len(args_need_doc)))
- print(args_need_doc)
- print("Args unknown : {}".format(len(args_unknown)))
- print(args_unknown)
-
- sys.exit(len(args_need_doc))
-
-
-if __name__ == "__main__":
- main()
diff --git a/contrib/devtools/check-rpc-mappings.py b/contrib/devtools/check-rpc-mappings.py
deleted file mode 100755
index 7e96852c5c..0000000000
--- a/contrib/devtools/check-rpc-mappings.py
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2017 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Check RPC argument consistency."""
-
-from collections import defaultdict
-import os
-import re
-import sys
-
-# Source files (relative to root) to scan for dispatch tables
-SOURCES = [
- "src/rpc/server.cpp",
- "src/rpc/blockchain.cpp",
- "src/rpc/mining.cpp",
- "src/rpc/misc.cpp",
- "src/rpc/net.cpp",
- "src/rpc/rawtransaction.cpp",
- "src/wallet/rpcwallet.cpp",
-]
-# Source file (relative to root) containing conversion mapping
-SOURCE_CLIENT = 'src/rpc/client.cpp'
-# Argument names that should be ignored in consistency checks
-IGNORE_DUMMY_ARGS = {'dummy', 'arg0', 'arg1', 'arg2', 'arg3', 'arg4', 'arg5', 'arg6', 'arg7', 'arg8', 'arg9'}
-
-class RPCCommand:
- def __init__(self, name, args):
- self.name = name
- self.args = args
-
-class RPCArgument:
- def __init__(self, names, idx):
- self.names = names
- self.idx = idx
- self.convert = False
-
-def parse_string(s):
- assert s[0] == '"'
- assert s[-1] == '"'
- return s[1:-1]
-
-def process_commands(fname):
- """Find and parse dispatch table in implementation file `fname`."""
- cmds = []
- in_rpcs = False
- with open(fname, "r") as f:
- for line in f:
- line = line.rstrip()
- if not in_rpcs:
- if re.match("static const CRPCCommand .*\[\] =", line):
- in_rpcs = True
- else:
- if line.startswith('};'):
- in_rpcs = False
- elif '{' in line and '"' in line:
- m = re.search('{ *("[^"]*"), *("[^"]*"), *&([^,]*), *{([^}]*)} *},', line)
- assert m, 'No match to table expression: %s' % line
- name = parse_string(m.group(2))
- args_str = m.group(4).strip()
- if args_str:
- args = [RPCArgument(parse_string(x.strip()).split('|'), idx) for idx, x in enumerate(args_str.split(','))]
- else:
- args = []
- cmds.append(RPCCommand(name, args))
- assert not in_rpcs and cmds, "Something went wrong with parsing the C++ file: update the regexps"
- return cmds
-
-def process_mapping(fname):
- """Find and parse conversion table in implementation file `fname`."""
- cmds = []
- in_rpcs = False
- with open(fname, "r") as f:
- for line in f:
- line = line.rstrip()
- if not in_rpcs:
- if line == 'static const CRPCConvertParam vRPCConvertParams[] =':
- in_rpcs = True
- else:
- if line.startswith('};'):
- in_rpcs = False
- elif '{' in line and '"' in line:
- m = re.search('{ *("[^"]*"), *([0-9]+) *, *("[^"]*") *},', line)
- assert m, 'No match to table expression: %s' % line
- name = parse_string(m.group(1))
- idx = int(m.group(2))
- argname = parse_string(m.group(3))
- cmds.append((name, idx, argname))
- assert not in_rpcs and cmds
- return cmds
-
-def main():
- root = sys.argv[1]
-
- # Get all commands from dispatch tables
- cmds = []
- for fname in SOURCES:
- cmds += process_commands(os.path.join(root, fname))
-
- cmds_by_name = {}
- for cmd in cmds:
- cmds_by_name[cmd.name] = cmd
-
- # Get current convert mapping for client
- client = SOURCE_CLIENT
- mapping = set(process_mapping(os.path.join(root, client)))
-
- print('* Checking consistency between dispatch tables and vRPCConvertParams')
-
- # Check mapping consistency
- errors = 0
- for (cmdname, argidx, argname) in mapping:
- try:
- rargnames = cmds_by_name[cmdname].args[argidx].names
- except IndexError:
- print('ERROR: %s argument %i (named %s in vRPCConvertParams) is not defined in dispatch table' % (cmdname, argidx, argname))
- errors += 1
- continue
- if argname not in rargnames:
- print('ERROR: %s argument %i is named %s in vRPCConvertParams but %s in dispatch table' % (cmdname, argidx, argname, rargnames), file=sys.stderr)
- errors += 1
-
- # Check for conflicts in vRPCConvertParams conversion
- # All aliases for an argument must either be present in the
- # conversion table, or not. Anything in between means an oversight
- # and some aliases won't work.
- for cmd in cmds:
- for arg in cmd.args:
- convert = [((cmd.name, arg.idx, argname) in mapping) for argname in arg.names]
- if any(convert) != all(convert):
- print('ERROR: %s argument %s has conflicts in vRPCConvertParams conversion specifier %s' % (cmd.name, arg.names, convert))
- errors += 1
- arg.convert = all(convert)
-
- # Check for conversion difference by argument name.
- # It is preferable for API consistency that arguments with the same name
- # have the same conversion, so bin by argument name.
- all_methods_by_argname = defaultdict(list)
- converts_by_argname = defaultdict(list)
- for cmd in cmds:
- for arg in cmd.args:
- for argname in arg.names:
- all_methods_by_argname[argname].append(cmd.name)
- converts_by_argname[argname].append(arg.convert)
-
- for argname, convert in converts_by_argname.items():
- if all(convert) != any(convert):
- if argname in IGNORE_DUMMY_ARGS:
- # these are testing or dummy, don't warn for them
- continue
- print('WARNING: conversion mismatch for argument named %s (%s)' %
- (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname]))))
-
- sys.exit(errors > 0)
-
-
-if __name__ == '__main__':
- main()
diff --git a/contrib/devtools/circular-dependencies.py b/contrib/devtools/circular-dependencies.py
new file mode 100755
index 0000000000..abfa5ed5ae
--- /dev/null
+++ b/contrib/devtools/circular-dependencies.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+
+import sys
+import re
+
+MAPPING = {
+ 'core_read.cpp': 'core_io.cpp',
+ 'core_write.cpp': 'core_io.cpp',
+}
+
+def module_name(path):
+ if path in MAPPING:
+ path = MAPPING[path]
+ if path.endswith(".h"):
+ return path[:-2]
+ if path.endswith(".c"):
+ return path[:-2]
+ if path.endswith(".cpp"):
+ return path[:-4]
+ return None
+
+files = dict()
+deps = dict()
+
+RE = re.compile("^#include <(.*)>")
+
+# Iterate over files, and create list of modules
+for arg in sys.argv[1:]:
+ module = module_name(arg)
+ if module is None:
+ print("Ignoring file %s (does not constitute module)\n" % arg)
+ else:
+ files[arg] = module
+ deps[module] = set()
+
+# Iterate again, and build list of direct dependencies for each module
+# TODO: implement support for multiple include directories
+for arg in sorted(files.keys()):
+ module = files[arg]
+ with open(arg, 'r', encoding="utf8") as f:
+ for line in f:
+ match = RE.match(line)
+ if match:
+ include = match.group(1)
+ included_module = module_name(include)
+ if included_module is not None and included_module in deps and included_module != module:
+ deps[module].add(included_module)
+
+# Loop to find the shortest (remaining) circular dependency
+have_cycle = False
+while True:
+ shortest_cycle = None
+ for module in sorted(deps.keys()):
+ # Build the transitive closure of dependencies of module
+ closure = dict()
+ for dep in deps[module]:
+ closure[dep] = []
+ while True:
+ old_size = len(closure)
+ old_closure_keys = sorted(closure.keys())
+ for src in old_closure_keys:
+ for dep in deps[src]:
+ if dep not in closure:
+ closure[dep] = closure[src] + [src]
+ if len(closure) == old_size:
+ break
+ # If module is in its own transitive closure, it's a circular dependency; check if it is the shortest
+ if module in closure and (shortest_cycle is None or len(closure[module]) + 1 < len(shortest_cycle)):
+ shortest_cycle = [module] + closure[module]
+ if shortest_cycle is None:
+ break
+ # We have the shortest circular dependency; report it
+ module = shortest_cycle[0]
+ print("Circular dependency: %s" % (" -> ".join(shortest_cycle + [module])))
+ # And then break the dependency to avoid repeating in other cycles
+ deps[shortest_cycle[-1]] = deps[shortest_cycle[-1]] - set([module])
+ have_cycle = True
+
+sys.exit(1 if have_cycle else 0)
diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py
index 5402870fba..77e845a9b4 100755
--- a/contrib/devtools/clang-format-diff.py
+++ b/contrib/devtools/clang-format-diff.py
@@ -152,7 +152,7 @@ def main():
sys.exit(p.returncode)
if not args.i:
- with open(filename) as f:
+ with open(filename, encoding="utf8") as f:
code = f.readlines()
formatted_code = io.StringIO(stdout).readlines()
diff = difflib.unified_diff(code, formatted_code,
diff --git a/contrib/devtools/commit-script-check.sh b/contrib/devtools/commit-script-check.sh
deleted file mode 100755
index 1c9dbc7f68..0000000000
--- a/contrib/devtools/commit-script-check.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-# Copyright (c) 2017 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-# This simple script checks for commits beginning with: scripted-diff:
-# If found, looks for a script between the lines -BEGIN VERIFY SCRIPT- and
-# -END VERIFY SCRIPT-. If no ending is found, it reads until the end of the
-# commit message.
-
-# The resulting script should exactly transform the previous commit into the current
-# one. Any remaining diff signals an error.
-
-if test "x$1" = "x"; then
- echo "Usage: $0 <commit>..."
- exit 1
-fi
-
-RET=0
-PREV_BRANCH=`git name-rev --name-only HEAD`
-PREV_HEAD=`git rev-parse HEAD`
-for i in `git rev-list --reverse $1`; do
- if git rev-list -n 1 --pretty="%s" $i | grep -q "^scripted-diff:"; then
- git checkout --quiet $i^ || exit
- SCRIPT="`git rev-list --format=%b -n1 $i | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d'`"
- if test "x$SCRIPT" = "x"; then
- echo "Error: missing script for: $i"
- echo "Failed"
- RET=1
- else
- echo "Running script for: $i"
- echo "$SCRIPT"
- eval "$SCRIPT"
- git --no-pager diff --exit-code $i && echo "OK" || (echo "Failed"; false) || RET=1
- fi
- git reset --quiet --hard HEAD
- else
- if git rev-list "--format=%b" -n1 $i | grep -q '^-\(BEGIN\|END\)[ a-zA-Z]*-$'; then
- echo "Error: script block marker but no scripted-diff in title"
- echo "Failed"
- RET=1
- fi
- fi
-done
-git checkout --quiet $PREV_BRANCH 2>/dev/null || git checkout --quiet $PREV_HEAD
-exit $RET
diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py
index e7cccaab03..da7d74bdc4 100755
--- a/contrib/devtools/copyright_header.py
+++ b/contrib/devtools/copyright_header.py
@@ -146,7 +146,7 @@ def file_has_without_c_style_copyright_for_holder(contents, holder_name):
################################################################################
def read_file(filename):
- return open(os.path.abspath(filename), 'r').read()
+ return open(os.path.abspath(filename), 'r', encoding="utf8").read()
def gather_file_info(filename):
info = {}
@@ -325,13 +325,13 @@ def get_most_recent_git_change_year(filename):
################################################################################
def read_file_lines(filename):
- f = open(os.path.abspath(filename), 'r')
+ f = open(os.path.abspath(filename), 'r', encoding="utf8")
file_lines = f.readlines()
f.close()
return file_lines
def write_file_lines(filename, file_lines):
- f = open(os.path.abspath(filename), 'w')
+ f = open(os.path.abspath(filename), 'w', encoding="utf8")
f.write(''.join(file_lines))
f.close()
@@ -506,7 +506,7 @@ def file_has_hashbang(file_lines):
def insert_python_header(filename, file_lines, start_year, end_year):
if file_has_hashbang(file_lines):
- insert_idx = 1
+ insert_idx = 1
else:
insert_idx = 0
header_lines = get_python_header_lines_to_insert(start_year, end_year)
@@ -571,7 +571,7 @@ def insert_cmd(argv):
if extension not in ['.h', '.cpp', '.cc', '.c', '.py']:
sys.exit("*** cannot insert for file extension %s" % extension)
- if extension == '.py':
+ if extension == '.py':
style = 'python'
else:
style = 'cpp'
diff --git a/contrib/devtools/gen-manpages.sh b/contrib/devtools/gen-manpages.sh
index 27c80548c1..b5de5a395f 100755
--- a/contrib/devtools/gen-manpages.sh
+++ b/contrib/devtools/gen-manpages.sh
@@ -1,5 +1,6 @@
-#!/bin/bash
+#!/usr/bin/env bash
+export LC_ALL=C
TOPDIR=${TOPDIR:-$(git rev-parse --show-toplevel)}
BUILDDIR=${BUILDDIR:-$TOPDIR}
diff --git a/contrib/devtools/git-subtree-check.sh b/contrib/devtools/git-subtree-check.sh
deleted file mode 100755
index 184951715e..0000000000
--- a/contrib/devtools/git-subtree-check.sh
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/bin/sh
-# Copyright (c) 2015 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-DIR="$1"
-COMMIT="$2"
-if [ -z "$COMMIT" ]; then
- COMMIT=HEAD
-fi
-
-# Taken from git-subtree (Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>)
-find_latest_squash()
-{
- dir="$1"
- sq=
- main=
- sub=
- git log --grep="^git-subtree-dir: $dir/*\$" \
- --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$COMMIT" |
- while read a b _; do
- case "$a" in
- START) sq="$b" ;;
- git-subtree-mainline:) main="$b" ;;
- git-subtree-split:) sub="$b" ;;
- END)
- if [ -n "$sub" ]; then
- if [ -n "$main" ]; then
- # a rejoin commit?
- # Pretend its sub was a squash.
- sq="$sub"
- fi
- echo "$sq" "$sub"
- break
- fi
- sq=
- main=
- sub=
- ;;
- esac
- done
-}
-
-# find latest subtree update
-latest_squash="$(find_latest_squash "$DIR")"
-if [ -z "$latest_squash" ]; then
- echo "ERROR: $DIR is not a subtree" >&2
- exit 2
-fi
-set $latest_squash
-old=$1
-rev=$2
-
-# get the tree in the current commit
-tree_actual=$(git ls-tree -d "$COMMIT" "$DIR" | head -n 1)
-if [ -z "$tree_actual" ]; then
- echo "FAIL: subtree directory $DIR not found in $COMMIT" >&2
- exit 1
-fi
-set $tree_actual
-tree_actual_type=$2
-tree_actual_tree=$3
-echo "$DIR in $COMMIT currently refers to $tree_actual_type $tree_actual_tree"
-if [ "d$tree_actual_type" != "dtree" ]; then
- echo "FAIL: subtree directory $DIR is not a tree in $COMMIT" >&2
- exit 1
-fi
-
-# get the tree at the time of the last subtree update
-tree_commit=$(git show -s --format="%T" $old)
-echo "$DIR in $COMMIT was last updated in commit $old (tree $tree_commit)"
-
-# ... and compare the actual tree with it
-if [ "$tree_actual_tree" != "$tree_commit" ]; then
- git diff $tree_commit $tree_actual_tree >&2
- echo "FAIL: subtree directory was touched without subtree merge" >&2
- exit 1
-fi
-
-# get the tree in the subtree commit referred to
-if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then
- echo "subtree commit $rev unavailable: cannot compare" >&2
- exit
-fi
-tree_subtree=$(git show -s --format="%T" $rev)
-echo "$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)"
-
-# ... and compare the actual tree with it
-if [ "$tree_actual_tree" != "$tree_subtree" ]; then
- echo "FAIL: subtree update commit differs from upstream tree!" >&2
- exit 1
-fi
-
-echo "GOOD"
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index 187ef75fb7..4e90f85f50 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -191,7 +191,7 @@ def main():
merge_branch = 'pull/'+pull+'/merge'
local_merge_branch = 'pull/'+pull+'/local-merge'
- devnull = open(os.devnull,'w')
+ devnull = open(os.devnull, 'w', encoding="utf8")
try:
subprocess.check_call([GIT,'checkout','-q',branch])
except subprocess.CalledProcessError:
diff --git a/contrib/devtools/lint-all.sh b/contrib/devtools/lint-all.sh
deleted file mode 100755
index b6d86959c6..0000000000
--- a/contrib/devtools/lint-all.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2017 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# This script runs all contrib/devtools/lint-*.sh files, and fails if any exit
-# with a non-zero status code.
-
-set -u
-
-SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
-LINTALL=$(basename "${BASH_SOURCE[0]}")
-
-for f in "${SCRIPTDIR}"/lint-*.sh; do
- if [ "$(basename "$f")" != "$LINTALL" ]; then
- if ! "$f"; then
- echo "^---- failure generated from $f"
- exit 1
- fi
- fi
-done
diff --git a/contrib/devtools/lint-include-guards.sh b/contrib/devtools/lint-include-guards.sh
deleted file mode 100755
index 6a0dd556bb..0000000000
--- a/contrib/devtools/lint-include-guards.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Check include guards.
-
-HEADER_ID_PREFIX="BITCOIN_"
-HEADER_ID_SUFFIX="_H"
-
-REGEXP_EXCLUDE_FILES_WITH_PREFIX="src/(crypto/ctaes/|leveldb/|secp256k1/|tinyformat.h|univalue/)"
-
-EXIT_CODE=0
-for HEADER_FILE in $(git ls-files -- "*.h" | grep -vE "^${REGEXP_EXCLUDE_FILES_WITH_PREFIX}")
-do
- HEADER_ID_BASE=$(cut -f2- -d/ <<< "${HEADER_FILE}" | sed "s/\.h$//g" | tr / _ | tr "[:lower:]" "[:upper:]")
- HEADER_ID="${HEADER_ID_PREFIX}${HEADER_ID_BASE}${HEADER_ID_SUFFIX}"
- if [[ $(grep -cE "^#(ifndef|define) ${HEADER_ID}" "${HEADER_FILE}") != 2 ]]; then
- echo "${HEADER_FILE} seems to be missing the expected include guard:"
- echo " #ifndef ${HEADER_ID}"
- echo " #define ${HEADER_ID}"
- echo " ..."
- echo " #endif // ${HEADER_ID}"
- echo
- EXIT_CODE=1
- fi
-done
-exit ${EXIT_CODE}
diff --git a/contrib/devtools/lint-includes.sh b/contrib/devtools/lint-includes.sh
deleted file mode 100755
index f54be46b52..0000000000
--- a/contrib/devtools/lint-includes.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Check for duplicate includes.
-
-filter_suffix() {
- git ls-files | grep -E "^src/.*\.${1}"'$' | grep -Ev "/(leveldb|secp256k1|univalue)/"
-}
-
-EXIT_CODE=0
-for HEADER_FILE in $(filter_suffix h); do
- DUPLICATE_INCLUDES_IN_HEADER_FILE=$(grep -E "^#include " < "${HEADER_FILE}" | sort | uniq -d)
- if [[ ${DUPLICATE_INCLUDES_IN_HEADER_FILE} != "" ]]; then
- echo "Duplicate include(s) in ${HEADER_FILE}:"
- echo "${DUPLICATE_INCLUDES_IN_HEADER_FILE}"
- echo
- EXIT_CODE=1
- fi
-done
-for CPP_FILE in $(filter_suffix cpp); do
- DUPLICATE_INCLUDES_IN_CPP_FILE=$(grep -E "^#include " < "${CPP_FILE}" | sort | uniq -d)
- if [[ ${DUPLICATE_INCLUDES_IN_CPP_FILE} != "" ]]; then
- echo "Duplicate include(s) in ${CPP_FILE}:"
- echo "${DUPLICATE_INCLUDES_IN_CPP_FILE}"
- echo
- EXIT_CODE=1
- fi
-done
-exit ${EXIT_CODE}
diff --git a/contrib/devtools/lint-logs.sh b/contrib/devtools/lint-logs.sh
deleted file mode 100755
index 3bb54359a8..0000000000
--- a/contrib/devtools/lint-logs.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Check that all logs are terminated with '\n'
-#
-# Some logs are continued over multiple lines. They should be explicitly
-# commented with \* Continued *\
-#
-# There are some instances of LogPrintf() in comments. Those can be
-# ignored
-
-
-UNTERMINATED_LOGS=$(git grep "LogPrintf(" -- "*.cpp" | \
- grep -v '\\n"' | \
- grep -v "/\* Continued \*/" | \
- grep -v "LogPrintf()")
-if [[ ${UNTERMINATED_LOGS} != "" ]]; then
- echo "All calls to LogPrintf() should be terminated with \\n"
- echo
- echo "${UNTERMINATED_LOGS}"
- exit 1
-fi
diff --git a/contrib/devtools/lint-python-shebang.sh b/contrib/devtools/lint-python-shebang.sh
deleted file mode 100755
index f5c5971c03..0000000000
--- a/contrib/devtools/lint-python-shebang.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-# Shebang must use python3 (not python or python2)
-EXIT_CODE=0
-for PYTHON_FILE in $(git ls-files -- "*.py"); do
- if [[ $(head -c 2 "${PYTHON_FILE}") == "#!" &&
- $(head -n 1 "${PYTHON_FILE}") != "#!/usr/bin/env python3" ]]; then
- echo "Missing shebang \"#!/usr/bin/env python3\" in ${PYTHON_FILE} (do not use python or python2)"
- EXIT_CODE=1
- fi
-done
-exit ${EXIT_CODE}
diff --git a/contrib/devtools/lint-python.sh b/contrib/devtools/lint-python.sh
deleted file mode 100755
index 239337000d..0000000000
--- a/contrib/devtools/lint-python.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2017 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Check for specified flake8 warnings in python files.
-
-# E112 expected an indented block
-# E113 unexpected indentation
-# E115 expected an indented block (comment)
-# E116 unexpected indentation (comment)
-# E125 continuation line with same indent as next logical line
-# E131 continuation line unaligned for hanging indent
-# E133 closing bracket is missing indentation
-# E223 tab before operator
-# E224 tab after operator
-# E242 tab after ','
-# E266 too many leading '#' for block comment
-# E271 multiple spaces after keyword
-# E272 multiple spaces before keyword
-# E273 tab after keyword
-# E274 tab before keyword
-# E275 missing whitespace after keyword
-# E304 blank lines found after function decorator
-# E306 expected 1 blank line before a nested definition
-# E401 multiple imports on one line
-# E402 module level import not at top of file
-# E502 the backslash is redundant between brackets
-# E701 multiple statements on one line (colon)
-# E702 multiple statements on one line (semicolon)
-# E703 statement ends with a semicolon
-# E714 test for object identity should be "is not"
-# E721 do not compare types, use "isinstance()"
-# E741 do not use variables named "l", "O", or "I"
-# E742 do not define classes named "l", "O", or "I"
-# E743 do not define functions named "l", "O", or "I"
-# E901 SyntaxError: invalid syntax
-# E902 TokenError: EOF in multi-line string
-# F401 module imported but unused
-# F402 import module from line N shadowed by loop variable
-# F404 future import(s) name after other statements
-# F406 "from module import *" only allowed at module level
-# F407 an undefined __future__ feature name was imported
-# F601 dictionary key name repeated with different values
-# F602 dictionary key variable name repeated with different values
-# F621 too many expressions in an assignment with star-unpacking
-# F622 two or more starred expressions in an assignment (a, *b, *c = d)
-# F631 assertion test is a tuple, which are always True
-# F701 a break statement outside of a while or for loop
-# F702 a continue statement outside of a while or for loop
-# F703 a continue statement in a finally block in a loop
-# F704 a yield or yield from statement outside of a function
-# F705 a return statement with arguments inside a generator
-# F706 a return statement outside of a function/method
-# F707 an except: block as not the last exception handler
-# F811 redefinition of unused name from line N
-# F812 list comprehension redefines 'foo' from line N
-# F821 undefined name 'Foo'
-# F822 undefined name name in __all__
-# F823 local variable name … referenced before assignment
-# F831 duplicate argument name in function definition
-# F841 local variable 'foo' is assigned to but never used
-# W292 no newline at end of file
-# W293 blank line contains whitespace
-# W504 line break after binary operator
-# W601 .has_key() is deprecated, use "in"
-# W602 deprecated form of raising exception
-# W603 "<>" is deprecated, use "!="
-# W604 backticks are deprecated, use "repr()"
-# W605 invalid escape sequence "x"
-# W606 'async' and 'await' are reserved keywords starting with Python 3.7
-
-flake8 --ignore=B,C,E,F,I,N,W --select=E112,E113,E115,E116,E125,E131,E133,E223,E224,E242,E266,E271,E272,E273,E274,E275,E304,E306,E401,E402,E502,E701,E702,E703,E714,E721,E741,E742,E743,F401,E901,E902,F402,F404,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F821,F822,F823,F831,F841,W292,W293,W504,W601,W602,W603,W604,W605,W606 .
diff --git a/contrib/devtools/lint-shell.sh b/contrib/devtools/lint-shell.sh
deleted file mode 100755
index 5f5fa9a925..0000000000
--- a/contrib/devtools/lint-shell.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Check for shellcheck warnings in shell scripts.
-
-# Disabled warnings:
-# SC2001: See if you can use ${variable//search/replace} instead.
-# SC2004: $/${} is unnecessary on arithmetic variables.
-# SC2005: Useless echo? Instead of 'echo $(cmd)', just use 'cmd'.
-# SC2006: Use $(..) instead of legacy `..`.
-# SC2016: Expressions don't expand in single quotes, use double quotes for that.
-# SC2028: echo won't expand escape sequences. Consider printf.
-# SC2046: Quote this to prevent word splitting.
-# SC2048: Use "$@" (with quotes) to prevent whitespace problems.
-# SC2066: Since you double quoted this, it will not word split, and the loop will only run once.
-# SC2086: Double quote to prevent globbing and word splitting.
-# SC2116: Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'.
-# SC2148: Tips depend on target shell and yours is unknown. Add a shebang.
-# SC2162: read without -r will mangle backslashes.
-# SC2166: Prefer [ p ] && [ q ] as [ p -a q ] is not well defined.
-# SC2166: Prefer [ p ] || [ q ] as [ p -o q ] is not well defined.
-# SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
-shellcheck -e SC2001,SC2004,SC2005,SC2006,SC2016,SC2028,SC2046,SC2048,SC2066,SC2086,SC2116,SC2148,SC2162,SC2166,SC2181 \
- $(git ls-files -- "*.sh" | grep -vE 'src/(secp256k1|univalue)/')
diff --git a/contrib/devtools/lint-tests.sh b/contrib/devtools/lint-tests.sh
deleted file mode 100755
index ffc0660551..0000000000
--- a/contrib/devtools/lint-tests.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Check the test suite naming conventions
-
-EXIT_CODE=0
-
-NAMING_INCONSISTENCIES=$(git grep -E '^BOOST_FIXTURE_TEST_SUITE\(' -- \
- "src/test/**.cpp" "src/wallet/test/**.cpp" | \
- grep -vE '/(.*?)\.cpp:BOOST_FIXTURE_TEST_SUITE\(\1, .*\)$')
-if [[ ${NAMING_INCONSISTENCIES} != "" ]]; then
- echo "The test suite in file src/test/foo_tests.cpp should be named"
- echo "\"foo_tests\". Please make sure the following test suites follow"
- echo "that convention:"
- echo
- echo "${NAMING_INCONSISTENCIES}"
- EXIT_CODE=1
-fi
-
-TEST_SUITE_NAME_COLLISSIONS=$(git grep -E '^BOOST_FIXTURE_TEST_SUITE\(' -- \
- "src/test/**.cpp" "src/wallet/test/**.cpp" | cut -f2 -d'(' | cut -f1 -d, | \
- sort | uniq -d)
-if [[ ${TEST_SUITE_NAME_COLLISSIONS} != "" ]]; then
- echo "Test suite names must be unique. The following test suite names"
- echo "appear to be used more than once:"
- echo
- echo "${TEST_SUITE_NAME_COLLISSIONS}"
- EXIT_CODE=1
-fi
-
-exit ${EXIT_CODE}
diff --git a/contrib/devtools/lint-whitespace.sh b/contrib/devtools/lint-whitespace.sh
deleted file mode 100755
index c5d43043d5..0000000000
--- a/contrib/devtools/lint-whitespace.sh
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2017 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Check for new lines in diff that introduce trailing whitespace.
-
-# We can't run this check unless we know the commit range for the PR.
-
-while getopts "?" opt; do
- case $opt in
- ?)
- echo "Usage: .lint-whitespace.sh [N]"
- echo " TRAVIS_COMMIT_RANGE='<commit range>' .lint-whitespace.sh"
- echo " .lint-whitespace.sh -?"
- echo "Checks unstaged changes, the previous N commits, or a commit range."
- echo "TRAVIS_COMMIT_RANGE='47ba2c3...ee50c9e' .lint-whitespace.sh"
- exit 0
- ;;
- esac
-done
-
-if [ -z "${TRAVIS_COMMIT_RANGE}" ]; then
- if [ "$1" ]; then
- TRAVIS_COMMIT_RANGE="HEAD~$1...HEAD"
- else
- TRAVIS_COMMIT_RANGE="HEAD"
- fi
-fi
-
-showdiff() {
- if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/"; then
- echo "Failed to get a diff"
- exit 1
- fi
-}
-
-showcodediff() {
- if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- *.cpp *.h *.md *.py *.sh ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/"; then
- echo "Failed to get a diff"
- exit 1
- fi
-}
-
-RET=0
-
-# Check if trailing whitespace was found in the diff.
-if showdiff | grep -E -q '^\+.*\s+$'; then
- echo "This diff appears to have added new lines with trailing whitespace."
- echo "The following changes were suspected:"
- FILENAME=""
- SEEN=0
- SEENLN=0
- while read -r line; do
- if [[ "$line" =~ ^diff ]]; then
- FILENAME="$line"
- SEEN=0
- elif [[ "$line" =~ ^@@ ]]; then
- LINENUMBER="$line"
- SEENLN=0
- else
- if [ "$SEEN" -eq 0 ]; then
- # The first time a file is seen with trailing whitespace, we print the
- # filename (preceded by a newline).
- echo
- echo "$FILENAME"
- SEEN=1
- fi
- if [ "$SEENLN" -eq 0 ]; then
- echo "$LINENUMBER"
- SEENLN=1
- fi
- echo "$line"
- fi
- done < <(showdiff | grep -E '^(diff --git |@@|\+.*\s+$)')
- RET=1
-fi
-
-# Check if tab characters were found in the diff.
-if showcodediff | perl -nle '$MATCH++ if m{^\+.*\t}; END{exit 1 unless $MATCH>0}' > /dev/null; then
- echo "This diff appears to have added new lines with tab characters instead of spaces."
- echo "The following changes were suspected:"
- FILENAME=""
- SEEN=0
- SEENLN=0
- while read -r line; do
- if [[ "$line" =~ ^diff ]]; then
- FILENAME="$line"
- SEEN=0
- elif [[ "$line" =~ ^@@ ]]; then
- LINENUMBER="$line"
- SEENLN=0
- else
- if [ "$SEEN" -eq 0 ]; then
- # The first time a file is seen with a tab character, we print the
- # filename (preceded by a newline).
- echo
- echo "$FILENAME"
- SEEN=1
- fi
- if [ "$SEENLN" -eq 0 ]; then
- echo "$LINENUMBER"
- SEENLN=1
- fi
- echo "$line"
- fi
- done < <(showcodediff | perl -nle 'print if m{^(diff --git |@@|\+.*\t)}')
- RET=1
-fi
-
-exit $RET
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 0f2099953f..c9516ef83f 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -150,7 +150,7 @@ def check_PE_DYNAMIC_BASE(executable):
def check_PE_HIGH_ENTROPY_VA(executable):
'''PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR'''
(arch,bits) = get_PE_dll_characteristics(executable)
- if arch == 'i386:x86-64':
+ if arch == 'i386:x86-64':
reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
else: # Unnecessary on 32-bit
assert(arch == 'i386')
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index ee87c8bab4..9b6d6bf665 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -9,7 +9,7 @@ import subprocess
import unittest
def write_testcode(filename):
- with open(filename, 'w') as f:
+ with open(filename, 'w', encoding="utf8") as f:
f.write('''
#include <stdio.h>
int main()
@@ -32,29 +32,39 @@ class TestSecurityChecks(unittest.TestCase):
cc = 'gcc'
write_testcode(source)
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro']),
(1, executable+': failed PIE NX RELRO Canary'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro']),
(1, executable+': failed PIE RELRO Canary'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro']),
(1, executable+': failed PIE RELRO'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE']),
(1, executable+': failed RELRO'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']),
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']),
(0, ''))
- def test_PE(self):
+ def test_32bit_PE(self):
source = 'test1.c'
executable = 'test1.exe'
cc = 'i686-w64-mingw32-gcc'
write_testcode(source)
- self.assertEqual(call_security_check(cc, source, executable, []),
- (1, executable+': failed PIE NX'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']),
- (1, executable+': failed PIE'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']),
+ self.assertEqual(call_security_check(cc, source, executable, []),
+ (1, executable+': failed DYNAMIC_BASE NX'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']),
+ (1, executable+': failed DYNAMIC_BASE'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']),
(0, ''))
+ def test_64bit_PE(self):
+ source = 'test1.c'
+ executable = 'test1.exe'
+ cc = 'x86_64-w64-mingw32-gcc'
+ write_testcode(source)
+
+ self.assertEqual(call_security_check(cc, source, executable, []), (1, executable+': failed DYNAMIC_BASE NX\n'+executable+': warning HIGH_ENTROPY_VA'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']), (1, executable+': failed DYNAMIC_BASE\n'+executable+': warning HIGH_ENTROPY_VA'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']), (0, executable+': warning HIGH_ENTROPY_VA'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--high-entropy-va']), (0, ''))
if __name__ == '__main__':
unittest.main()
diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py
index b36e6968bf..f0098cfcdf 100755
--- a/contrib/devtools/update-translations.py
+++ b/contrib/devtools/update-translations.py
@@ -30,6 +30,8 @@ SOURCE_LANG = 'bitcoin_en.ts'
LOCALE_DIR = 'src/qt/locale'
# Minimum number of messages for translation to be considered at all
MIN_NUM_MESSAGES = 10
+# Regexp to check for Bitcoin addresses
+ADDRESS_REGEXP = re.compile('([13]|bc1)[a-zA-Z0-9]{30,}')
def check_at_repository_root():
if not os.path.exists('.git'):
@@ -122,6 +124,12 @@ def escape_cdata(text):
text = text.replace('"', '&quot;')
return text
+def contains_bitcoin_addr(text, errors):
+ if text != None and ADDRESS_REGEXP.search(text) != None:
+ errors.append('Translation "%s" contains a bitcoin address. This will be removed.' % (text))
+ return True
+ return False
+
def postprocess_translations(reduce_diff_hacks=False):
print('Checking and postprocessing...')
@@ -160,7 +168,7 @@ def postprocess_translations(reduce_diff_hacks=False):
if translation is None:
continue
errors = []
- valid = check_format_specifiers(source, translation, errors, numerus)
+ valid = check_format_specifiers(source, translation, errors, numerus) and not contains_bitcoin_addr(translation, errors)
for error in errors:
print('%s: %s' % (filename, error))