summaryrefslogtreecommitdiff
path: root/scripts/setlocalversion
blob: 28169d7e143b6999d93a0471f5d20927a53522fb (plain)
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# This scripts adds local version information from the version
# control system git.
#
# If something goes wrong, send a mail the kernel build mailinglist
# (see MAINTAINERS) and CC Nico Schottelius
# <nico-linuxsetlocalversion -at- schottelius.org>.
#
#

set -e

usage() {
	echo "Usage: $0 [--no-local] [srctree]" >&2
	exit 1
}

no_local=false
if test "$1" = "--no-local"; then
	no_local=true
	shift
fi

srctree=.
if test $# -gt 0; then
	srctree=$1
	shift
fi
if test $# -gt 0 -o ! -d "$srctree"; then
	usage
fi

try_tag() {
	tag="$1"

	# Is $tag an annotated tag?
	if [ "$(git cat-file -t "$tag" 2> /dev/null)" != tag ]; then
		 return
	fi

	# Is it an ancestor of HEAD, and if so, how many commits are in $tag..HEAD?
	# shellcheck disable=SC2046 # word splitting is the point here
	set -- $(git rev-list --count --left-right "$tag"...HEAD 2> /dev/null)

	# $1 is 0 if and only if $tag is an ancestor of HEAD. Use
	# string comparison, because $1 is empty if the 'git rev-list'
	# command somehow failed.
	if [ "$1" != 0 ]; then
		return
	fi

	# $2 is the number of commits in the range $tag..HEAD, possibly 0.
	count="$2"
}

scm_version()
{
	local short=false
	local no_dirty=false
	local tag

	while [ $# -gt 0 ];
	do
		case "$1" in
		--short)
			short=true;;
		--no-dirty)
			no_dirty=true;;
		esac
		shift
	done

	cd "$srctree"

	if test -n "$(git rev-parse --show-cdup 2>/dev/null)"; then
		return
	fi

	if ! head=$(git rev-parse --verify HEAD 2>/dev/null); then
		return
	fi

	# mainline kernel:  6.2.0-rc5  ->  v6.2-rc5
	# stable kernel:    6.1.7      ->  v6.1.7
	version_tag=v$(echo "${KERNELVERSION}" | sed -E 's/^([0-9]+\.[0-9]+)\.0(.*)$/\1\2/')

	# try_tag initializes count if the tag is usable.
	count=

	# If a localversion* file exists, and the corresponding
	# annotated tag exists and is an ancestor of HEAD, use
	# it. This is the case in linux-next.
	if [ -n "${file_localversion#-}" ] ; then
		try_tag "${file_localversion#-}"
	fi

	# Otherwise, if a localversion* file exists, and the tag
	# obtained by appending it to the tag derived from
	# KERNELVERSION exists and is an ancestor of HEAD, use
	# it. This is e.g. the case in linux-rt.
	if [ -z "${count}" ] && [ -n "${file_localversion}" ]; then
		try_tag "${version_tag}${file_localversion}"
	fi

	# Otherwise, default to the annotated tag derived from KERNELVERSION.
	if [ -z "${count}" ]; then
		try_tag "${version_tag}"
	fi

	# If we are at the tagged commit, we ignore it because the
	# version is well-defined. If none of the attempted tags exist
	# or were usable, $count is still empty.
	if [ -z "${count}" ] || [ "${count}" -gt 0 ]; then

		# If only the short version is requested, don't bother
		# running further git commands
		if $short; then
			echo "+"
			return
		fi

		# If we are past the tagged commit, we pretty print it.
		# (like 6.1.0-14595-g292a089d78d3)
		if [ -n "${count}" ]; then
			printf "%s%05d" "-" "${count}"
		fi

		# Add -g and exactly 12 hex chars.
		printf '%s%.12s' -g "$head"
	fi

	if ${no_dirty}; then
		return
	fi

	# Check for uncommitted changes.
	# This script must avoid any write attempt to the source tree, which
	# might be read-only.
	# You cannot use 'git describe --dirty' because it tries to create
	# .git/index.lock .
	# First, with git-status, but --no-optional-locks is only supported in
	# git >= 2.14, so fall back to git-diff-index if it fails. Note that
	# git-diff-index does not refresh the index, so it may give misleading
	# results.
	# See git-update-index(1), git-diff-index(1), and git-status(1).
	if {
		git --no-optional-locks status -uno --porcelain 2>/dev/null ||
		git diff-index --name-only HEAD
	} | read dummy; then
		printf '%s' -dirty
	fi
}

collect_files()
{
	local file res=

	for file; do
		case "$file" in
		*\~*)
			continue
			;;
		esac
		if test -e "$file"; then
			res="$res$(cat "$file")"
		fi
	done
	echo "$res"
}

if [ -z "${KERNELVERSION}" ]; then
	echo "KERNELVERSION is not set" >&2
	exit 1
fi

# localversion* files in the build and source directory
file_localversion="$(collect_files localversion*)"
if test ! "$srctree" -ef .; then
	file_localversion="${file_localversion}$(collect_files "$srctree"/localversion*)"
fi

if ${no_local}; then
	echo "${KERNELVERSION}$(scm_version --no-dirty)"
	exit 0
fi

if ! test -e include/config/auto.conf; then
	echo "Error: kernelrelease not valid - run 'make prepare' to update it" >&2
	exit 1
fi

# version string from CONFIG_LOCALVERSION
config_localversion=$(sed -n 's/^CONFIG_LOCALVERSION=\(.*\)$/\1/p' include/config/auto.conf)

# scm version string if not at the kernel version tag or at the file_localversion
if grep -q "^CONFIG_LOCALVERSION_AUTO=y$" include/config/auto.conf; then
	# full scm version string
	scm_version="$(scm_version)"
elif [ "${LOCALVERSION+set}" != "set" ]; then
	# If the variable LOCALVERSION is not set, append a plus
	# sign if the repository is not in a clean annotated or
	# signed tagged state (as git describe only looks at signed
	# or annotated tags - git tag -a/-s).
	#
	# If the variable LOCALVERSION is set (including being set
	# to an empty string), we don't want to append a plus sign.
	scm_version="$(scm_version --short)"
fi

echo "${KERNELVERSION}${file_localversion}${config_localversion}${LOCALVERSION}${scm_version}"