summaryrefslogtreecommitdiff
path: root/scripts/setlocalversion
blob: 38b96c6797f4080ee07fc40e074638994d5ba3d0 (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
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/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>.
#
#

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

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/')

	# 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.
	tag=${file_localversion#-}
	desc=
	if [ -n "${tag}" ]; then
		desc=$(git describe --match=$tag 2>/dev/null)
	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 "${desc}" ] && [ -n "${file_localversion}" ]; then
		tag="${version_tag}${file_localversion}"
		desc=$(git describe --match=$tag 2>/dev/null)
	fi

	# Otherwise, default to the annotated tag derived from KERNELVERSION.
	if [ -z "${desc}" ]; then
		tag="${version_tag}"
		desc=$(git describe --match=$tag 2>/dev/null)
	fi

	# If we are at the tagged commit, we ignore it because the version is
	# well-defined.
	if [ "${tag}" != "${desc}" ]; 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 "${desc}" ]; then
			echo "${desc}" | awk -F- '{printf("-%05d", $(NF-1))}'
		fi

		# Add -g and exactly 12 hex chars.
		printf '%s%s' -g "$(echo $head | cut -c1-12)"
	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}"