Subject: [PATCH] Allow to store and read repository information of VCS builds
From: Björn Bidar <[email-masked]>
To: [email-masked]
Date: Mon, 18 Nov 2024 10:18:11 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch

Emacs has the feature to read the repository version and
branch if git is installed during the build and afterwards if also
the sources including the VCS repository is present.

For the Android builds the feature was added to store and read the
information mentioned above in a special version file.

This patch reuses that mechanism so it can be reused on other platforms
to use for the same reasons its available for Android and to also be
able to use the information on CI workers without git installed and/or a
full source checkout.

The things I'm not sure about for this patch are:
- Is the generating of the version file in the right place in
Makefile.in
- Is the data directory the right place to store the file
- Should the creation of the version file be shared between the Android
  builds and the other platforms

In GNU Emacs 31.0.50 (build 1, x86_64-suse-linux-gnu, GTK+ Version
3.24.43, cairo version 1.18.2)
Repository revision: eee0ed8442aa78320a3e578ab290df145fb49624
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101014
System Description: openSUSE Tumbleweed

Configured using:
 'configure --disable-build-details --without-pop --with-mailutils
 --without-hesiod --with-gameuser=:games --with-kerberos
 --with-kerberos5 --with-file-notification=inotify --with-modules
 --enable-autodepend --enable-link-time-optimization --prefix=/usr
 --mandir=/usr/share/man --infodir=/usr/share/info --datadir=/usr/share
 --localstatedir=/var --sharedstatedir=/var/lib
 --libexecdir=/usr/libexec --with-file-notification=yes
 --libdir=/usr/lib64 --with-native-compilation=aot
 --enable-locallisppath=/usr/share/emacs/31.0.50/site-lisp:/usr/share/emacs/site-lisp
 --with-x --with-xim --with-sound --with-xpm --with-jpeg --with-tiff
 --with-gif --with-png --with-rsvg --with-dbus --with-xft --without-gpm
 --with-tree-sitter --with-x-toolkit=gtk --without-pgtk
 --with-toolkit-scroll-bars --x-includes=/usr/include
 --x-libraries=/usr/lib64 --with-libotf --with-m17n-flt --with-cairo
 --build=x86_64-suse-linux --with-dumping=pdumper
 build_alias=x86_64-suse-linux 'CC=sccache cc' 'CFLAGS=-O2 -Wall
 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -fstack-protector-strong
 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection
 -Werror=return-type -flto=auto -march=znver3 -mmmx -mpopcnt -msse
 -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -mavx -mavx2 -msse4a -mno-fma4
 -mno-xop -mfma -mbmi -mbmi2 -maes -mpclmul -mno-gfni -mvpclmulqdq
 -mno-3dnow -madx -mabm -mno-cldemote -mclflushopt -mclwb -mclzero
 -mcx16 -mno-enqcmd -mf16c -mfsgsbase -mfxsr -mno-hle -msahf -mno-lwp
 -mlzcnt -mmovbe -mno-movdir64b -mno-movdiri -mmwaitx -mno-pconfig -mpku
 -mprfchw -mno-ptwrite -mrdpid -mrdrnd -mrdseed -mno-rtm -mno-serialize
 -mno-sgx -msha -mshstk -mno-tbm -mno-tsxldtrk -mvaes -mno-waitpkg
 -mwbnoinvd -mxsave -mxsavec -mxsaveopt -mxsaves -mno-amx-tile
 -mno-amx-int8 -mno-amx-bf16 -mno-uintr -mno-hreset -mno-kl -mno-widekl
 -mno-avxvnni -mno-avxifma -mno-avxvnniint8 -mno-avxneconvert
 -mno-cmpccxadd -mno-amx-fp16 -mno-prefetchi -mno-raoint
 -mno-amx-complex --param l1-cache-size=32 --param l1-cache-line-size=64
 --param l2-cache-size=512 -mtune=znver3 -fno-optimize-sibling-calls -O2
 -Wall -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -fstack-protector-strong
 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection
 -Werror=return-type -flto=auto -g -D_GNU_SOURCE
 -DGDK_DISABLE_DEPRECATION_WARNINGS -DGLIB_DISABLE_DEPRECATION_WARNINGS
 -pipe -Wno-pointer-sign -Wno-unused-variable -Wno-unused-label
 -DPDMP_BASE='\''"emacs-gtk"'\''' LDFLAGS=-Wl,-O2 'CXX=sccache c++'
 PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig'

From c5332d1a4a65ad6b124d0919d275c0ddde045842 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Bidar?= <[email-masked]>
Date: Sun, 17 Nov 2024 13:37:21 +0200
Subject: [PATCH] Allow to store and read repository information of VCS builds

Store repository information in version file if Emacs is build from
source while VCS is present. The version file can also be stored in the Emacs
sources prior built to indicate if Emacs was built from VCS sources.

An example use case could be if Emacs runs on a system where
the version control system isn't available, e.g. similarly
as it is intended for Android builds.
Another one is to be able to set the VCS information for workers
in a CI environment where sources are generated separately from VCS
but it or the VCS repository isn't present on the worker.

Reuse the same mechanism that exist for Android builds if the version
file is present.

* Makefile.in (etc-emacsver):
Generate etc/version file with revision and branch if git is installed
and Emacs sources are VCS sources.

* lisp/version.el (emacs-repository-get-branch)
(emacs-repository-get-version, emacs-repository-branch-static)
(emacs-repository-version-static):
Implement static versions that can use the information generated during
build if present.
---
 .gitignore      |  1 +
 Makefile.in     | 20 ++++++++++++++++----
 lisp/version.el | 44 ++++++++++++++++++++++++++++++++------------
 3 files changed, 49 insertions(+), 16 deletions(-)

diff --git a/.gitignore b/.gitignore
index c1f31514d06..d3b737d590c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -314,6 +314,7 @@ doc/misc/modus-themes.texi
 doc/misc/org.texi
 etc/DOC
 etc/refcards/emacsver.tex
+etc/version
 gnustmp*
 /info/
 
diff --git a/Makefile.in b/Makefile.in
index 30a762ed03b..202b0417282 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -452,7 +452,18 @@ etc-emacsver:
 	sed "s/[@]majorversion@/$${majorversion}/" \
 	  ${srcdir}/etc/refcards/emacsver.tex.in > emacsver.tex.$$$$ && \
 	  ${srcdir}/build-aux/move-if-change emacsver.tex.$$$$ \
-	  ${srcdir}/etc/refcards/emacsver.tex
+	  ${srcdir}/etc/refcards/emacsver.tex; \
+	  if [ -e $(srcdir)/.git ]  && \
+	  which git > /dev/null ; then \
+	  { (cd $(srcdir) \
+	     && git rev-parse HEAD || echo "Unknown") \
+	     && (git rev-parse --abbrev-ref HEAD \
+	         || echo "Unknown") } 2> /dev/null > \
+	     ${top_builddir}/etc/version.$$$$; \
+	     ${srcdir}/build-aux/move-if-change \
+		${top_builddir}/etc/version.$$$$ \
+		${top_builddir}/etc/version; \
+          else : ;fi
 
 # The shared gamedir name as a C string literal, or a null ptr if not in use.
 PATH_GAME = $(if $(use_gamedir),"$(gamedir)",((char const *) 0))
@@ -627,7 +638,7 @@ install-arch-dep:
 	umask 022; ${MKDIR_P} "$(DESTDIR)${bindir}"
 	$(MAKE) -C lib-src install
 ifeq (${ns_self_contained},no)
-	${INSTALL_PROGRAM} $(INSTALL_STRIP) src/emacs${EXEEXT} "$(DESTDIR)${bindir}/$(EMACSFULL)"
+	${INSTALL_PROGRAM} $(INSTALL_STRIP) src/emacs${EXEEXT} "$(DESTDIR)${bindir}/$(EMACS)"
 ifeq (${HAVE_BE_APP},yes)
 	${INSTALL_PROGRAM} $(INSTALL_STRIP) src/Emacs "$(DESTDIR)${prefix}/apps/Emacs"
 endif
@@ -637,7 +648,7 @@ install-arch-dep:
 endif
 	${INSTALL_DATA} src/emacs.pdmp "$(DESTDIR)${libexecdir}/emacs/${version}/${configuration}"/emacs-${EMACS_PDMP}
 endif
-	-chmod 755 "$(DESTDIR)${bindir}/$(EMACSFULL)"
+	-chmod 755 "$(DESTDIR)${bindir}/$(EMACS)"
 ifndef NO_BIN_LINK
 	rm -f "$(DESTDIR)${bindir}/$(EMACS)"
 	cd "$(DESTDIR)${bindir}" && $(LN_S_FILEONLY) "$(EMACSFULL)" "$(EMACS)"
@@ -826,6 +837,7 @@ install-man:
 	umask 022; ${MKDIR_P} "$(DESTDIR)${man1dir}"
 	thisdir=`pwd -P`; \
 	cd ${mansrcdir}; \
+	cp ctags.1 gnuctags.1; \
 	for page in *.1; do \
 	  test "$$page" = ChangeLog.1 && continue; \
 	  dest=`echo "$${page}" | sed -e 's/\.1$$//' -e '$(TRANSFORM)'`.1; \
@@ -969,7 +981,7 @@ uninstall:
 	   for page in *.1; do \
 	     rm -f "$(DESTDIR)${man1dir}"/`echo "$${page}" | sed -e 's/\.1$$//' -e '$(TRANSFORM)'`.1$$ext; done; \
 	 fi)
-	rm -f "$(DESTDIR)${bindir}/$(EMACS)" "$(DESTDIR)${bindir}/$(EMACSFULL)"
+	rm -f "$(DESTDIR)${bindir}/$(EMACS)"
 	(if cd "$(DESTDIR)${icondir}"; then \
 	   rm -f hicolor/*x*/apps/"${EMACS_NAME}.png" \
 	     "hicolor/scalable/apps/${EMACS_NAME}.svg" \
diff --git a/lisp/version.el b/lisp/version.el
index db2afd55694..3b2c91c03dc 100644
--- a/lisp/version.el
+++ b/lisp/version.el
@@ -171,15 +171,21 @@ emacs-repository-version-git
 		  (looking-at "[[:xdigit:]]\\{40\\}"))
 	   (match-string 0)))))
 
-(defun emacs-repository-version-android ()
+(defun emacs-repository-version-static (dir)
   "Return the Emacs repository revision Emacs was built from.
 Value is nil if Emacs was not built from a repository checkout.
-Use information from the `/assets/version' special file."
+Use information from the `DIR/version' special file."
   (with-temp-buffer
-    (insert-file-contents "/assets/version")
+    (insert-file-contents (expand-file-name "version" dir))
     (let ((string (buffer-substring 1 (line-end-position))))
       (and (not (equal string "Unknown")) string))))
 
+(defun emacs-repository-version-android ()
+  "Return the Emacs repository revision Emacs was built from.
+Value is nil if Emacs was not built from a repository checkout.
+Use information from the `/assets/version' special file."
+  (emacs-repository-version-static "/assets"))
+
 (defun emacs-repository-get-version (&optional dir _external)
   "Try to return as a string the repository revision of the Emacs sources.
 The format of the returned string is dependent on the VCS in use.
@@ -194,9 +200,13 @@ emacs-repository-get-version
 
 Optional argument DIR is a directory to use instead of `source-directory'.
 Optional argument EXTERNAL is ignored."
-  (cond ((and (featurep 'android)
-              (eq system-type 'android))
-         (emacs-repository-version-android))
+  (cond ((and (or (and (featurep 'android)
+                       (eq system-type 'android)
+                       (setq dir "/assets"))
+                  (and (not dir)
+                       (file-exists-p (expand-file-name  "version" data-directory))
+                       (setq dir data-directory)))
+              (emacs-repository-version-static dir)))
         (t (emacs-repository-version-git
             (or dir source-directory)))))
 
@@ -209,8 +219,14 @@ emacs-repository-branch-android
   "Return the Emacs repository branch Emacs was built from.
 Value is nil if Emacs was not built from a repository checkout.
 Use information from the `/assets/version' special file."
+  (emacs-repository-branch-static "/assets"))
+
+(defun emacs-repository-branch-static (dir)
+  "Return the Emacs repository branch Emacs was built from.
+Value is nil if Emacs was not built from a repository checkout.
+Use information from the `DIR/version' special file."
   (with-temp-buffer
-    (insert-file-contents "/assets/version")
+    (insert-file-contents (expand-file-name "version" dir))
     (end-of-line)
     (forward-char)
     (let ((string (buffer-substring (point) (line-end-position))))
@@ -232,8 +248,8 @@ emacs-repository-get-branch
   "Try to return as a string the repository branch of the Emacs sources.
 The format of the returned string is dependent on the VCS in use.
 
-If Emacs is built for Android, use the version information
-embedded in the Emacs installation package.
+If Emacs is built for Android or contains version file,
+use the version information embedded in the Emacs installation package.
 
 Value is nil if the sources do not seem to be under version
 control, or if we could not determine the branch.  Note that
@@ -241,9 +257,13 @@ emacs-repository-get-branch
 correspond to the running Emacs.
 
 Optional argument DIR is a directory to use instead of `source-directory'."
-  (cond ((and (featurep 'android)
-              (eq system-type 'android))
-         (emacs-repository-branch-android))
+  (cond ((and (or (and (featurep 'android)
+                       (eq system-type 'android)
+                       (setq dir "/assets"))
+                  (and (not dir)
+                       (file-exists-p (expand-file-name  "version" data-directory))
+                       (setq dir data-directory)))
+              (emacs-repository-branch-static dir)))
         (t (emacs-repository-branch-git
             (or dir source-directory)))))
 
-- 
2.45.2