Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/Tools/scripts/fix_libraries_includes.sh
Views: 1798
#!/usr/bin/env bash12src=$(realpath $(dirname $BASH_SOURCE)/../../)3base=$src/libraries4declare -A header_dirs56arg_verbose=false7arg_create_commits=false89usage(){10cat <<EOF11Usage: $(basename $BASH_SOURCE) [OPTIONS] [--] [<pathspec>...]1213Fix includes of libraries headers in source files to be as the following:1415- If the header is in the same directory the source belongs to, then the16notation #include "" is used with the path relative to the directory17containing the source.1819- If the header is outside the directory containing the source, then we use20the notation #include <> with the path relative to libraries folder.2122If pathspec is given then it's an argument passed directly to git-grep. See23git-grep(1) for more information on its format. In this case the changes will24apply only to files that match the pathspec. Otherwise changes will be made to25the entire repository.2627The output is a log of the process.2829OPTIONS:30-h,--help31Display this help message.3233-v,--verbose34Not only log errors and warnings but also substitutions.3536-c,--create-commits37Create commits in the end.3839--commit40Assume that the user have run the substitutions beforehand - only41create the commits.42EOF43}4445create_commits(){46for f in $(git diff-files --name-only); do47if [[ ${f%%/*} == "libraries" ]]; then48echo $f | sed "s,\(libraries/[^/]*\)/.*,\1,"49else50echo ${f%%/*}51fi52done | uniq | while read d; do53if [[ $d == libraries/* ]]; then54commit_base=${d#libraries/}55else56commit_base=$d57fi58cat >/tmp/commit_msg <<EOF59$commit_base: standardize inclusion of libaries headers6061This commit changes the way libraries headers are included in source files:6263- If the header is in the same directory the source belongs to, so the64notation '#include ""' is used with the path relative to the directory65containing the source.6667- If the header is outside the directory containing the source, then we use68the notation '#include <>' with the path relative to libraries folder.6970Some of the advantages of such approach:7172- Only one search path for libraries headers.7374- OSs like Windows may have a better lookup time.75EOF76git add -u $d77git commit -F /tmp/commit_msg78done79}8081replace_include(){82local file=$183local n=$284local new_path=$385local old_path=$486local regex="\(#\s*include\s*\)[<\"].\+[>\"]"8788[[ $new_path == $old_path ]] && return8990$arg_verbose && echo "$file:$n: $old_path --> $new_path"91if ! sed -i "${n}s,$regex,\1$new_path," $file; then92echo Error on executing command: sed -i "${n}s,$regex,\1$new_path," $file >&293kill -SIGINT $$94fi95}9697fix_includes(){98local file=$199local header=$2100local dirs=(${header_dirs[$header]})101local num_dirs=${#dirs[@]}102local regex="^\s*#\s*include\s*[<\"]\(.*/\)\?$header[>\"]"103104grep -ahno $regex $file | while IFS=":" read n match; do105path=$(echo $match | sed "s/^\s*#\s*include\s*//g")106delim=${path:0:1}107path=${path:1:(${#path}-2)}108file_dir=$(realpath $(dirname $file))109110if [[ $delim == "\"" ]]; then111localpath=$file_dir/$path112if [[ -f $localpath ]]; then113# verify if file is under to the file dir114localpath=$(realpath $localpath)115[[ $localpath == $file_dir* ]] && continue116117# if not under file dir, check if $localpath is under $base118if [[ $localpath == $base* ]]; then119new_path=${localpath#$base/}120replace_include $file $n \<$new_path\> \"$path\"121continue122fi123fi124fi125126match_count=0127possible_paths=()128for dir in "${dirs[@]}"; do129if [[ $dir/$header == *$path ]]; then130((match_count++))131new_path=$dir/$header132possible_paths[${#possible_paths[@]}]=$new_path133fi134done135136if [[ $match_count -eq 0 ]]; then137echo "$file:$n: couldn't find a match for inclusion of $path"138elif [[ $match_count -eq 1 ]]; then139# check if included header is under file dir140if [[ -f $file_dir/$path ]]; then141new_path=\"$(realpath $file_dir/$path --relative-to $file_dir)\"142else143new_path=\<$new_path\>144fi145if [[ $delim == '"' ]]; then path=\"$path\"; else path=\<$path\>; fi146replace_include $file $n $new_path $path147else148echo "$file:$n: more than one match for inclusion of $path"149echo " possible paths:"150for p in "${possible_paths[@]}"; do151echo " $p"152done153fi154done155}156157trap_reset_tree(){158echo159echo Process killed or interrupted! Reseting tree...160git -C $src reset --hard161exit 1162}163164# parse args165while [[ -n $1 ]]; do166case "$1" in167-h|--help)168usage169exit 0170;;171-v|--verbose)172arg_verbose=true173;;174-c|--create-commits)175arg_create_commits=true176;;177--commit)178create_commits179exit $?180;;181--)182# remaining args are pathspecs183shift184break185;;186-*)187usage >&2188exit 1189;;190*)191# this and the remaining args are pathspecs192break193esac194shift195done196197trap trap_reset_tree SIGINT SIGKILL198199if ! git -C $src diff-files --quiet --exit-code; then200echo You have unstaged changes, please commit or stash them beforehand >&2201exit 1202fi203204pushd $src > /dev/null205206# collect all headers207git -C $base ls-files *.h > /tmp/headers208total=$(cat /tmp/headers | wc -l)209header_max_len=0210while read f; do211header=$(basename $f)212dir=$(dirname $f)213if [[ -z ${header_dirs[$header]} ]]; then214header_dirs[$header]=$dir215else216header_dirs[$header]+=" $dir"217fi218printf "\rCollecting header files paths... $((++i))/$total" >&2219[[ ${#header} -gt $header_max_len ]] && header_max_len=${#header}220done </tmp/headers221echo222223total=${#header_dirs[@]}224i=0225for header in "${!header_dirs[@]}"; do226regex="#\s*include\s*[<\"]\(.*/\)\?$header[>\"]"227printf "\r($((++i))/$total) Fixing includes for header %-${header_max_len}s" $header >&2228229# for each file that includes $header230git grep -l $regex -- "$@" | while read f; do231fix_includes $f $header232done233done234235$arg_create_commits && create_commits236237popd > /dev/null238239240