aboutsummaryrefslogtreecommitdiff
path: root/bin/uninclude
blob: ce8b633803cd76aa97c3ea468310e5b3f783e608 (plain) (blame)
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
#!/bin/sh
set -eu

usage() {
	cat <<-'EOF'
		Usage:
		  uninclude -E REGEXP -- COMMAND...
		  uninclude -h
	EOF
}

help() {
	cat <<-'EOF'


		Options:
		  -E REGEXP     the test expression for lines to be deleted
		  -h, --help    show this message

		  COMMAND       the build/test command used to validate the uninclusion


		Read list of files from STDIN, and for each try to delete all lines
		that match REGEXP and see if COMMAND passes.  Do this for every match
		untill all lines that could be removed are removed.


		Examples:

		  Remove all non-required "#include" lines from lib.c and main.c:

		    $ find lib.c main.c | uninclude -E '^#include ' -- cc $CFLAGS
		    lib.c: 3 lines unincluded
		    main.c: nothing to uninclude


		  Remove all non-required "imports" from all files that ends with ".py":

		    $ git ls-files | grep '\.py$' | uninclude '^import ' -- pytest
	EOF
}


for flag in "$@"; do
	case "$flag" in
		(--)
			break
			;;
		(--help)
			usage
			help
			exit
			;;
		(*)
			;;
	esac
done

while getopts 'E:h' flag; do
	case "$flag" in
		E)
			REGEXP="$OPTARG"
			;;
		(h)
			usage
			help
			exit
			;;
		(*)
			usage >&2
			exit 2
			;;
	esac
done
shift $((OPTIND - 1))

eval "$(assert-arg -- "${REGEXP:-}" '-E REGEXP')"



ORIG="$(mkstemp)"
VALID="$(mkstemp)"
MATCHES="$(mkstemp)"
LINES="$(mkstemp)"
trap 'rm -f "$ORIG" "$VALID" "$MATCHES" "$LINES"' EXIT
while read -r file; do
	cp "$file" "$ORIG"
	cp "$file" "$VALID"

	NTH=1
	while true; do
		if ! grep -nE "$REGEXP" "$file" > "$MATCHES" ||
				[ "$NTH" -ge "$(wc -l < "$MATCHES")" ]; then
			FROM="$(wc -l < "$ORIG")"
			TO="$(  wc -l < "$file")"
			if [ "$FROM" -eq "$TO" ]; then
				printf '%s: nothing to uninclude\n' "$file" >&2
			else
				printf '%s: %s lines unincluded\n' "$file" $((FROM - TO)) >&2
			fi
			break
		fi
		line="$(cut -d: -f1 "$MATCHES" | lines "$NTH")"
		sed "${line}d" "$file" | sponge "$file"
		if ! "$@" "$file"; then
			cp "$VALID" "$file"
			NTH=$((NTH + 1))
		else
			cp "$file" "$VALID"
		fi
	done
done