Merge branch 'js/windows'
authorJunio C Hamano <gitster@pobox.com>
Tue, 19 Jan 2010 02:12:49 +0000 (18:12 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 19 Jan 2010 02:12:49 +0000 (18:12 -0800)
* js/windows:
Do not use date.c:tm_to_time_t() from compat/mingw.c
MSVC: Windows-native implementation for subset of Pthreads API
MSVC: Fix an "incompatible pointer types" compiler warning
Windows: avoid the "dup dance" when spawning a child process
Windows: simplify the pipe(2) implementation
Windows: boost startup by avoiding a static dependency on shell32.dll
Windows: disable Python

1  2 
Makefile
run-command.c
diff --combined Makefile
index 7632db77e785d13f195d62255bedb164ca7b0e42,7f5814c7a3276886e6392e19c48ddb63a092d52b..45a23a4dc852433728fe4f74655a34fb960da903
+++ b/Makefile
@@@ -222,7 -222,7 +222,7 @@@ all:
  #   DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
  #   DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
  
 -GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
 +GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
  -include GIT-VERSION-FILE
  
@@@ -478,6 -478,7 +478,7 @@@ LIB_H += commit.
  LIB_H += compat/bswap.h
  LIB_H += compat/cygwin.h
  LIB_H += compat/mingw.h
+ LIB_H += compat/win32/pthread.h
  LIB_H += csum-file.h
  LIB_H += decorate.h
  LIB_H += delta.h
@@@ -995,15 -996,16 +996,16 @@@ ifeq ($(uname_S),Windows
        OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
        NO_REGEX = YesPlease
        NO_CURL = YesPlease
-       NO_PTHREADS = YesPlease
+       NO_PYTHON = YesPlease
        BLK_SHA1 = YesPlease
+       THREADED_DELTA_SEARCH = YesPlease
  
        CC = compat/vcbuild/scripts/clink.pl
        AR = compat/vcbuild/scripts/lib.pl
        CFLAGS =
        BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
-       COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o
-       COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\"
+       COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o
+       COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
        BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
        EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib
        lib =
@@@ -1045,10 -1047,13 +1047,13 @@@ ifneq (,$(findstring MINGW,$(uname_S))
        UNRELIABLE_FSTAT = UnfortunatelyYes
        OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
        NO_REGEX = YesPlease
+       NO_PYTHON = YesPlease
        BLK_SHA1 = YesPlease
+       THREADED_DELTA_SEARCH = YesPlease
        COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
-       COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o
+       COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
+               compat/win32/pthread.o
        EXTLIBS += -lws2_32
        X = .exe
  ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
        EXTLIBS += /mingw/lib/libz.a
        NO_R_TO_GCC_LINKER = YesPlease
        INTERNAL_QSORT = YesPlease
-       THREADED_DELTA_SEARCH = YesPlease
  else
        NO_CURL = YesPlease
-       NO_PTHREADS = YesPlease
  endif
  endif
  
@@@ -1486,19 -1489,20 +1489,19 @@@ shell_compatibility_test: please_set_SH
  strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
  
 -git.o: git.c common-cmds.h GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
 -              '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
 -              $(ALL_CFLAGS) -o $@ -c $(filter %.c,$^)
 +git.o: common-cmds.h
 +git.s git.o: ALL_CFLAGS += -DGIT_VERSION='"$(GIT_VERSION)"' \
 +      '-DGIT_HTML_PATH="$(htmldir_SQ)"'
  
  git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
  
 -builtin-help.o: builtin-help.c common-cmds.h GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
 -              '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
 -              '-DGIT_MAN_PATH="$(mandir_SQ)"' \
 -              '-DGIT_INFO_PATH="$(infodir_SQ)"' $<
 +builtin-help.o: common-cmds.h
 +builtin-help.s builtin-help.o: ALL_CFLAGS += \
 +      '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
 +      '-DGIT_MAN_PATH="$(mandir_SQ)"' \
 +      '-DGIT_INFO_PATH="$(infodir_SQ)"'
  
  $(BUILT_INS): git$X
        $(QUIET_BUILT_IN)$(RM) $@ && \
@@@ -1651,26 -1655,30 +1654,26 @@@ git.o git.spec 
  
  %.o: %.c GIT-CFLAGS
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
 -%.s: %.c GIT-CFLAGS
 +%.s: %.c GIT-CFLAGS FORCE
        $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
  %.o: %.S GIT-CFLAGS
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
  
 -exec_cmd.o: exec_cmd.c GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
 -              '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
 -              '-DBINDIR="$(bindir_relative_SQ)"' \
 -              '-DPREFIX="$(prefix_SQ)"' \
 -              $<
 +exec_cmd.s exec_cmd.o: ALL_CFLAGS += \
 +      '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
 +      '-DBINDIR="$(bindir_relative_SQ)"' \
 +      '-DPREFIX="$(prefix_SQ)"'
  
 -builtin-init-db.o: builtin-init-db.c GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
 +builtin-init-db.s builtin-init-db.o: ALL_CFLAGS += \
 +      -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
  
 -config.o: config.c GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $<
 +config.s config.o: ALL_CFLAGS += -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
  
 -http.o: http.c GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $<
 +http.s http.o: ALL_CFLAGS += -DGIT_USER_AGENT='"git/$(GIT_VERSION)"'
  
  ifdef NO_EXPAT
 -http-walker.o: http-walker.c http.h GIT-CFLAGS
 -      $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DNO_EXPAT $<
 +http-walker.o: http.h
 +http-walker.s http-walker.o: ALL_CFLAGS += -DNO_EXPAT
  endif
  
  git-%$X: %.o $(GITLIBS)
@@@ -1748,7 -1756,7 +1751,7 @@@ cscope
  TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
               $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
  
 -GIT-CFLAGS: .FORCE-GIT-CFLAGS
 +GIT-CFLAGS: FORCE
        @FLAGS='$(TRACK_CFLAGS)'; \
            if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
                echo 1>&2 "    * new build flags or prefix"; \
  # We need to apply sq twice, once to protect from the shell
  # that runs GIT-BUILD-OPTIONS, and then again to protect it
  # and the first level quoting from the shell that runs "echo".
 -GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
 +GIT-BUILD-OPTIONS: FORCE
        @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
        @echo PERL_PATH=\''$(subst ','\'',$(PERL_PATH_SQ))'\' >>$@
        @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
  ifndef NO_TCLTK
  TRACK_VARS = $(subst ','\'',-DTCLTK_PATH='$(TCLTK_PATH_SQ)')
  
 -GIT-GUI-VARS: .FORCE-GIT-GUI-VARS
 +GIT-GUI-VARS: FORCE
        @VARS='$(TRACK_VARS)'; \
            if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \
                echo 1>&2 "    * new Tcl/Tk interpreter location"; \
                echo "$$VARS" >$@; \
              fi
 -
 -.PHONY: .FORCE-GIT-GUI-VARS
  endif
  
  ### Testing rules
@@@ -2017,7 -2027,8 +2020,7 @@@ endi
  
  .PHONY: all install clean strip
  .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
 -.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags cscope .FORCE-GIT-CFLAGS
 -.PHONY: .FORCE-GIT-BUILD-OPTIONS
 +.PHONY: FORCE TAGS tags cscope
  
  ### Check documentation
  #
diff --combined run-command.c
index 47ced570bd58d7146bf226fcbb0fdfdf06b99be5,d270664026259c1513004277eb4c9be4f283610d..a90984576411d237c1b83b66427e99d9e37ea7c8
@@@ -8,57 -8,15 +8,59 @@@ static inline void close_pair(int fd[2]
        close(fd[1]);
  }
  
+ #ifndef WIN32
  static inline void dup_devnull(int to)
  {
        int fd = open("/dev/null", O_RDWR);
        dup2(fd, to);
        close(fd);
  }
+ #endif
  
 +static const char **prepare_shell_cmd(const char **argv)
 +{
 +      int argc, nargc = 0;
 +      const char **nargv;
 +
 +      for (argc = 0; argv[argc]; argc++)
 +              ; /* just counting */
 +      /* +1 for NULL, +3 for "sh -c" plus extra $0 */
 +      nargv = xmalloc(sizeof(*nargv) * (argc + 1 + 3));
 +
 +      if (argc < 1)
 +              die("BUG: shell command is empty");
 +
 +      if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) {
 +              nargv[nargc++] = "sh";
 +              nargv[nargc++] = "-c";
 +
 +              if (argc < 2)
 +                      nargv[nargc++] = argv[0];
 +              else {
 +                      struct strbuf arg0 = STRBUF_INIT;
 +                      strbuf_addf(&arg0, "%s \"$@\"", argv[0]);
 +                      nargv[nargc++] = strbuf_detach(&arg0, NULL);
 +              }
 +      }
 +
 +      for (argc = 0; argv[argc]; argc++)
 +              nargv[nargc++] = argv[argc];
 +      nargv[nargc] = NULL;
 +
 +      return nargv;
 +}
 +
 +#ifndef WIN32
 +static int execv_shell_cmd(const char **argv)
 +{
 +      const char **nargv = prepare_shell_cmd(argv);
 +      trace_argv_printf(nargv, "trace: exec:");
 +      execvp(nargv[0], (char **)nargv);
 +      free(nargv);
 +      return -1;
 +}
 +#endif
 +
  int start_command(struct child_process *cmd)
  {
        int need_in, need_out, need_err;
@@@ -167,8 -125,6 +169,8 @@@ fail_pipe
                        cmd->preexec_cb();
                if (cmd->git_cmd) {
                        execv_git_cmd(cmd->argv);
 +              } else if (cmd->use_shell) {
 +                      execv_shell_cmd(cmd->argv);
                } else {
                        execvp(cmd->argv[0], (char *const*) cmd->argv);
                }
                        strerror(failed_errno = errno));
  #else
  {
-       int s0 = -1, s1 = -1, s2 = -1;  /* backups of stdin, stdout, stderr */
+       int fhin = 0, fhout = 1, fherr = 2;
        const char **sargv = cmd->argv;
        char **env = environ;
  
-       if (cmd->no_stdin) {
-               s0 = dup(0);
-               dup_devnull(0);
-       } else if (need_in) {
-               s0 = dup(0);
-               dup2(fdin[0], 0);
-       } else if (cmd->in) {
-               s0 = dup(0);
-               dup2(cmd->in, 0);
-       }
-       if (cmd->no_stderr) {
-               s2 = dup(2);
-               dup_devnull(2);
-       } else if (need_err) {
-               s2 = dup(2);
-               dup2(fderr[1], 2);
-       }
-       if (cmd->no_stdout) {
-               s1 = dup(1);
-               dup_devnull(1);
-       } else if (cmd->stdout_to_stderr) {
-               s1 = dup(1);
-               dup2(2, 1);
-       } else if (need_out) {
-               s1 = dup(1);
-               dup2(fdout[1], 1);
-       } else if (cmd->out > 1) {
-               s1 = dup(1);
-               dup2(cmd->out, 1);
-       }
+       if (cmd->no_stdin)
+               fhin = open("/dev/null", O_RDWR);
+       else if (need_in)
+               fhin = dup(fdin[0]);
+       else if (cmd->in)
+               fhin = dup(cmd->in);
+       if (cmd->no_stderr)
+               fherr = open("/dev/null", O_RDWR);
+       else if (need_err)
+               fherr = dup(fderr[1]);
+       if (cmd->no_stdout)
+               fhout = open("/dev/null", O_RDWR);
+       else if (cmd->stdout_to_stderr)
+               fhout = dup(fherr);
+       else if (need_out)
+               fhout = dup(fdout[1]);
+       else if (cmd->out > 1)
+               fhout = dup(cmd->out);
  
        if (cmd->dir)
                die("chdir in start_command() not implemented");
  
        if (cmd->git_cmd) {
                cmd->argv = prepare_git_cmd(cmd->argv);
 +      } else if (cmd->use_shell) {
 +              cmd->argv = prepare_shell_cmd(cmd->argv);
        }
  
-       cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
+       cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env,
+                                 fhin, fhout, fherr);
        failed_errno = errno;
        if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
                error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
                free(cmd->argv);
  
        cmd->argv = sargv;
-       if (s0 >= 0)
-               dup2(s0, 0), close(s0);
-       if (s1 >= 0)
-               dup2(s1, 1), close(s1);
-       if (s2 >= 0)
-               dup2(s2, 2), close(s2);
+       if (fhin != 0)
+               close(fhin);
+       if (fhout != 1)
+               close(fhout);
+       if (fherr != 2)
+               close(fherr);
  }
  #endif
  
@@@ -345,7 -288,6 +336,7 @@@ static void prepare_run_command_v_opt(s
        cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
        cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
        cmd->silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
 +      cmd->use_shell = opt & RUN_USING_SHELL ? 1 : 0;
  }
  
  int run_command_v_opt(const char **argv, int opt)