Merge branch 'js/var-git-shell-path'

"git var GIT_SHELL_PATH" should report the path to the shell used
to spawn external commands, but it didn't do so on Windows, which
has been corrected.

* js/var-git-shell-path:
  var(win32): do report the GIT_SHELL_PATH that is actually used
  run-command: declare the `git_shell_path()` function globally
  run-command(win32): resolve the path to the Unix shell early
  mingw(is_msys2_sh): handle forward slashes in the `sh.exe` path, too
  win32: override `fspathcmp()` with a directory separator-aware version
  strvec: declare the `strvec_push_nodup()` function globally
  run-command: refactor getting the Unix shell path into its own function
maint
Junio C Hamano 2024-07-17 10:47:27 -07:00
commit 76e018b9a1
12 changed files with 78 additions and 13 deletions

View File

@ -12,6 +12,7 @@
#include "refs.h" #include "refs.h"
#include "path.h" #include "path.h"
#include "strbuf.h" #include "strbuf.h"
#include "run-command.h"


static const char var_usage[] = "git var (-l | <variable>)"; static const char var_usage[] = "git var (-l | <variable>)";


@ -51,7 +52,7 @@ static char *default_branch(int ident_flag UNUSED)


static char *shell_path(int ident_flag UNUSED) static char *shell_path(int ident_flag UNUSED)
{ {
return xstrdup(SHELL_PATH); return git_shell_path();
} }


static char *git_attr_val_system(int ident_flag UNUSED) static char *git_attr_val_system(int ident_flag UNUSED)

View File

@ -1546,7 +1546,7 @@ static int is_msys2_sh(const char *cmd)
return ret; return ret;
} }


if (ends_with(cmd, "\\sh.exe")) { if (ends_with(cmd, "\\sh.exe") || ends_with(cmd, "/sh.exe")) {
static char *sh; static char *sh;


if (!sh) if (!sh)

View File

@ -1,4 +1,5 @@
#include "../../git-compat-util.h" #include "../../git-compat-util.h"
#include "../../environment.h"


int win32_has_dos_drive_prefix(const char *path) int win32_has_dos_drive_prefix(const char *path)
{ {
@ -50,3 +51,39 @@ int win32_offset_1st_component(const char *path)


return pos + is_dir_sep(*pos) - path; return pos + is_dir_sep(*pos) - path;
} }

int win32_fspathncmp(const char *a, const char *b, size_t count)
{
int diff;

for (;;) {
if (!count--)
return 0;
if (!*a)
return *b ? -1 : 0;
if (!*b)
return +1;

if (is_dir_sep(*a)) {
if (!is_dir_sep(*b))
return -1;
a++;
b++;
continue;
} else if (is_dir_sep(*b))
return +1;

diff = ignore_case ?
(unsigned char)tolower(*a) - (int)(unsigned char)tolower(*b) :
(unsigned char)*a - (int)(unsigned char)*b;
if (diff)
return diff;
a++;
b++;
}
}

int win32_fspathcmp(const char *a, const char *b)
{
return win32_fspathncmp(a, b, (size_t)-1);
}

View File

@ -29,5 +29,9 @@ static inline int win32_has_dir_sep(const char *path)
#define has_dir_sep(path) win32_has_dir_sep(path) #define has_dir_sep(path) win32_has_dir_sep(path)
int win32_offset_1st_component(const char *path); int win32_offset_1st_component(const char *path);
#define offset_1st_component win32_offset_1st_component #define offset_1st_component win32_offset_1st_component
int win32_fspathcmp(const char *a, const char *b);
#define fspathcmp win32_fspathcmp
int win32_fspathncmp(const char *a, const char *b, size_t count);
#define fspathncmp win32_fspathncmp


#endif #endif

4
dir.c
View File

@ -95,7 +95,7 @@ int count_slashes(const char *s)
return cnt; return cnt;
} }


int fspathcmp(const char *a, const char *b) int git_fspathcmp(const char *a, const char *b)
{ {
return ignore_case ? strcasecmp(a, b) : strcmp(a, b); return ignore_case ? strcasecmp(a, b) : strcmp(a, b);
} }
@ -105,7 +105,7 @@ int fspatheq(const char *a, const char *b)
return !fspathcmp(a, b); return !fspathcmp(a, b);
} }


int fspathncmp(const char *a, const char *b, size_t count) int git_fspathncmp(const char *a, const char *b, size_t count)
{ {
return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count); return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count);
} }

4
dir.h
View File

@ -541,9 +541,9 @@ int remove_dir_recursively(struct strbuf *path, int flag);
*/ */
int remove_path(const char *path); int remove_path(const char *path);


int fspathcmp(const char *a, const char *b); int git_fspathcmp(const char *a, const char *b);
int fspatheq(const char *a, const char *b); int fspatheq(const char *a, const char *b);
int fspathncmp(const char *a, const char *b, size_t count); int git_fspathncmp(const char *a, const char *b, size_t count);
unsigned int fspathhash(const char *str); unsigned int fspathhash(const char *str);


/* /*

View File

@ -506,6 +506,14 @@ static inline int git_offset_1st_component(const char *path)
#define offset_1st_component git_offset_1st_component #define offset_1st_component git_offset_1st_component
#endif #endif


#ifndef fspathcmp
#define fspathcmp git_fspathcmp
#endif

#ifndef fspathncmp
#define fspathncmp git_fspathncmp
#endif

#ifndef is_valid_path #ifndef is_valid_path
#define is_valid_path(path) 1 #define is_valid_path(path) 1
#endif #endif

View File

@ -274,17 +274,24 @@ int sane_execvp(const char *file, char * const argv[])
return -1; return -1;
} }


char *git_shell_path(void)
{
#ifndef GIT_WINDOWS_NATIVE
return xstrdup(SHELL_PATH);
#else
char *p = locate_in_PATH("sh");
convert_slashes(p);
return p;
#endif
}

static const char **prepare_shell_cmd(struct strvec *out, const char **argv) static const char **prepare_shell_cmd(struct strvec *out, const char **argv)
{ {
if (!argv[0]) if (!argv[0])
BUG("shell command is empty"); BUG("shell command is empty");


if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) { if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
#ifndef GIT_WINDOWS_NATIVE strvec_push_nodup(out, git_shell_path());
strvec_push(out, SHELL_PATH);
#else
strvec_push(out, "sh");
#endif
strvec_push(out, "-c"); strvec_push(out, "-c");


/* /*

View File

@ -195,6 +195,11 @@ int is_executable(const char *name);
*/ */
int exists_in_PATH(const char *command); int exists_in_PATH(const char *command);


/**
* Return the path that is used to execute Unix shell command-lines.
*/
char *git_shell_path(void);

/** /**
* Start a sub-process. Takes a pointer to a `struct child_process` * Start a sub-process. Takes a pointer to a `struct child_process`
* that specifies the details and returns pipe FDs (if requested). * that specifies the details and returns pipe FDs (if requested).

View File

@ -10,7 +10,7 @@ void strvec_init(struct strvec *array)
memcpy(array, &blank, sizeof(*array)); memcpy(array, &blank, sizeof(*array));
} }


static void strvec_push_nodup(struct strvec *array, const char *value) void strvec_push_nodup(struct strvec *array, char *value)
{ {
if (array->v == empty_strvec) if (array->v == empty_strvec)
array->v = NULL; array->v = NULL;

View File

@ -46,6 +46,9 @@ void strvec_init(struct strvec *);
/* Push a copy of a string onto the end of the array. */ /* Push a copy of a string onto the end of the array. */
const char *strvec_push(struct strvec *, const char *); const char *strvec_push(struct strvec *, const char *);


/* Push an allocated string onto the end of the array, taking ownership. */
void strvec_push_nodup(struct strvec *array, char *value);

/** /**
* Format a string and push it onto the end of the array. This is a * Format a string and push it onto the end of the array. This is a
* convenience wrapper combining `strbuf_addf` and `strvec_push`. * convenience wrapper combining `strbuf_addf` and `strvec_push`.

View File

@ -157,7 +157,7 @@ test_expect_success POSIXPERM 'GIT_SHELL_PATH points to a valid executable' '
test_expect_success MINGW 'GIT_SHELL_PATH points to a suitable shell' ' test_expect_success MINGW 'GIT_SHELL_PATH points to a suitable shell' '
shellpath=$(git var GIT_SHELL_PATH) && shellpath=$(git var GIT_SHELL_PATH) &&
case "$shellpath" in case "$shellpath" in
*sh) ;; [A-Z]:/*/sh.exe) test -f "$shellpath";;
*) return 1;; *) return 1;;
esac esac
' '