| #!/bin/bash | |
| # verible-verilog-format-changed-lines-interactive.sh. | |
| # Copyright 2020 The Verible Authors. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| script_name="$(basename $0)" | |
| script_dir="$(dirname $0)" | |
| # Look first for support scripts/binaries installed alongside this script. | |
| # Fall back to searching in current PATH. | |
| # This is the script that drives interactive patching. | |
| interactive_patch_script="$script_dir"/verible-transform-interactive.sh | |
| [[ -x "$interactive_patch_script" ]] || \ | |
| interactive_patch_script="$(which verible-transform-interactive.sh)" | |
| # This is Verible's patch-based utility. | |
| patch_tool="$script_dir"/verible-patch-tool | |
| [[ -x "$patch_tool" ]] || patch_tool="$(which verible-patch-tool)" | |
| # This is Verible's Verilog formatter. | |
| formatter="$script_dir"/verible-verilog-format | |
| [[ -x "$formatter" ]] || formatter="$(which verible-verilog-format)" | |
| # version control system | |
| # auto-detect by default | |
| rcs=auto | |
| baserev= | |
| files=() | |
| function usage() { | |
| cat <<EOF | |
| $0: | |
| Interactively prompts user to accept/reject formatter tool changes, | |
| based only on touched lines of code in a revision-controlled workspace. | |
| Usage: $script_name [script_options] [FILES...] | |
| Run this from a version-controlled directory. | |
| If FILES is empty, scan for all Verilog files under the current directory. | |
| script options: | |
| --help, -h : print help and exit | |
| --rcs TOOL : revision control system [default:$rcs] | |
| Supported: p4,git,hg | |
| --base REV : Revision to diff against [default: git:HEAD hg:.] | |
| See tool-specific help for version specifiers: | |
| git help revisions | |
| hg help revisions | |
| EOF | |
| } | |
| function msg() { | |
| echo "[$script_name] " "$@" | |
| } | |
| # generic option processing | |
| for opt | |
| do | |
| # handle: --option arg | |
| if test -n "$prev_opt" | |
| then | |
| eval $prev_opt=\$opt | |
| prev_opt= | |
| shift | |
| continue | |
| fi | |
| case "$opt" in | |
| *=?*) optarg=$(expr "X$opt" : '[^=]*=\(.*\)') ;; | |
| *=) optarg= ;; | |
| esac | |
| case $opt in | |
| -- ) shift ; break ;; # stop option processing | |
| --help | -h ) { usage ; exit ;} ;; | |
| --rcs ) prev_opt=rcs ;; | |
| --rcs=* ) rcs="$optarg" ;; | |
| --base ) prev_opt=baserev ;; | |
| --base=* ) baserev="$optarg" ;; | |
| --* | -* ) msg "Unknown option: $opt" ; exit 1 ;; | |
| # Positional arguments [optional] are files. | |
| *) files+=( "$opt" ) ;; | |
| esac | |
| shift | |
| done | |
| # attempt to infer version control system (p4,svn,git,cvs,hg,...) | |
| # Note: these tests are sensitive to "$PWD" | |
| if [[ "$rcs" == "auto" ]] | |
| then | |
| if git status | |
| then | |
| rcs=git | |
| elif hg root | |
| then | |
| rcs=hg | |
| else | |
| # p4 is tricky to detect due to the concept of default clients, | |
| # so leave it last position, if all else fails. | |
| rcs=p4 | |
| fi > /dev/null 2>&1 | |
| fi | |
| # Set default rev to 'dot' (parent) or HEAD. User can override | |
| # to a different revision if they want (eg p4head) | |
| case "$rcs" in | |
| git) baserev=${baserev:-HEAD} ;; | |
| hg) baserev=${baserev:-.} ;; | |
| esac | |
| function p4_touched_files() { | |
| # Result is already absolute paths to local files. | |
| p4 whatsout | |
| } | |
| function git_touched_files() { | |
| # Get added/modified files that are tracked. | |
| # See git help diff. | |
| # readlink: resolve absolute path to eliminate sensitivity to "$PWD" | |
| # Since 'git status' doesn't allow passing in a revision, use git diff instead | |
| # of status. But that gives a root-relative path, so cd to the root first | |
| (cd $(git rev-parse --show-toplevel) ; | |
| git diff --name-only --diff-filter=AM "$baserev" | xargs readlink -f | |
| ) | |
| } | |
| function hg_touched_files() { | |
| # Get added/modified files that are tracked. | |
| # See hg help status | |
| hg status --no-status -am --rev "$baserev" | xargs readlink -f | |
| } | |
| # Set commands based on version control system | |
| case "$rcs" in | |
| p4) touched_files=p4_touched_files | |
| # force use of traditional text 'diff', not some other UI-diff tool | |
| single_file_diff=(P4DIFF=diff p4 diff -d-u "{}") ;; | |
| git) touched_files=git_touched_files | |
| single_file_diff=(git diff -u --cached "$baserev" "{}") ;; | |
| hg) touched_files=hg_touched_files | |
| single_file_diff=(hg diff -g --rev "$baserev" "{}") ;; | |
| *) { msg "Unsupported version control system: $rcs" ; exit 1;} ;; | |
| esac | |
| # If files is unspecified, scan for all locally modified files. | |
| if [[ "${#files[@]}" == 0 ]] | |
| then | |
| # File extensions are currently hardcoded to Verilog files. | |
| files=($("$touched_files" | grep -e '\.sv$' -e '\.v$' -e '\.svh$' -e '\.vh$' )) | |
| fi | |
| # Note about --per-file-transform-flags: | |
| # The file name is stripped away to yield only line numbers, which is why | |
| # this still works with git-diffs, which contain a/ and b/ prefixes in | |
| # filenames. The file name used for applying changes is still the one from | |
| # "${files[@]}". | |
| interact_command=("$interactive_patch_script" \ | |
| --patch-tool "$patch_tool" \ | |
| --per-file-transform-flags='--lines=$('"${single_file_diff[*]}"' | '"$patch_tool"' changed-lines - | cut -d" " -f2)' \ | |
| -- "$formatter" \ | |
| -- "${files[@]}" ) | |
| msg "interact command: ${interact_command[@]}" | |
| exec "${interact_command[@]}" |