mirror of https://github.com/ArduPilot/ardupilot
Tools: add script for standardize includes of libraries headers
This commit is contained in:
parent
ce0cb248ce
commit
ae9a314295
|
@ -0,0 +1,225 @@
|
|||
#!/bin/bash
|
||||
|
||||
src=$(realpath $(dirname $BASH_SOURCE)/../../)
|
||||
base=$src/libraries
|
||||
declare -A header_dirs
|
||||
|
||||
arg_verbose=false
|
||||
arg_create_commits=false
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: $(basename $BASH_SOURCE) [-h|--help]
|
||||
|
||||
Fix includes of libraries headers in source files to be as the following:
|
||||
|
||||
- If the header is in the same directory the source belongs to, then the
|
||||
notation #include "" is used with the path relative to the directory
|
||||
containing the source.
|
||||
|
||||
- If the header is outside the directory containing the source, then we use
|
||||
the notation #include <> with the path relative to libraries folder.
|
||||
|
||||
The output is a log of the process.
|
||||
|
||||
Options:
|
||||
-h,--help
|
||||
Display this help message.
|
||||
|
||||
-v,--verbose
|
||||
Not only log errors and warnings but also substitutions.
|
||||
|
||||
-c,--create-commits
|
||||
Create commits in the end.
|
||||
|
||||
--commit
|
||||
Assume that the user have run the substitutions beforehand - only
|
||||
create the commits.
|
||||
EOF
|
||||
}
|
||||
|
||||
create_commits(){
|
||||
for f in $(git diff-files --name-only); do
|
||||
if [[ ${f%%/*} == "libraries" ]]; then
|
||||
echo $f | sed "s,\(libraries/[^/]*\)/.*,\1,"
|
||||
else
|
||||
echo ${f%%/*}
|
||||
fi
|
||||
done | uniq | while read d; do
|
||||
if [[ $d == libraries/* ]]; then
|
||||
commit_base=${d#libraries/}
|
||||
else
|
||||
commit_base=$d
|
||||
fi
|
||||
cat >/tmp/commit_msg <<EOF
|
||||
$commit_base: standardize inclusion of libaries headers
|
||||
|
||||
This commit changes the way libraries headers are included in source files:
|
||||
|
||||
- If the header is in the same directory the source belongs to, so the
|
||||
notation '#include ""' is used with the path relative to the directory
|
||||
containing the source.
|
||||
|
||||
- If the header is outside the directory containing the source, then we use
|
||||
the notation '#include <>' with the path relative to libraries folder.
|
||||
|
||||
Some of the advantages of such approach:
|
||||
|
||||
- Only one search path for libraries headers.
|
||||
|
||||
- OSs like Windows may have a better lookup time.
|
||||
EOF
|
||||
git add -u $d
|
||||
git commit -F /tmp/commit_msg
|
||||
done
|
||||
}
|
||||
|
||||
replace_include(){
|
||||
local file=$1
|
||||
local n=$2
|
||||
local new_path=$3
|
||||
local old_path=$4
|
||||
local regex="\(#\s*include\s*\)[<\"].\+[>\"]"
|
||||
|
||||
[[ $new_path == $old_path ]] && return
|
||||
|
||||
$arg_verbose && echo "$file:$n: $old_path --> $new_path"
|
||||
if ! sed -i "${n}s,$regex,\1$new_path," $file; then
|
||||
echo Error on executing command: sed -i "${n}s,$regex,\1$new_path," $file >&2
|
||||
kill -SIGINT $$
|
||||
fi
|
||||
}
|
||||
|
||||
fix_includes(){
|
||||
local file=$1
|
||||
local header=$2
|
||||
local dirs=(${header_dirs[$header]})
|
||||
local num_dirs=${#dirs[@]}
|
||||
local regex="^\s*#\s*include\s*[<\"]\(.*/\)\?$header[>\"]"
|
||||
|
||||
grep -ahno $regex $file | while IFS=":" read n match; do
|
||||
path=$(echo $match | sed "s/^\s*#\s*include\s*//g")
|
||||
delim=${path:0:1}
|
||||
path=${path:1:(${#path}-2)}
|
||||
file_dir=$(realpath $(dirname $file))
|
||||
|
||||
if [[ $delim == "\"" ]]; then
|
||||
localpath=$file_dir/$path
|
||||
if [[ -f $localpath ]]; then
|
||||
# verify if file is under to the file dir
|
||||
localpath=$(realpath $localpath)
|
||||
[[ $localpath == $file_dir* ]] && continue
|
||||
|
||||
# if not under file dir, check if $localpath is under $base
|
||||
if [[ $localpath == $base* ]]; then
|
||||
new_path=${localpath#$base/}
|
||||
replace_include $file $n \<$new_path\> \"$path\"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
match_count=0
|
||||
possible_paths=()
|
||||
for dir in "${dirs[@]}"; do
|
||||
if [[ $dir/$header == *$path ]]; then
|
||||
((match_count++))
|
||||
new_path=$dir/$header
|
||||
possible_paths[${#possible_paths[@]}]=$new_path
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $match_count -eq 0 ]]; then
|
||||
echo "$file:$n: couldn't find a match for inclusion of $path"
|
||||
elif [[ $match_count -eq 1 ]]; then
|
||||
# check if included header is under file dir
|
||||
if [[ -f $file_dir/$path ]]; then
|
||||
new_path=\"$(realpath $file_dir/$path --relative-to $file_dir)\"
|
||||
else
|
||||
new_path=\<$new_path\>
|
||||
fi
|
||||
if [[ $delim == '"' ]]; then path=\"$path\"; else path=\<$path\>; fi
|
||||
replace_include $file $n $new_path $path
|
||||
else
|
||||
echo "$file:$n: more than one match for inclusion of $path"
|
||||
echo " possible paths:"
|
||||
for p in "${possible_paths[@]}"; do
|
||||
echo " $p"
|
||||
done
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
trap_reset_tree(){
|
||||
echo
|
||||
echo Process killed or interrupted! Reseting tree...
|
||||
git -C $src reset --hard
|
||||
exit 1
|
||||
}
|
||||
|
||||
# parse args
|
||||
while [[ -n $1 ]]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-v|--verbose)
|
||||
arg_verbose=true
|
||||
;;
|
||||
-c|--create-commits)
|
||||
arg_create_commits=true
|
||||
;;
|
||||
--commit)
|
||||
create_commits
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
trap trap_reset_tree SIGINT SIGKILL
|
||||
|
||||
if ! git -C $src diff-files --quiet --exit-code; then
|
||||
echo You have unstaged changes, please commit or stash them beforehand >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pushd $src > /dev/null
|
||||
|
||||
# collect all headers
|
||||
git -C $base ls-files *.h > /tmp/headers
|
||||
total=$(cat /tmp/headers | wc -l)
|
||||
header_max_len=0
|
||||
while read f; do
|
||||
header=$(basename $f)
|
||||
dir=$(dirname $f)
|
||||
if [[ -z ${header_dirs[$header]} ]]; then
|
||||
header_dirs[$header]=$dir
|
||||
else
|
||||
header_dirs[$header]+=" $dir"
|
||||
fi
|
||||
printf "\rCollecting header files paths... $((++i))/$total" >&2
|
||||
[[ ${#header} -gt $header_max_len ]] && header_max_len=${#header}
|
||||
done </tmp/headers
|
||||
echo
|
||||
|
||||
total=${#header_dirs[@]}
|
||||
i=0
|
||||
for header in "${!header_dirs[@]}"; do
|
||||
regex="#\s*include\s*[<\"]\(.*/\)\?$header[>\"]"
|
||||
printf "\r($((++i))/$total) Fixing includes for header %-${header_max_len}s" $header >&2
|
||||
|
||||
# for each file that includes $header
|
||||
git grep -l $regex | while read f; do
|
||||
fix_includes $f $header
|
||||
done
|
||||
done
|
||||
|
||||
$arg_create_commits && create_commits
|
||||
|
||||
popd > /dev/null
|
Loading…
Reference in New Issue