xref: /illumos-gate/usr/src/tools/scripts/check-gitignore.sh (revision 14e8f286dd05c4acf54ddb51d15afc0de471037b)
1#!/bin/ksh
2#
3# This file and its contents are supplied under the terms of the
4# Common Development and Distribution License ("CDDL"), version 1.0.
5# You may only use this file in accordance with the terms of version
6# 1.0 of the CDDL.
7#
8# A full copy of the text of the CDDL should have accompanied this
9# source.  A copy of the CDDL is also available via the Internet at
10# http://www.illumos.org/license/CDDL.
11#
12
13#
14# Copyright 2025 Oxide Computer Company
15#
16
17function cd_git_root
18{
19	git_root=$(git rev-parse --show-toplevel)
20
21	if [[ ! -d $git_root ]]; then
22		echo "Must be run from within git repository"
23		exit 1
24	fi
25
26	cd $git_root
27}
28
29function check_stale
30{
31	cd_git_root
32	awk -f - <<'EOF'
33function check_ignore(repo_root, path, seen_lines, printed_header)
34{
35	fp = repo_root "/" path;
36	lnr = 0;
37	found = 0;
38	while (getline < (repo_root "/" path) > 0) {
39		lnr += 1;
40		original = $0;
41		# trim comments
42		sub(/#.*/, "");
43		# and white space
44		sub(/[ \t]+/, "");
45
46		if (length() == 0) {
47			# skip empty lines
48			continue;
49		}
50		if (/^!/) {
51			# skip excludes
52			continue;
53		}
54		if (seen_lines[lnr] == 0) {
55			if (printed_header == 0) {
56				print "Possible stale:" > "/dev/stderr"
57				printed_header = 1;
58			}
59			printf "%s:%u\t%s\n", path, lnr, original;
60			found += 1;
61		}
62	}
63	return found;
64}
65
66BEGIN {
67	cmd_ignored_files = \
68	"git ls-files -i -o -x '*' | git check-ignore -v --stdin --no-index";
69	FS=":"
70	while ((cmd_ignored_files | getline) > 0) {
71		# If --verbose is specified, the output is a series of lines of the form:
72		# <source> <COLON> <linenum> <COLON> <pattern> <HT> <pathname>
73		seen_lines[$1][$2] = 1;
74	}
75
76	nignore = 0;
77	while (("git ls-files --full-name '*.gitignore'" | getline) > 0) {
78		ignores[nignore] = $0;
79		nignore += 1;
80	}
81
82	"git rev-parse --show-toplevel" | getline repo_root
83
84	total = 0;
85	for (n in ignores) {
86		path = ignores[n];
87		total += check_ignore(repo_root, path, seen_lines[path], total);
88	}
89}
90EOF
91}
92
93function check_tracked
94{
95	cd_git_root
96	echo "git-tracked files matched by gitignore:" 1>&2
97	git ls-files | git check-ignore --no-index --stdin
98}
99
100
101USAGE='Usage: check-gitignore <check>
102
103Where <check> is one of:
104	tracked	- Are any tracked files covered by a gitignore?
105	stale	- Are there gitignore definitions which match no files?
106'
107
108case $1 in
109	tracked )
110		check_tracked
111		;;
112	stale )
113		check_stale
114		;;
115	* )
116		echo "$USAGE"
117		exit 1
118		;;
119esac
120