git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 4/4] version: introduce osversion.command config for os-version output

From
Usman Akinyemi <usmanakinyemi202@gmail.com>
Date
Jan 6, 2025, 10:30 UTC
Message-ID
<20250106103713.1452035-5-usmanakinyemi202@gmail.com>
In-Reply-To
<20250106103713.1452035-1-usmanakinyemi202@gmail.com>

Currently by default, the new `os-version` capability only exchange the operating system name between servers and clients i.e "Linux" or "Windows".

Let's introduce a new configuration option, `osversion.command`, to handle the string exchange between servers and clients. This option allows customization of the exchanged string by leveraging the output of the specified command. If this is not set, the `os-version` capability exchange just the operating system name.

Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
---
 Documentation/config/transfer.txt | 11 ++++++-
 Documentation/gitprotocol-v2.txt  | 13 ++++----
 t/t5555-http-smart-common.sh      | 29 ++++++++++++++++++
 t/t5701-git-serve.sh              | 33 ++++++++++++++++++++
 version.c                         | 51 ++++++++++++++++++++++++++++++-
 5 files changed, 129 insertions(+), 8 deletions(-)
diff --git a/Documentation/config/transfer.txt b/Documentation/config/transfer.txt
index e2d95d1ccd..28a08f21fc 100644
--- a/Documentation/config/transfer.txt
+++ b/Documentation/config/transfer.txt
@@ -131,4 +131,13 @@ transfer.advertiseOSVersion::
 	servers. It makes clients and servers send to each other a string
 	representing the operating system name, like "Linux" or "Windows".
 	This string is retrieved from the 'sysname' field of the struct returned
-	by the uname(2) system call. Defaults to true.
+	by the uname(2) system call. If the `osVersion.command` is set, the
+	output of the command specified will be the string exchanged by the clients
+	and the servers. Defaults to true.
+
+osVersion.command::
+	If this variable is set, the specified command will be run and the output
+	will be used as the value `X` for `os-version` capability (in the form
+	`os-version=X`). `osVersion.command` is only used if `transfer.advertiseOSVersion`
+	is true. Refer to the linkgit:git-config[1] documentation to learn more about
+	`transfer.advertiseOSVersion` config option.
diff --git a/Documentation/gitprotocol-v2.txt b/Documentation/gitprotocol-v2.txt
index c28262c60b..53621c0bce 100644
--- a/Documentation/gitprotocol-v2.txt
+++ b/Documentation/gitprotocol-v2.txt
@@ -203,12 +203,13 @@ in its request to the server (but it MUST NOT do so if the server did
 not advertise the os-version capability). The `X` and `Y` strings may
 contain any printable ASCII characters except space (i.e., the byte
 range 32 < x < 127), and are typically made from the result of
-`uname -s`(OS name e.g Linux). The os-version capability can be disabled
-entirely by setting the `transfer.advertiseOSVersion` config option
-to `false`. The `os-version` strings are purely informative for
-statistics and debugging purposes, and MUST NOT be used to
-programmatically assume the presence or absence of particular
-features.
+`uname -s`(OS name e.g Linux).  If the `osVersion.command` is set,
+the `X` and `Y` are made from the ouput of the command specified.
+The os-version capability can be disabled entirely by setting the
+`transfer.advertiseOSVersion` config option to `false`. The `os-version`
+strings are purely informative for statistics and debugging purposes, and
+MUST NOT be used to programmatically assume the presence or absence of
+particular features.
 
 ls-refs
 ~~~~~~~
diff --git a/t/t5555-http-smart-common.sh b/t/t5555-http-smart-common.sh
index f9e2a66cba..8d5844eaf2 100755
--- a/t/t5555-http-smart-common.sh
+++ b/t/t5555-http-smart-common.sh
@@ -152,6 +152,35 @@ test_expect_success 'git upload-pack --advertise-refs: v2' '
 	test_cmp actual expect
 '
 
+test_expect_success 'git upload-pack --advertise-refs: v2 with osVersion.command config set' '
+	# test_config is used here as we are not reusing any file output from here
+	test_config osVersion.command "uname -srvm" &&
+	printf "agent=FAKE" >agent_and_long_os_name &&
+
+	if test_have_prereq !WINDOWS
+	then
+		printf "\nos-version=%s\n" $(uname -srvm | test_redact_non_printables) >>agent_and_long_os_name
+	fi &&
+
+	cat >expect <<-EOF &&
+	version 2
+	$(cat agent_and_long_os_name)
+	ls-refs=unborn
+	fetch=shallow wait-for-done
+	server-option
+	object-format=$(test_oid algo)
+	0000
+	EOF
+
+	GIT_PROTOCOL=version=2 \
+	GIT_USER_AGENT=FAKE \
+	git upload-pack --advertise-refs . >out 2>err &&
+
+	test-tool pkt-line unpack <out >actual &&
+	test_must_be_empty err &&
+	test_cmp actual expect
+'
+
 test_expect_success 'git receive-pack --advertise-refs: v2' '
 	# There is no v2 yet for receive-pack, implicit v0
 	cat >expect <<-EOF &&
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index f4668b7acd..51d99cd62c 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -41,6 +41,39 @@ test_expect_success 'test capability advertisement' '
 	test_cmp expect actual
 '
 
+test_expect_success 'test capability advertisement with osVersion.command config set' '
+	# test_config is used here as we are not reusing any file output from here
+	test_config osVersion.command "uname -srvm" &&
+	printf "agent=git/$(git version | cut -d" " -f3)" >agent_and_long_os_name &&
+
+	if test_have_prereq !WINDOWS
+	then
+		printf "\nos-version=%s\n" $(uname -srvm | test_redact_non_printables) >>agent_and_long_os_name
+	fi &&
+
+	test_oid_cache <<-EOF &&
+	wrong_algo sha1:sha256
+	wrong_algo sha256:sha1
+	EOF
+	cat >expect.base_long <<-EOF &&
+	version 2
+	$(cat agent_and_long_os_name)
+	ls-refs=unborn
+	fetch=shallow wait-for-done
+	server-option
+	object-format=$(test_oid algo)
+	EOF
+	cat >expect.trailer_long <<-EOF &&
+	0000
+	EOF
+	cat expect.base_long expect.trailer_long >expect &&
+
+	GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
+		--advertise-capabilities >out &&
+	test-tool pkt-line unpack <out >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'stateless-rpc flag does not list capabilities' '
 	# Empty request
 	test-tool pkt-line pack >in <<-EOF &&
diff --git a/version.c b/version.c
index 8242baf41c..b446232898 100644
--- a/version.c
+++ b/version.c
@@ -1,9 +1,13 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
 #include "git-compat-util.h"
 #include "version.h"
 #include "version-def.h"
 #include "strbuf.h"
 #include "gettext.h"
 #include "config.h"
+#include "run-command.h"
+#include "alias.h"
 
 const char git_version_string[] = GIT_VERSION;
 const char git_built_from_commit_string[] = GIT_BUILT_FROM_COMMIT;
@@ -72,6 +76,50 @@ int get_uname_info(struct strbuf *buf, unsigned int full)
 	return 0;
 }
 
+/*
+ * Return -1 if unable to retrieve the osversion.command config or
+ * if the command is malformed; otherwise, return 0 if successful.
+ */
+static int fill_os_version_command(struct child_process *cmd)
+{
+	const char *os_version_command;
+	const char **argv;
+	char *os_version_copy;
+	int n;
+
+	if (git_config_get_string_tmp("osversion.command", &os_version_command))
+		return -1;
+
+	os_version_copy = xstrdup(os_version_command);
+	n = split_cmdline(os_version_copy, &argv);
+
+	if (n < 0) {
+		warning(_("malformed osVersion.command config option: %s"),
+			_(split_cmdline_strerror(n)));
+		free(os_version_copy);
+		return -1;
+	}
+
+	for (int i = 0; i < n; i++)
+		strvec_push(&cmd->args, argv[i]);
+	free(os_version_copy);
+	free(argv);
+
+	return 0;
+}
+
+static int capture_os_version(struct strbuf *buf)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	if (fill_os_version_command(&cmd))
+		return -1;
+	if (capture_command(&cmd, buf, 0))
+		return -1;
+
+	return 0;
+}
+
 const char *os_version(void)
 {
 	static const char *os = NULL;
@@ -79,7 +127,8 @@ const char *os_version(void)
 	if (!os) {
 		struct strbuf buf = STRBUF_INIT;
 
-		get_uname_info(&buf, 0);
+		if (capture_os_version(&buf))
+			get_uname_info(&buf, 0);
 		os = strbuf_detach(&buf, NULL);
 	}
 
-- 
2.47.1
Previous: Usman AkinyemiNext: Usman Akinyemi
Message 23 of 107 in “[Outreachy] Introduce os-version Capability with Configurable Options”
  1. 0/4 [Outreachy] Introduce os-version Capability with Configurable OptionsUsman Akinyemi, Jan 6, 2025
  2. 1/4 version: refactor redact_non_printables()Usman Akinyemi, Jan 6, 2025
  3. Eric SunshineJan 6, 2025
  4. Usman AkinyemiJan 8, 2025
  5. 2/4 version: refactor get_uname_info()Usman Akinyemi, Jan 6, 2025
  6. Junio C HamanoJan 6, 2025
  7. Usman AkinyemiJan 8, 2025
  8. 3/4 connect: advertise OS versionUsman Akinyemi, Jan 6, 2025
  9. Junio C HamanoJan 6, 2025
  10. Usman AkinyemiJan 8, 2025
  11. Junio C HamanoJan 8, 2025
  12. Usman AkinyemiJan 9, 2025
  13. Junio C HamanoJan 9, 2025
  14. Usman AkinyemiJan 10, 2025
  15. Junio C HamanoJan 10, 2025
  16. Usman AkinyemiJan 11, 2025
  17. Junio C HamanoJan 13, 2025
  18. Usman AkinyemiJan 13, 2025
  19. Junio C HamanoJan 13, 2025
  20. rsbecker@nexbridge.comJan 13, 2025
  21. Eric SunshineJan 6, 2025
  22. Usman AkinyemiJan 8, 2025
  23. 4/4 version: introduce osversion.command config for os-version outputUsman Akinyemi, Jan 6, 2025
  24. 0/6 [Outreachy] Introduce os-version Capability with Configurable OptionsUsman Akinyemi, Jan 17, 2025
  25. 1/6 version: refactor redact_non_printables()Usman Akinyemi, Jan 17, 2025
  26. Junio C HamanoJan 17, 2025
  27. Junio C HamanoJan 17, 2025
  28. Usman AkinyemiJan 20, 2025
  29. Christian CouderJan 21, 2025
  30. Junio C HamanoJan 21, 2025
  31. 2/6 version: refactor get_uname_info()Usman Akinyemi, Jan 17, 2025
  32. 3/6 version: extend get_uname_info() to hide system detailsUsman Akinyemi, Jan 17, 2025
  33. Junio C HamanoJan 17, 2025
  34. 4/6 t5701: add setup test to remove side-effect dependencyUsman Akinyemi, Jan 17, 2025
  35. Junio C HamanoJan 17, 2025
  36. Usman AkinyemiJan 20, 2025
  37. Junio C HamanoJan 20, 2025
  38. Usman AkinyemiJan 21, 2025
  39. 5/6 connect: advertise OS versionUsman Akinyemi, Jan 17, 2025
  40. Junio C HamanoJan 17, 2025
  41. Junio C HamanoJan 17, 2025
  42. rsbecker@nexbridge.comJan 17, 2025
  43. Junio C HamanoJan 17, 2025
  44. Usman AkinyemiJan 20, 2025
  45. Junio C HamanoJan 21, 2025
  46. 6/6 version: introduce osversion.command config for os-version outputUsman Akinyemi, Jan 17, 2025
  47. Eric SunshineJan 17, 2025
  48. Usman AkinyemiJan 20, 2025
  49. Eric SunshineJan 20, 2025
  50. Usman AkinyemiJan 20, 2025
  51. Junio C HamanoJan 17, 2025
  52. rsbecker@nexbridge.comJan 17, 2025
  53. Junio C HamanoJan 17, 2025
  54. rsbecker@nexbridge.comJan 17, 2025
  55. Usman AkinyemiJan 20, 2025
  56. Junio C HamanoJan 21, 2025
  57. rsbecker@nexbridge.comJan 21, 2025
  58. 0/6 [Outreachy] Introduce os-version Capability with Configurable OptionsUsman Akinyemi, Jan 24, 2025
  59. 1/6 version: replace manual ASCII checks with isprint() for clarityUsman Akinyemi, Jan 24, 2025
  60. Junio C HamanoJan 24, 2025
  61. 2/6 version: refactor redact_non_printables()Usman Akinyemi, Jan 24, 2025
  62. 3/6 version: refactor get_uname_info()Usman Akinyemi, Jan 24, 2025
  63. 4/6 version: extend get_uname_info() to hide system detailsUsman Akinyemi, Jan 24, 2025
  64. 5/6 t5701: add setup test to remove side-effect dependencyUsman Akinyemi, Jan 24, 2025
  65. Junio C HamanoJan 24, 2025
  66. 6/6 connect: advertise OS versionUsman Akinyemi, Jan 24, 2025
  67. 0/6 [Outreachy] extend agent capability to include OS nameUsman Akinyemi, Feb 5, 2025
  68. 1/6 version: replace manual ASCII checks with isprint() for clarityUsman Akinyemi, Feb 5, 2025
  69. 2/6 version: refactor redact_non_printables()Usman Akinyemi, Feb 5, 2025
  70. 3/6 version: refactor get_uname_info()Usman Akinyemi, Feb 5, 2025
  71. 4/6 version: extend get_uname_info() to hide system detailsUsman Akinyemi, Feb 5, 2025
  72. 6/6 agent: advertise OS name via agent capabilityUsman Akinyemi, Feb 5, 2025
  73. Junio C HamanoFeb 5, 2025
  74. Usman AkinyemiFeb 6, 2025
  75. Junio C HamanoFeb 6, 2025
  76. Usman AkinyemiFeb 7, 2025
  77. Junio C HamanoFeb 7, 2025
  78. Usman AkinyemiFeb 7, 2025
  79. 5/6 t5701: add setup test to remove side-effect dependencyUsman Akinyemi, Feb 5, 2025
  80. 0/6 [Outreachy] extend agent capability to include OS nameUsman Akinyemi, Feb 14, 2025
  81. 1/6 version: replace manual ASCII checks with isprint() for clarityUsman Akinyemi, Feb 14, 2025
  82. 2/6 version: refactor redact_non_printables()Usman Akinyemi, Feb 14, 2025
  83. 3/6 version: refactor get_uname_info()Usman Akinyemi, Feb 14, 2025
  84. 4/6 version: extend get_uname_info() to hide system detailsUsman Akinyemi, Feb 14, 2025
  85. 5/6 t5701: add setup test to remove side-effect dependencyUsman Akinyemi, Feb 14, 2025
  86. Junio C HamanoFeb 14, 2025
  87. 6/6 agent: advertise OS name via agent capabilityUsman Akinyemi, Feb 14, 2025
  88. Junio C HamanoFeb 14, 2025
  89. Usman AkinyemiFeb 15, 2025
  90. 0/6 [Outreachy] extend agent capability to include OS nameUsman Akinyemi, Feb 15, 2025
  91. 1/6 version: replace manual ASCII checks with isprint() for clarityUsman Akinyemi, Feb 15, 2025
  92. 2/6 version: refactor redact_non_printables()Usman Akinyemi, Feb 15, 2025
  93. 3/6 version: refactor get_uname_info()Usman Akinyemi, Feb 15, 2025
  94. 4/6 version: extend get_uname_info() to hide system detailsUsman Akinyemi, Feb 15, 2025
  95. 5/6 t5701: add setup test to remove side-effect dependencyUsman Akinyemi, Feb 15, 2025
  96. 6/6 agent: advertise OS name via agent capabilityUsman Akinyemi, Feb 15, 2025
  97. Junio C HamanoFeb 18, 2025
  98. Junio C HamanoFeb 18, 2025
  99. Junio C HamanoJan 24, 2025
  100. Christian CouderJan 27, 2025
  101. Junio C HamanoJan 27, 2025
  102. Christian CouderJan 31, 2025
  103. Junio C HamanoJan 31, 2025
  104. Usman AkinyemiJan 31, 2025
  105. Junio C HamanoJan 31, 2025
  106. Usman AkinyemiJan 31, 2025
  107. Junio C HamanoJan 31, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.