autotest: set parameter value so context pop resets it
[ardupilot.git] / Tools / scripts / fix_libraries_includes.sh
blob171fa598dab05f475c2cf4c4f66b5686cb3ea236
1 #!/usr/bin/env bash
3 src=$(realpath $(dirname $BASH_SOURCE)/../../)
4 base=$src/libraries
5 declare -A header_dirs
7 arg_verbose=false
8 arg_create_commits=false
10 usage(){
11 cat <<EOF
12 Usage: $(basename $BASH_SOURCE) [OPTIONS] [--] [<pathspec>...]
14 Fix includes of libraries headers in source files to be as the following:
16 - If the header is in the same directory the source belongs to, then the
17 notation #include "" is used with the path relative to the directory
18 containing the source.
20 - If the header is outside the directory containing the source, then we use
21 the notation #include <> with the path relative to libraries folder.
23 If pathspec is given then it's an argument passed directly to git-grep. See
24 git-grep(1) for more information on its format. In this case the changes will
25 apply only to files that match the pathspec. Otherwise changes will be made to
26 the entire repository.
28 The output is a log of the process.
30 OPTIONS:
31 -h,--help
32 Display this help message.
34 -v,--verbose
35 Not only log errors and warnings but also substitutions.
37 -c,--create-commits
38 Create commits in the end.
40 --commit
41 Assume that the user have run the substitutions beforehand - only
42 create the commits.
43 EOF
46 create_commits(){
47 for f in $(git diff-files --name-only); do
48 if [[ ${f%%/*} == "libraries" ]]; then
49 echo $f | sed "s,\(libraries/[^/]*\)/.*,\1,"
50 else
51 echo ${f%%/*}
53 done | uniq | while read d; do
54 if [[ $d == libraries/* ]]; then
55 commit_base=${d#libraries/}
56 else
57 commit_base=$d
59 cat >/tmp/commit_msg <<EOF
60 $commit_base: standardize inclusion of libaries headers
62 This commit changes the way libraries headers are included in source files:
64 - If the header is in the same directory the source belongs to, so the
65 notation '#include ""' is used with the path relative to the directory
66 containing the source.
68 - If the header is outside the directory containing the source, then we use
69 the notation '#include <>' with the path relative to libraries folder.
71 Some of the advantages of such approach:
73 - Only one search path for libraries headers.
75 - OSs like Windows may have a better lookup time.
76 EOF
77 git add -u $d
78 git commit -F /tmp/commit_msg
79 done
82 replace_include(){
83 local file=$1
84 local n=$2
85 local new_path=$3
86 local old_path=$4
87 local regex="\(#\s*include\s*\)[<\"].\+[>\"]"
89 [[ $new_path == $old_path ]] && return
91 $arg_verbose && echo "$file:$n: $old_path --> $new_path"
92 if ! sed -i "${n}s,$regex,\1$new_path," $file; then
93 echo Error on executing command: sed -i "${n}s,$regex,\1$new_path," $file >&2
94 kill -SIGINT $$
98 fix_includes(){
99 local file=$1
100 local header=$2
101 local dirs=(${header_dirs[$header]})
102 local num_dirs=${#dirs[@]}
103 local regex="^\s*#\s*include\s*[<\"]\(.*/\)\?$header[>\"]"
105 grep -ahno $regex $file | while IFS=":" read n match; do
106 path=$(echo $match | sed "s/^\s*#\s*include\s*//g")
107 delim=${path:0:1}
108 path=${path:1:(${#path}-2)}
109 file_dir=$(realpath $(dirname $file))
111 if [[ $delim == "\"" ]]; then
112 localpath=$file_dir/$path
113 if [[ -f $localpath ]]; then
114 # verify if file is under to the file dir
115 localpath=$(realpath $localpath)
116 [[ $localpath == $file_dir* ]] && continue
118 # if not under file dir, check if $localpath is under $base
119 if [[ $localpath == $base* ]]; then
120 new_path=${localpath#$base/}
121 replace_include $file $n \<$new_path\> \"$path\"
122 continue
127 match_count=0
128 possible_paths=()
129 for dir in "${dirs[@]}"; do
130 if [[ $dir/$header == *$path ]]; then
131 ((match_count++))
132 new_path=$dir/$header
133 possible_paths[${#possible_paths[@]}]=$new_path
135 done
137 if [[ $match_count -eq 0 ]]; then
138 echo "$file:$n: couldn't find a match for inclusion of $path"
139 elif [[ $match_count -eq 1 ]]; then
140 # check if included header is under file dir
141 if [[ -f $file_dir/$path ]]; then
142 new_path=\"$(realpath $file_dir/$path --relative-to $file_dir)\"
143 else
144 new_path=\<$new_path\>
146 if [[ $delim == '"' ]]; then path=\"$path\"; else path=\<$path\>; fi
147 replace_include $file $n $new_path $path
148 else
149 echo "$file:$n: more than one match for inclusion of $path"
150 echo " possible paths:"
151 for p in "${possible_paths[@]}"; do
152 echo " $p"
153 done
155 done
158 trap_reset_tree(){
159 echo
160 echo Process killed or interrupted! Reseting tree...
161 git -C $src reset --hard
162 exit 1
165 # parse args
166 while [[ -n $1 ]]; do
167 case "$1" in
168 -h|--help)
169 usage
170 exit 0
172 -v|--verbose)
173 arg_verbose=true
175 -c|--create-commits)
176 arg_create_commits=true
178 --commit)
179 create_commits
180 exit $?
183 # remaining args are pathspecs
184 shift
185 break
188 usage >&2
189 exit 1
192 # this and the remaining args are pathspecs
193 break
194 esac
195 shift
196 done
198 trap trap_reset_tree SIGINT SIGKILL
200 if ! git -C $src diff-files --quiet --exit-code; then
201 echo You have unstaged changes, please commit or stash them beforehand >&2
202 exit 1
205 pushd $src > /dev/null
207 # collect all headers
208 git -C $base ls-files *.h > /tmp/headers
209 total=$(cat /tmp/headers | wc -l)
210 header_max_len=0
211 while read f; do
212 header=$(basename $f)
213 dir=$(dirname $f)
214 if [[ -z ${header_dirs[$header]} ]]; then
215 header_dirs[$header]=$dir
216 else
217 header_dirs[$header]+=" $dir"
219 printf "\rCollecting header files paths... $((++i))/$total" >&2
220 [[ ${#header} -gt $header_max_len ]] && header_max_len=${#header}
221 done </tmp/headers
222 echo
224 total=${#header_dirs[@]}
226 for header in "${!header_dirs[@]}"; do
227 regex="#\s*include\s*[<\"]\(.*/\)\?$header[>\"]"
228 printf "\r($((++i))/$total) Fixing includes for header %-${header_max_len}s" $header >&2
230 # for each file that includes $header
231 git grep -l $regex -- "$@" | while read f; do
232 fix_includes $f $header
233 done
234 done
236 $arg_create_commits && create_commits
238 popd > /dev/null