File: checkstyle.sh

package info (click to toggle)
lcov 2.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,412 kB
  • sloc: perl: 27,615; xml: 6,982; sh: 6,977; python: 1,147; makefile: 593; cpp: 455; ansic: 167
file content (186 lines) | stat: -rwxr-xr-x 4,317 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/bin/bash
#
# checkstyle.sh FILENAME(S)
#
# Check specified files for coding style issues. The mode of checking is
# selected using the MODE environment variable:
#
# MODE:
#   diff    Report only issues on code changed since git HEAD (default)
#   full    Report all issues
#
# Note: Currently checking is restricted to Perl files

# Return absolute path
function realpath() {
	local path="$1"

	if [[ -d "$path" ]] ; then
		echo "$(cd "$path" && pwd)"
	else
		echo "$(cd "$(dirname "$path")" && pwd)/$(basename "$1")"
	fi
}

# Return path relative to TOOLDIR
function relpath() {
	local inpath="$1" outpath

	outpath="${1##$TOOLDIR/}"

	echo "$outpath"

	# Let caller know if path was inside TOOLDIR
	[[ "$inpath" != "$outpath" ]]
}

# Terminate with an error message
function die() {
	echo "Error: $*" >&2
	exit 1
}

# List source lines that violate the style guide rules. If an original file
# is supplied, only report new findings.
function report() {
	local file="$1" tidy="$2" origfile="${3:-}" origtidy="${4:-}"
	local diffopts mark origmark newmark lineno continuation newline
	local tag line

	# Mark offending lines. An offending line is a line in the original
	# file that was removed and replaced with a fixed line by the tidy
	# script.
	diffopts=(
		'--old-line-format'		'-%L'	# Mark changed lines
		'--new-line-format'		''	# Remove fixed lines
		'--unchanged-line-format'	' %L'	# Leave other lines
		'--minimal'
	)

	mark="$TEMPDIR/${file##*/}.marked"
	diff "${diffopts[@]}" "$file" "$tidy" >"$mark"

	origmark="$TEMPDIR/${file##*/}.origmarked"
	if [[ -n "$origfile" ]] ; then
		# Use original version as baseline
		diff "${diffopts[@]}" "$origfile" "$origtidy" >"$origmark"
	else
		# Use full file as baseline
		sed -e 's/^/ /g' "$file" >"$origmark"
	fi

	# Mark lines that are added compared to baseline
	diffopts=(
		'--old-line-format'		''	# Remove old lines
		'--new-line-format'		'+%L'	# Mark changed lines
		'--unchanged-line-format'	' %L'	# Leave other lines
		'--minimal'
	)

	newmark="$TEMPDIR/${file##*/}.newmarked"
	diff "${diffopts[@]}" "$origmark" "$mark" >"$newmark"

	if ! grep -q '^+-' "$newmark" ; then
		echo "$file has no obvious style issues"
		return 0
	fi

	if [[ -z "$origfile" ]] ; then
		echo "Listing all findings in $file:"
	else
		echo "Listing findings in $file since git ref $GITBASE:"
	fi
	echo

	# Display groups of newly introduced offending lines
	lineno=1
	continuation=0
	newline=0
	while read -r line ; do
		tag=${line:0:2}
		line=${line:2}
		if [[ "$tag" == "+-" ]] ; then
			# + means: introduced after baseline
			# - means: an offending line
			if [[ "$continuation" -eq 0 ]] ; then
				if [[ "$newline" -eq 1 ]] ; then
					echo
					newline=0
				fi
				echo "In $file line $lineno:"
				continuation=1
			fi
			echo "+${line//$'\t'/^I}"
		else
			if [[ "$continuation" -eq 1 ]] ; then
				newline=1
				continuation=0
			fi
		fi
		(( lineno++ ))
	done < "$newmark"

	echo
	echo "$file has style issues, please review (see also $tidy)." >&2

	return 1
}

TOOLDIR="$(realpath "$(dirname "$0")"/..)"

PERLTIDY="${PERLTIDY:-perltidy}"
PERLTIDYRC="${PERLTIDYRC:-$TOOLDIR/.perltidyrc}"

# HEAD is default baseline
GITBASE=${GITBASE:-HEAD}

# diff is default mode
MODE=${MODE:-diff}
#MODE=${MODE@L}

case "$MODE" in
"diff")	[[ ! -d "$TOOLDIR/.git" ]] && die "Not in a git repository" ;;
"full")	;;
*)	die "Unknown checking mode '$MODE'" ;;
esac

TEMPDIR=$(mktemp -d) || die "Could not create temporary directory"
trap "rm -rf '$TEMPDIR'" exit

RC=0
for FILE in "${@}" ; do
	BASE=${FILE##*/}
	TIDY="$FILE.tdy"

	if [[ "$MODE" == "diff" ]] ; then
		GITFILE="$TEMPDIR/$BASE.git"
		GITTIDY="$TEMPDIR/$BASE.git.tdy"

		RELFILE="$(relpath "$(realpath "$FILE")")" ||
			die "$FILE is outside of git repository"

		git show "$GITBASE:$RELFILE" >"$GITFILE" ||
			die "No version of $FILE found in git ref $GITBASE"

		"$PERLTIDY" --profile="$PERLTIDYRC" "$GITFILE" -o "$GITTIDY" ||
			die "Could not check git version of $FILE"

		"$PERLTIDY" --profile="$PERLTIDYRC" "$FILE" -o "$TIDY" ||
			die "Could not check $FILE"

		report "$FILE" "$TIDY" "$GITFILE" "$GITTIDY"
	else
		"$PERLTIDY" --profile="$PERLTIDYRC" "$FILE" -o "$TIDY" ||
			die "Could not check $FILE"

		report "$FILE" "$TIDY"
	fi

	if [[ $? -ne 0 ]] ; then
		RC=1
	else
		rm -f "$TIDY"
	fi
done

exit $RC