3 src
=$
(realpath $
(dirname $BASH_SOURCE)/..
/..
/)
8 arg_create_commits
=false
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.
32 Display this help message.
35 Not only log errors and warnings but also substitutions.
38 Create commits in the end.
41 Assume that the user have run the substitutions beforehand - only
47 for f
in $
(git diff-files
--name-only); do
48 if [[ ${f%%/*} == "libraries" ]]; then
49 echo $f |
sed "s,\(libraries/[^/]*\)/.*,\1,"
53 done |
uniq |
while read d
; do
54 if [[ $d == libraries
/* ]]; then
55 commit_base
=${d#libraries/}
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.
78 git commit
-F /tmp
/commit_msg
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
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")
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\"
129 for dir
in "${dirs[@]}"; do
130 if [[ $dir/$header == *$path ]]; then
132 new_path
=$dir/$header
133 possible_paths
[${#possible_paths[@]}]=$new_path
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)\"
144 new_path
=\
<$new_path\
>
146 if [[ $delim == '"' ]]; then path
=\"$path\"; else path
=\
<$path\
>; fi
147 replace_include
$file $n $new_path $path
149 echo "$file:$n: more than one match for inclusion of $path"
150 echo " possible paths:"
151 for p
in "${possible_paths[@]}"; do
160 echo Process killed or interrupted
! Reseting tree...
161 git
-C $src reset --hard
166 while [[ -n $1 ]]; do
176 arg_create_commits
=true
183 # remaining args are pathspecs
192 # this and the remaining args are pathspecs
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
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)
212 header
=$
(basename $f)
214 if [[ -z ${header_dirs[$header]} ]]; then
215 header_dirs
[$header]=$dir
217 header_dirs
[$header]+=" $dir"
219 printf "\rCollecting header files paths... $((++i))/$total" >&2
220 [[ ${#header} -gt $header_max_len ]] && header_max_len
=${#header}
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
236 $arg_create_commits && create_commits