Skip to content

Commit

Permalink
version: introduce osversion.command config for os-version output
Browse files Browse the repository at this point in the history
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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Unique-Usman authored and gitster committed Jan 6, 2025
1 parent c3231ae commit cbb94dc
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 8 deletions.
11 changes: 10 additions & 1 deletion Documentation/config/transfer.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
13 changes: 7 additions & 6 deletions Documentation/gitprotocol-v2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
~~~~~~~
Expand Down
29 changes: 29 additions & 0 deletions t/t5555-http-smart-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand Down
33 changes: 33 additions & 0 deletions t/t5701-git-serve.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand Down
51 changes: 50 additions & 1 deletion version.c
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -72,14 +76,59 @@ 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;

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);
}

Expand Down

0 comments on commit cbb94dc

Please sign in to comment.