CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Ardupilot

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: Ardupilot/ardupilot
Path: blob/master/Tools/scripts/fix_libraries_includes.sh
Views: 1798
1
#!/usr/bin/env bash
2
3
src=$(realpath $(dirname $BASH_SOURCE)/../../)
4
base=$src/libraries
5
declare -A header_dirs
6
7
arg_verbose=false
8
arg_create_commits=false
9
10
usage(){
11
cat <<EOF
12
Usage: $(basename $BASH_SOURCE) [OPTIONS] [--] [<pathspec>...]
13
14
Fix includes of libraries headers in source files to be as the following:
15
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.
19
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.
22
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.
27
28
The output is a log of the process.
29
30
OPTIONS:
31
-h,--help
32
Display this help message.
33
34
-v,--verbose
35
Not only log errors and warnings but also substitutions.
36
37
-c,--create-commits
38
Create commits in the end.
39
40
--commit
41
Assume that the user have run the substitutions beforehand - only
42
create the commits.
43
EOF
44
}
45
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%%/*}
52
fi
53
done | uniq | while read d; do
54
if [[ $d == libraries/* ]]; then
55
commit_base=${d#libraries/}
56
else
57
commit_base=$d
58
fi
59
cat >/tmp/commit_msg <<EOF
60
$commit_base: standardize inclusion of libaries headers
61
62
This commit changes the way libraries headers are included in source files:
63
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.
67
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.
70
71
Some of the advantages of such approach:
72
73
- Only one search path for libraries headers.
74
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
80
}
81
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*\)[<\"].\+[>\"]"
88
89
[[ $new_path == $old_path ]] && return
90
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 $$
95
fi
96
}
97
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[>\"]"
104
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))
110
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
117
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
123
fi
124
fi
125
fi
126
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
134
fi
135
done
136
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\>
145
fi
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
154
fi
155
done
156
}
157
158
trap_reset_tree(){
159
echo
160
echo Process killed or interrupted! Reseting tree...
161
git -C $src reset --hard
162
exit 1
163
}
164
165
# parse args
166
while [[ -n $1 ]]; do
167
case "$1" in
168
-h|--help)
169
usage
170
exit 0
171
;;
172
-v|--verbose)
173
arg_verbose=true
174
;;
175
-c|--create-commits)
176
arg_create_commits=true
177
;;
178
--commit)
179
create_commits
180
exit $?
181
;;
182
--)
183
# remaining args are pathspecs
184
shift
185
break
186
;;
187
-*)
188
usage >&2
189
exit 1
190
;;
191
*)
192
# this and the remaining args are pathspecs
193
break
194
esac
195
shift
196
done
197
198
trap trap_reset_tree SIGINT SIGKILL
199
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
203
fi
204
205
pushd $src > /dev/null
206
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"
218
fi
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
223
224
total=${#header_dirs[@]}
225
i=0
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
229
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
235
236
$arg_create_commits && create_commits
237
238
popd > /dev/null
239
240